Files
android_kernel_samsung_sm86…/msm/sde/sde_hw_cdm.c
Samantha Tran 262099e94a disp: msm: replace kzfree with kfree
This change replaces kzfree with kfree as kzfree has been
renamed.

While moving to the latest 5.10 tip, additional small changes
were required to resolve compilation issues:

set_dma_ops has moved from dma-mapping to dma-map-ops header.
This change includes the new header file required.

drm_panel_add returns void, this change removes the expected
return value check.

drm_prime_pages_to_sg takes an additional parameter. This change
passes in the drm_device pointer the function is looking for.

Remove an unused variable in sde_crtc vblank function.

Change-Id: I47c085c0cb64432873c2e750ae64cbdc2b5340da
Signed-off-by: Samantha Tran <samtran@codeaurora.org>
2020-12-22 10:42:18 -08:00

361 rader
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2020, 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->hwversion = m->hwversion;
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;
}
static struct sde_hw_blk_ops sde_hw_ops = {
.start = NULL,
.stop = NULL,
};
struct sde_hw_cdm *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;
int rc;
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;
rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CDM, idx, &sde_hw_ops);
if (rc) {
SDE_ERROR("failed to init hw blk %d\n", rc);
goto blk_init_error;
}
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;
blk_init_error:
kfree(c);
return ERR_PTR(rc);
}
void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm)
{
if (cdm)
sde_hw_blk_destroy(&cdm->base);
kfree(cdm);
}