blob: 82ca83f6d76a22bab25c36caa84d6ea194d39644 [file] [log] [blame]
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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 "drm/msm_drm_pp.h"
#include "sde_hw_mdss.h"
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_dspp.h"
#define PCC_ENABLE BIT(0)
#define PCC_OP_MODE_OFF 0
#define PCC_CONST_COEFF_OFF 4
#define PCC_R_COEFF_OFF 0x10
#define PCC_G_COEFF_OFF 0x1C
#define PCC_B_COEFF_OFF 0x28
#define PCC_RG_COEFF_OFF 0x34
#define PCC_RB_COEFF_OFF 0x40
#define PCC_GB_COEFF_OFF 0x4C
#define PCC_RGB_COEFF_OFF 0x58
#define PCC_CONST_COEFF_MASK 0xFFFF
#define PCC_COEFF_MASK 0x3FFFF
#define REG_MASK(n) ((BIT(n)) - 1)
#define PA_SZ_VAL_MASK BIT(31)
#define PA_SZ_SAT_MASK BIT(30)
#define PA_SZ_HUE_MASK BIT(29)
#define PA_CONT_MASK BIT(28)
#define PA_VAL_MASK BIT(27)
#define PA_SAT_MASK BIT(26)
#define PA_HUE_MASK BIT(25)
#define PA_LUTV_MASK BIT(19)
#define PA_HIST_MASK BIT(16)
#define PA_MEM_SKY_MASK BIT(7)
#define PA_MEM_FOL_MASK BIT(6)
#define PA_MEM_SKIN_MASK BIT(5)
#define PA_ENABLE BIT(20)
#define PA_ENABLE_MASK (PA_SZ_VAL_MASK | PA_SZ_SAT_MASK | PA_SZ_HUE_MASK \
| PA_CONT_MASK | PA_VAL_MASK | PA_SAT_MASK \
| PA_HUE_MASK | PA_LUTV_MASK | PA_HIST_MASK \
| PA_MEM_SKY_MASK | PA_MEM_FOL_MASK | PA_MEM_SKIN_MASK)
#define PA_LUT_SWAP_OFF 0x234
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
struct sde_mdss_cfg *m,
void __iomem *addr,
struct sde_hw_blk_reg_map *b)
{
int i;
for (i = 0; i < m->dspp_count; i++) {
if (dspp == m->dspp[i].id) {
b->base_off = addr;
b->blk_off = m->dspp[i].base;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_DSPP;
return &m->dspp[i];
}
}
return ERR_PTR(-EINVAL);
}
void sde_dspp_setup_histogram(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_read_histogram(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_update_igc(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_setup_pa(struct sde_hw_dspp *dspp, void *cfg)
{
}
void sde_dspp_setup_hue(struct sde_hw_dspp *dspp, void *cfg)
{
}
void sde_dspp_setup_vlut(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_pa_vlut *payload = NULL;
struct sde_hw_cp_cfg *hw_cfg = cfg;
u32 op_mode, tmp;
int i = 0, j = 0;
if (!hw_cfg || (hw_cfg->payload && hw_cfg->len !=
sizeof(struct drm_msm_pa_vlut))) {
DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n",
hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
((hw_cfg) ? hw_cfg->len : 0),
sizeof(struct drm_msm_pa_vlut));
return;
}
op_mode = SDE_REG_READ(&ctx->hw, 0);
if (!hw_cfg->payload) {
DRM_DEBUG_DRIVER("Disable vlut feature\n");
/**
* In the PA_VLUT disable case, remove PA_VLUT enable bit(19)
* first, then check whether any other PA sub-features are
* enabled or not. If none of the sub-features are enabled,
* remove the PA global enable bit(20).
*/
op_mode &= ~((u32)PA_LUTV_MASK);
if (!(op_mode & PA_ENABLE_MASK))
op_mode &= ~((u32)PA_ENABLE);
SDE_REG_WRITE(&ctx->hw, 0, op_mode);
return;
}
payload = hw_cfg->payload;
DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) {
tmp = (payload->val[i] & REG_MASK(10)) |
((payload->val[i + 1] & REG_MASK(10)) << 16);
SDE_REG_WRITE(&ctx->hw, (ctx->cap->sblk->vlut.base + j),
tmp);
}
SDE_REG_WRITE(&ctx->hw, PA_LUT_SWAP_OFF, 1);
op_mode |= PA_ENABLE | PA_LUTV_MASK;
SDE_REG_WRITE(&ctx->hw, 0, op_mode);
}
void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg)
{
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct drm_msm_pcc *pcc;
void __iomem *base;
if (!hw_cfg || (hw_cfg->len != sizeof(*pcc) && hw_cfg->payload)) {
DRM_ERROR(
"hw_cfg %pK payload %pK payload size %d exp size %zd\n",
hw_cfg, (hw_cfg ? hw_cfg->payload : NULL),
((hw_cfg) ? hw_cfg->len : 0), sizeof(*pcc));
return;
}
base = ctx->hw.base_off + ctx->cap->base;
/* Turn off feature */
if (!hw_cfg->payload) {
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base,
PCC_OP_MODE_OFF);
return;
}
DRM_DEBUG_DRIVER("Enable PCC feature\n");
pcc = hw_cfg->payload;
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF,
pcc->r.c & PCC_CONST_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw,
ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 4,
pcc->g.c & PCC_CONST_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw,
ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 8,
pcc->b.c & PCC_CONST_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF,
pcc->r.r & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 4,
pcc->g.r & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 8,
pcc->b.r & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF,
pcc->r.g & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 4,
pcc->g.g & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 8,
pcc->b.g & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF,
pcc->r.b & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 4,
pcc->g.b & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 8,
pcc->b.b & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF,
pcc->r.rg & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 4,
pcc->g.rg & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 8,
pcc->b.rg & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF,
pcc->r.rb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 4,
pcc->g.rb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 8,
pcc->b.rb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF,
pcc->r.gb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 4,
pcc->g.gb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 8,
pcc->b.gb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF,
pcc->r.rgb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw,
ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 4,
pcc->g.rgb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw,
ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 8,
pcc->b.rgb & PCC_COEFF_MASK);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, PCC_ENABLE);
}
void sde_dspp_setup_sharpening(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_setup_pa_memcolor(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_setup_sixzone(struct sde_hw_dspp *dspp)
{
}
void sde_dspp_setup_danger_safe(struct sde_hw_dspp *ctx, void *cfg)
{
}
void sde_dspp_setup_dither(struct sde_hw_dspp *ctx, void *cfg)
{
}
static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
{
int i = 0;
for (i = 0; i < SDE_DSPP_MAX; i++) {
if (!test_bit(i, &features))
continue;
switch (i) {
case SDE_DSPP_PCC:
if (c->cap->sblk->pcc.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x0)))
c->ops.setup_pcc = sde_dspp_setup_pcc;
break;
case SDE_DSPP_HSIC:
if (c->cap->sblk->hsic.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x0)))
c->ops.setup_hue = sde_dspp_setup_hue;
break;
case SDE_DSPP_VLUT:
if (c->cap->sblk->vlut.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x0))) {
c->ops.setup_vlut = sde_dspp_setup_vlut;
}
default:
break;
}
}
}
struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_dspp *c;
struct sde_dspp_cfg *cfg;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
cfg = _dspp_offset(idx, m, addr, &c->hw);
if (IS_ERR_OR_NULL(cfg)) {
kfree(c);
return ERR_PTR(-EINVAL);
}
/* Assign ops */
c->idx = idx;
c->cap = cfg;
_setup_dspp_ops(c, c->cap->features);
return c;
}
void sde_hw_dspp_destroy(struct sde_hw_dspp *dspp)
{
kfree(dspp);
}