blob: 639ed943eb18066ac39f2c36c44051d506dcaacb [file] [log] [blame]
/*
* Copyright (C) 2017 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <drm/drm_fourcc.h>
#include <video/imx-dcss.h>
#include "dcss-prv.h"
#define USE_CTXLD 1
/* DEC400D registers offsets */
#define DEC400D_READCONFIG_BASE 0x800
#define DEC400D_READCONFIG(i) (DEC400D_READCONFIG_BASE + ((i) << 2))
#define COMPRESSION_ENABLE_BIT 0
#define COMPRESSION_FORMAT_BIT 3
#define COMPRESSION_ALIGN_MODE_BIT 16
#define TILE_ALIGN_MODE_BIT 22
#define TILE_MODE_BIT 25
#define DEC400D_READBUFFERBASE0 0x900
#define DEC400D_READCACHEBASE0 0x980
#define DEC400D_CONTROL 0xB00
#define DISABLE_COMPRESSION_BIT 1
#define SHADOW_TRIGGER_BIT 29
struct dcss_dec400d_priv {
struct dcss_soc *dcss;
void __iomem *dec400d_reg;
uint32_t dec400d_reg_base;
uint64_t modifier[4];
uint32_t pixel_format;
uint32_t ctx_id;
bool bypass; /* bypass or decompress */
};
static void dcss_dec400d_write(struct dcss_dec400d_priv *dec400d,
uint32_t value,
uint32_t offset)
{
#if !USE_CTXLD
dcss_writel(value, dec400d->dec400d_reg + offset);
#else
dcss_ctxld_write(dec400d->dcss, dec400d->ctx_id,
value, dec400d->dec400d_reg_base + offset);
#endif
}
int dcss_dec400d_init(struct dcss_soc *dcss, unsigned long dec400d_base)
{
struct dcss_dec400d_priv *dec400d;
dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
if (!dec400d)
return -ENOMEM;
dcss->dec400d_priv = dec400d;
dec400d->dcss = dcss;
dec400d->dec400d_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
if (!dec400d->dec400d_reg) {
dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
return -ENOMEM;
}
dec400d->dec400d_reg_base = dec400d_base;
#if USE_CTXLD
dec400d->ctx_id = CTX_SB_HP;
#endif
return 0;
}
void dcss_dec400d_exit(struct dcss_soc *dcss)
{
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
if (!IS_ERR(dec400d)) {
devm_kfree(dcss->dev, dec400d);
dcss->dec400d_priv = NULL;
}
}
void dcss_dec400d_set_format_mod(struct dcss_soc *dcss,
uint32_t fourcc,
uint32_t mod_idx,
uint64_t modifier)
{
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
if (mod_idx > 3) {
WARN_ON(1);
return;
}
if (mod_idx == 0)
dec400d->pixel_format = fourcc;
dec400d->modifier[mod_idx] = modifier;
}
EXPORT_SYMBOL(dcss_dec400d_set_format_mod);
void dcss_dec400d_bypass(struct dcss_soc *dcss)
{
uint32_t control;
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
dcss_dec400d_read_config(dcss, 0, false);
control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
pr_debug("%s: dec400d control = %#x\n", __func__, control);
control |= 0x1 << DISABLE_COMPRESSION_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
/* Trigger shadow registers */
control |= 0x1 << SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
dec400d->bypass = true;
}
EXPORT_SYMBOL(dcss_dec400d_bypass);
void dcss_dec400d_shadow_trig(struct dcss_soc *dcss)
{
uint32_t control;
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
/* do nothing */
if (dec400d->bypass == true)
return;
control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
/* Trigger shadow registers */
control |= 0x1 << SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
}
EXPORT_SYMBOL(dcss_dec400d_shadow_trig);
void dcss_dec400d_addr_set(struct dcss_soc *dcss,
uint32_t baddr,
uint32_t caddr)
{
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
/* 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;
}
EXPORT_SYMBOL(dcss_dec400d_addr_set);
void dcss_dec400d_read_config(struct dcss_soc *dcss,
uint32_t read_id,
bool compress_en)
{
uint32_t read_config = 0x0;
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
/* TODO: using 'read_id' 0 by default */
if (read_id) {
WARN_ON(1);
return;
}
if (compress_en == false)
goto config;
switch (dec400d->pixel_format) {
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
read_config |= 0x0 << COMPRESSION_FORMAT_BIT;
break;
default:
/* TODO: not support yet */
WARN_ON(1);
return;
}
/* ALIGN32_BYTE */
read_config |= 0x2 << COMPRESSION_ALIGN_MODE_BIT;
/* TILE1_ALIGN */
read_config |= 0x0 << TILE_ALIGN_MODE_BIT;
/* TILE8x4 */
read_config |= 0x3 << TILE_MODE_BIT;
/* Compression Enable */
read_config |= 0x1 << COMPRESSION_ENABLE_BIT;
config:
dcss_dec400d_write(dec400d, read_config, DEC400D_READCONFIG(read_id));
}
EXPORT_SYMBOL(dcss_dec400d_read_config);
void dcss_dec400d_enable(struct dcss_soc *dcss)
{
uint32_t control;
struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
if (dec400d->bypass)
return;
control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
/* enable compression */
control &= ~(0x1 << DISABLE_COMPRESSION_BIT);
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
/* Trigger shadow registers */
control |= 0x1 << SHADOW_TRIGGER_BIT;
dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
}
EXPORT_SYMBOL(dcss_dec400d_enable);