The sde_hw_blk was meant to be a generic base object for all SDE HW blocks, however, it enforces using a common set of ops which is not practical when blocks have different capabilities. Since this object was never used as intended and is not doing anything functional today, remove the dead weight. Change-Id: If76006c1ae5c62e8d7d77b100837dbaf6c661bd3 Signed-off-by: Steve Cohen <quic_cohens@quicinc.com>
343 líneas
8.2 KiB
C
343 líneas
8.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#include "sde_hw_mdss.h"
|
|
#include "sde_hwio.h"
|
|
#include "sde_hw_catalog.h"
|
|
#include "sde_hw_cdm.h"
|
|
#include "sde_dbg.h"
|
|
#include "sde_kms.h"
|
|
|
|
#define CDM_CSC_10_OPMODE 0x000
|
|
#define CDM_CSC_10_BASE 0x004
|
|
|
|
#define CDM_CDWN2_OP_MODE 0x100
|
|
#define CDM_CDWN2_CLAMP_OUT 0x104
|
|
#define CDM_CDWN2_PARAMS_3D_0 0x108
|
|
#define CDM_CDWN2_PARAMS_3D_1 0x10C
|
|
#define CDM_CDWN2_COEFF_COSITE_H_0 0x110
|
|
#define CDM_CDWN2_COEFF_COSITE_H_1 0x114
|
|
#define CDM_CDWN2_COEFF_COSITE_H_2 0x118
|
|
#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C
|
|
#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120
|
|
#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124
|
|
#define CDM_CDWN2_COEFF_COSITE_V 0x128
|
|
#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C
|
|
#define CDM_CDWN2_OUT_SIZE 0x130
|
|
|
|
#define CDM_HDMI_PACK_OP_MODE 0x200
|
|
#define CDM_CSC_10_MATRIX_COEFF_0 0x004
|
|
|
|
#define CDM_MUX 0x224
|
|
|
|
/**
|
|
* Horizontal coefficients for cosite chroma downscale
|
|
* s13 representation of coefficients
|
|
*/
|
|
static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e};
|
|
|
|
/**
|
|
* Horizontal coefficients for offsite chroma downscale
|
|
*/
|
|
static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046};
|
|
|
|
/**
|
|
* Vertical coefficients for cosite chroma downscale
|
|
*/
|
|
static u32 cosite_v_coeff[] = {0x00080004};
|
|
/**
|
|
* Vertical coefficients for offsite chroma downscale
|
|
*/
|
|
static u32 offsite_v_coeff[] = {0x00060002};
|
|
|
|
/* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */
|
|
static struct sde_csc_cfg rgb2yuv_cfg = {
|
|
{
|
|
0x0083, 0x0102, 0x0032,
|
|
0x1fb5, 0x1f6c, 0x00e1,
|
|
0x00e1, 0x1f45, 0x1fdc
|
|
},
|
|
{ 0x00, 0x00, 0x00 },
|
|
{ 0x0040, 0x0200, 0x0200 },
|
|
{ 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff },
|
|
{ 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 },
|
|
};
|
|
|
|
static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm,
|
|
struct sde_mdss_cfg *m,
|
|
void __iomem *addr,
|
|
struct sde_hw_blk_reg_map *b)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < m->cdm_count; i++) {
|
|
if (cdm == m->cdm[i].id) {
|
|
b->base_off = addr;
|
|
b->blk_off = m->cdm[i].base;
|
|
b->length = m->cdm[i].len;
|
|
b->hw_rev = m->hw_rev;
|
|
b->log_mask = SDE_DBG_MASK_CDM;
|
|
return &m->cdm[i];
|
|
}
|
|
}
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
static int sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx,
|
|
struct sde_csc_cfg *data)
|
|
{
|
|
sde_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, data, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx,
|
|
struct sde_hw_cdm_cfg *cfg)
|
|
{
|
|
struct sde_hw_blk_reg_map *c = &ctx->hw;
|
|
u32 opmode = 0;
|
|
u32 out_size = 0;
|
|
|
|
if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT)
|
|
opmode &= ~BIT(7);
|
|
else
|
|
opmode |= BIT(7);
|
|
|
|
/* ENABLE DWNS_H bit */
|
|
opmode |= BIT(1);
|
|
|
|
switch (cfg->h_cdwn_type) {
|
|
case CDM_CDWN_DISABLE:
|
|
/* CLEAR METHOD_H field */
|
|
opmode &= ~(0x18);
|
|
/* CLEAR DWNS_H bit */
|
|
opmode &= ~BIT(1);
|
|
break;
|
|
case CDM_CDWN_PIXEL_DROP:
|
|
/* Clear METHOD_H field (pixel drop is 0) */
|
|
opmode &= ~(0x18);
|
|
break;
|
|
case CDM_CDWN_AVG:
|
|
/* Clear METHOD_H field (Average is 0x1) */
|
|
opmode &= ~(0x18);
|
|
opmode |= (0x1 << 0x3);
|
|
break;
|
|
case CDM_CDWN_COSITE:
|
|
/* Clear METHOD_H field (Average is 0x2) */
|
|
opmode &= ~(0x18);
|
|
opmode |= (0x2 << 0x3);
|
|
/* Co-site horizontal coefficients */
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0,
|
|
cosite_h_coeff[0]);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1,
|
|
cosite_h_coeff[1]);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2,
|
|
cosite_h_coeff[2]);
|
|
break;
|
|
case CDM_CDWN_OFFSITE:
|
|
/* Clear METHOD_H field (Average is 0x3) */
|
|
opmode &= ~(0x18);
|
|
opmode |= (0x3 << 0x3);
|
|
|
|
/* Off-site horizontal coefficients */
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0,
|
|
offsite_h_coeff[0]);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1,
|
|
offsite_h_coeff[1]);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2,
|
|
offsite_h_coeff[2]);
|
|
break;
|
|
default:
|
|
pr_err("%s invalid horz down sampling type\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* ENABLE DWNS_V bit */
|
|
opmode |= BIT(2);
|
|
|
|
switch (cfg->v_cdwn_type) {
|
|
case CDM_CDWN_DISABLE:
|
|
/* CLEAR METHOD_V field */
|
|
opmode &= ~(0x60);
|
|
/* CLEAR DWNS_V bit */
|
|
opmode &= ~BIT(2);
|
|
break;
|
|
case CDM_CDWN_PIXEL_DROP:
|
|
/* Clear METHOD_V field (pixel drop is 0) */
|
|
opmode &= ~(0x60);
|
|
break;
|
|
case CDM_CDWN_AVG:
|
|
/* Clear METHOD_V field (Average is 0x1) */
|
|
opmode &= ~(0x60);
|
|
opmode |= (0x1 << 0x5);
|
|
break;
|
|
case CDM_CDWN_COSITE:
|
|
/* Clear METHOD_V field (Average is 0x2) */
|
|
opmode &= ~(0x60);
|
|
opmode |= (0x2 << 0x5);
|
|
/* Co-site vertical coefficients */
|
|
SDE_REG_WRITE(c,
|
|
CDM_CDWN2_COEFF_COSITE_V,
|
|
cosite_v_coeff[0]);
|
|
break;
|
|
case CDM_CDWN_OFFSITE:
|
|
/* Clear METHOD_V field (Average is 0x3) */
|
|
opmode &= ~(0x60);
|
|
opmode |= (0x3 << 0x5);
|
|
|
|
/* Off-site vertical coefficients */
|
|
SDE_REG_WRITE(c,
|
|
CDM_CDWN2_COEFF_OFFSITE_V,
|
|
offsite_v_coeff[0]);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cfg->v_cdwn_type || cfg->h_cdwn_type)
|
|
opmode |= BIT(0); /* EN CDWN module */
|
|
else
|
|
opmode &= ~BIT(0);
|
|
|
|
out_size = (cfg->output_width & 0xFFFF) |
|
|
((cfg->output_height & 0xFFFF) << 16);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode);
|
|
SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT,
|
|
((0x3FF << 16) | 0x0));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sde_hw_cdm_enable(struct sde_hw_cdm *ctx,
|
|
struct sde_hw_cdm_cfg *cdm)
|
|
{
|
|
struct sde_hw_blk_reg_map *c = &ctx->hw;
|
|
const struct sde_format *fmt;
|
|
struct cdm_output_cfg cdm_cfg = { 0 };
|
|
u32 opmode = 0;
|
|
u32 csc = 0;
|
|
|
|
if (!ctx || !cdm)
|
|
return -EINVAL;
|
|
|
|
fmt = cdm->output_fmt;
|
|
|
|
if (!SDE_FORMAT_IS_YUV(fmt))
|
|
return -EINVAL;
|
|
|
|
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
|
|
if (fmt->chroma_sample != SDE_CHROMA_H1V2)
|
|
return -EINVAL; /*unsupported format */
|
|
opmode = BIT(0);
|
|
opmode |= (fmt->chroma_sample << 1);
|
|
cdm_cfg.intf_en = true;
|
|
} else {
|
|
opmode = 0;
|
|
cdm_cfg.wb_en = true;
|
|
}
|
|
|
|
csc |= BIT(2);
|
|
csc &= ~BIT(1);
|
|
csc |= BIT(0);
|
|
|
|
if (ctx && ctx->ops.bind_pingpong_blk)
|
|
ctx->ops.bind_pingpong_blk(ctx, true,
|
|
cdm->pp_id);
|
|
else if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output)
|
|
ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg);
|
|
|
|
SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc);
|
|
SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode);
|
|
return 0;
|
|
}
|
|
|
|
void sde_hw_cdm_disable(struct sde_hw_cdm *ctx)
|
|
{
|
|
struct cdm_output_cfg cdm_cfg = { 0 };
|
|
|
|
if (!ctx)
|
|
return;
|
|
|
|
if (ctx && ctx->ops.bind_pingpong_blk)
|
|
ctx->ops.bind_pingpong_blk(ctx, false, 0);
|
|
else if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output)
|
|
ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg);
|
|
}
|
|
|
|
static void sde_hw_cdm_bind_pingpong_blk(
|
|
struct sde_hw_cdm *ctx,
|
|
bool enable,
|
|
const enum sde_pingpong pp)
|
|
{
|
|
struct sde_hw_blk_reg_map *c;
|
|
int mux_cfg = 0xF;
|
|
|
|
if (!ctx || (enable && (pp < PINGPONG_0 || pp >= PINGPONG_MAX)))
|
|
return;
|
|
|
|
c = &ctx->hw;
|
|
|
|
if (enable)
|
|
mux_cfg = (pp - PINGPONG_0) & 0x7;
|
|
|
|
SDE_REG_WRITE(c, CDM_MUX, mux_cfg);
|
|
}
|
|
|
|
|
|
static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops,
|
|
unsigned long features)
|
|
{
|
|
ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit;
|
|
ops->setup_cdwn = sde_hw_cdm_setup_cdwn;
|
|
ops->enable = sde_hw_cdm_enable;
|
|
ops->disable = sde_hw_cdm_disable;
|
|
if (features & BIT(SDE_CDM_INPUT_CTRL))
|
|
ops->bind_pingpong_blk = sde_hw_cdm_bind_pingpong_blk;
|
|
}
|
|
|
|
struct sde_hw_blk_reg_map *sde_hw_cdm_init(enum sde_cdm idx,
|
|
void __iomem *addr,
|
|
struct sde_mdss_cfg *m,
|
|
struct sde_hw_mdp *hw_mdp)
|
|
{
|
|
struct sde_hw_cdm *c;
|
|
struct sde_cdm_cfg *cfg;
|
|
|
|
c = kzalloc(sizeof(*c), GFP_KERNEL);
|
|
if (!c)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
cfg = _cdm_offset(idx, m, addr, &c->hw);
|
|
if (IS_ERR_OR_NULL(cfg)) {
|
|
kfree(c);
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
c->idx = idx;
|
|
c->caps = cfg;
|
|
_setup_cdm_ops(&c->ops, c->caps->features);
|
|
c->hw_mdp = hw_mdp;
|
|
|
|
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
|
|
c->hw.blk_off + c->hw.length, c->hw.xin_id);
|
|
|
|
/*
|
|
* Perform any default initialization for the chroma down module
|
|
* @setup default csc coefficients
|
|
*/
|
|
if (!m->trusted_vm_env)
|
|
sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
|
|
|
|
return &c->hw;
|
|
}
|
|
|
|
void sde_hw_cdm_destroy(struct sde_hw_blk_reg_map *hw)
|
|
{
|
|
if (hw)
|
|
kfree(to_sde_hw_cdm(hw));
|
|
}
|