Files
android_kernel_samsung_sm86…/msm/sde/sde_hw_cdm.c
Jeykumar Sankaran 935af8104a disp: msm: sde: avoid MDSS register access during boot in trusted VM
Trusted VM will be assigned MDSS HW access dynamically only on TUI
use case start boundary. So, any HW access during the boot sequence
will result in stage2 faults. But SDE driver initializes few HW
blocks during the boot up sequence. This change fixes them by either
skipping those accesses, if those registers expected to be programmed
by the Primary VM or postponing those accesses until the HW is
assigned.

Change-Id: Ic85238c5d734e9ac993072374c1b0ae661708fca
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
2020-06-19 15:39:03 -07:00

361 行
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:
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);
}