Dateien
android_kernel_samsung_sm86…/msm/sde/sde_hw_cdm.c
Narendra Muppalla 3709853456 Display drivers kernel project initial snapshot
This change brings msm display driver including sde,
dp, dsi, rotator, dsi pll and dp pll from base 4.19 kernel
project. It is first source code snapshot from base kernel project.

Change-Id: Iec864c064ce5ea04e170f24414c728684002f284
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
2019-04-14 22:20:59 -07:00

360 Zeilen
8.4 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2019, 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
*/
sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
return c;
blk_init_error:
kzfree(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);
}