1
0
Fork 0
alistair23-linux/drivers/gpu/drm/imx/dcss/dcss-dec400d.c

271 lines
6.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP.
*/
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <drm/drm_fourcc.h>
#include "dcss-dev.h"
/* DEC400D registers offsets */
#define DEC400D_READCONFIG_BASE 0x800
#define DEC400D_READCONFIG(i) (DEC400D_READCONFIG_BASE + ((i) << 2))
#define COMPRESSION_ENABLE_BIT BIT(0)
#define COMPRESSION_FORMAT_POS 3
#define COMPRESSION_ALIGN_MODE_POS 16
#define TILE_ALIGN_MODE_POS 22
#define TILE_MODE_POS 25
#define DEC400D_READBUFFERBASE0 0x900
#define DEC400D_READCACHEBASE0 0x980
#define DEC400D_CONTROL 0xB00
#define DEC400D_CLEAR 0xB80
#define DEC400D_READBUFFERBASE0 0x900
#define DEC400D_READCACHEBASE0 0x980
#define DEC400D_CONTROL 0xB00
#define DISABLE_COMPRESSION_BIT BIT(1)
#define SHADOW_TRIGGER_BIT BIT(29)
#define DEC400_CFMT_ARGB8 0x0
#define DEC400_CFMT_XRGB8 0x1
#define DEC400_CFMT_AYUV 0x2
#define DEC400_CFMT_UYVY 0x3
#define DEC400_CFMT_YUY2 0x4
#define DEC400_CFMT_YUV_ONLY 0x5
#define DEC400_CFMT_UV_MIX 0x6
#define DEC400_CFMT_ARGB4 0x7
#define DEC400_CFMT_XRGB4 0x8
#define DEC400_CFMT_A1R5G5B5 0x9
#define DEC400_CFMT_X1R5G5B5 0xA
#define DEC400_CFMT_R5G6B5 0xB
#define DEC400_CFMT_Z24S8 0xC
#define DEC400_CFMT_Z24 0xD
#define DEC400_CFMT_Z16 0xE
#define DEC400_CFMT_A2R10G10B10 0xF
#define DEC400_CFMT_BAYER 0x10
#define DEC400_CFMT_SIGNED_BAYER 0x11
struct dcss_dec400d {
struct device *dev;
void __iomem *base_reg;
u32 base_ofs;
struct dcss_ctxld *ctxld;
u32 ctx_id;
bool bypass; /* bypass or decompress */
};
static void dcss_dec400d_write(struct dcss_dec400d *dec400d,
u32 value,
u32 offset)
{
dcss_ctxld_write(dec400d->ctxld, dec400d->ctx_id,
value, dec400d->base_ofs + offset);
}
int dcss_dec400d_init(struct dcss_dev *dcss, unsigned long dec400d_base)
{
struct dcss_dec400d *dec400d;
int ret;
dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
if (!dec400d)
return -ENOMEM;
dcss->dec400d = dec400d;
dec400d->dev = dcss->dev;
dec400d->ctxld = dcss->ctxld;
dec400d->base_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
if (!dec400d->base_reg) {
dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
ret = -ENOMEM;
goto free_mem;
}
dec400d->base_ofs = dec400d_base;
dec400d->ctx_id = CTX_SB_HP;
return 0;
free_mem:
devm_kfree(dcss->dev, dcss->dec400d);
return ret;
}
void dcss_dec400d_exit(struct dcss_dec400d *dec400d)
{
if (dec400d->base_reg)
devm_iounmap(dec400d->dev, dec400d->base_reg);
devm_kfree(dec400d->dev, dec400d);
}
void dcss_dec400d_read_config(struct dcss_dec400d *dec400d,
u32 read_id,
bool compress_en,
u32 compress_format)
{
u32 cformat = 0;
u32 read_config = 0x0;
/* TODO: using 'read_id' 0 by default */
if (read_id) {
WARN_ON(1);
return;
}
if (!compress_en)
goto config;
switch (compress_format) {
case _VIV_CFMT_ARGB8:
cformat = DEC400_CFMT_ARGB8;
break;
case _VIV_CFMT_XRGB8:
cformat = DEC400_CFMT_XRGB8;
break;
case _VIV_CFMT_AYUV:
cformat = DEC400_CFMT_AYUV;
break;
case _VIV_CFMT_UYVY:
cformat = DEC400_CFMT_UYVY;
break;
case _VIV_CFMT_YUY2:
cformat = DEC400_CFMT_YUY2;
break;
case _VIV_CFMT_YUV_ONLY:
cformat = DEC400_CFMT_YUV_ONLY;
break;
case _VIV_CFMT_UV_MIX:
cformat = DEC400_CFMT_UV_MIX;
break;
case _VIV_CFMT_ARGB4:
cformat = DEC400_CFMT_ARGB4;
break;
case _VIV_CFMT_XRGB4:
cformat = DEC400_CFMT_XRGB4;
break;
case _VIV_CFMT_A1R5G5B5:
cformat = DEC400_CFMT_A1R5G5B5;
break;
case _VIV_CFMT_X1R5G5B5:
cformat = DEC400_CFMT_X1R5G5B5;
break;
case _VIV_CFMT_R5G6B5:
cformat = DEC400_CFMT_R5G6B5;
break;
case _VIV_CFMT_Z24S8:
cformat = DEC400_CFMT_Z24S8;
break;
case _VIV_CFMT_Z24:
cformat = DEC400_CFMT_Z24;
break;
case _VIV_CFMT_Z16:
cformat = DEC400_CFMT_Z16;
break;
case _VIV_CFMT_A2R10G10B10:
cformat = DEC400_CFMT_A2R10G10B10;
break;
case _VIV_CFMT_BAYER:
cformat = DEC400_CFMT_BAYER;
break;
case _VIV_CFMT_SIGNED_BAYER:
cformat = DEC400_CFMT_SIGNED_BAYER;
break;
default:
/* TODO: not support yet */
WARN_ON(1);
return;
}
/* Dec compress format */
read_config |= cformat << COMPRESSION_FORMAT_POS;
/* ALIGN32_BYTE */
read_config |= 0x2 << COMPRESSION_ALIGN_MODE_POS;
/* TILE1_ALIGN */
read_config |= 0x0 << TILE_ALIGN_MODE_POS;
/* TILE8x4 */
read_config |= 0x3 << TILE_MODE_POS;
/* Compression Enable */
read_config |= COMPRESSION_ENABLE_BIT;
config:
dcss_dec400d_write(dec400d, read_config, DEC400D_READCONFIG(read_id));
}
void dcss_dec400d_bypass(struct dcss_dec400d *dec400d)
{
u32 control;
dcss_dec400d_read_config(dec400d, 0, false, 0);
control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
dev_dbg(dec400d->dev, "%s: dec400d control = %#x\n", __func__, control);
control |= DISABLE_COMPRESSION_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
/* Trigger shadow registers */
control |= SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
dec400d->bypass = true;
}
void dcss_dec400d_shadow_trig(struct dcss_dec400d *dec400d)
{
u32 control;
/* do nothing */
if (dec400d->bypass)
return;
control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
/* Trigger shadow registers */
control |= SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
}
void dcss_dec400d_addr_set(struct dcss_dec400d *dec400d, u32 baddr, u32 caddr)
{
/* set frame buffer base addr */
dcss_dec400d_write(dec400d, baddr, DEC400D_READBUFFERBASE0);
/* set tile status cache addr */
dcss_dec400d_write(dec400d, caddr, DEC400D_READCACHEBASE0);
dec400d->bypass = false;
}
void dcss_dec400d_fast_clear_config(struct dcss_dec400d *dec400d,
u32 fc_value,
bool enable)
{
dcss_dec400d_write(dec400d, fc_value, DEC400D_CLEAR);
}
void dcss_dec400d_enable(struct dcss_dec400d *dec400d)
{
u32 control;
if (dec400d->bypass)
return;
control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
/* enable compression */
control &= ~(DISABLE_COMPRESSION_BIT);
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
/* Trigger shadow registers */
control |= SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
}