blob: 42d14806868c1a754544cb7e0c1d052f901cabc4 [file] [log] [blame]
/* Copyright (c) 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_color_proc_common_v4.h"
#include "sde_hw_color_proc_v4.h"
static int sde_write_3d_gamut(struct sde_hw_blk_reg_map *hw,
struct drm_msm_3d_gamut *payload, u32 base,
u32 *opcode)
{
u32 reg, tbl_len, tbl_off, scale_off, i, j;
u32 *scale_data;
if (!payload || !opcode || !hw) {
DRM_ERROR("invalid payload %pK opcode %pK hw %pK\n",
payload, opcode, hw);
return -EINVAL;
}
switch (payload->mode) {
case GAMUT_3D_MODE_17:
tbl_len = GAMUT_3D_MODE17_TBL_SZ;
tbl_off = 0;
scale_off = GAMUT_SCALEA_OFFSET_OFF;
*opcode = gamut_mode_17 << 2;
break;
case GAMUT_3D_MODE_13:
*opcode = (*opcode & (BIT(4) - 1)) >> 2;
if (*opcode == gamut_mode_13a)
*opcode = gamut_mode_13b;
else
*opcode = gamut_mode_13a;
tbl_len = GAMUT_3D_MODE13_TBL_SZ;
tbl_off = (*opcode == gamut_mode_13a) ? 0 :
GAMUT_MODE_13B_OFF;
scale_off = (*opcode == gamut_mode_13a) ?
GAMUT_SCALEA_OFFSET_OFF : GAMUT_SCALEB_OFFSET_OFF;
*opcode <<= 2;
break;
case GAMUT_3D_MODE_5:
*opcode = gamut_mode_5 << 2;
*opcode |= GAMUT_MAP_EN;
tbl_len = GAMUT_3D_MODE5_TBL_SZ;
tbl_off = 0;
scale_off = GAMUT_SCALEB_OFFSET_OFF;
break;
default:
DRM_ERROR("invalid mode %d\n", payload->mode);
return -EINVAL;
}
if (payload->flags & GAMUT_3D_MAP_EN)
*opcode |= GAMUT_MAP_EN;
*opcode |= GAMUT_EN;
for (i = 0; i < GAMUT_3D_TBL_NUM; i++) {
reg = GAMUT_TABLE0_SEL << i;
reg |= ((tbl_off) & (BIT(11) - 1));
SDE_REG_WRITE(hw, base + GAMUT_TABLE_SEL_OFF, reg);
for (j = 0; j < tbl_len; j++) {
SDE_REG_WRITE(hw, base + GAMUT_LOWER_COLOR_OFF,
payload->col[i][j].c2_c1);
SDE_REG_WRITE(hw, base + GAMUT_UPPER_COLOR_OFF,
payload->col[i][j].c0);
}
}
if ((*opcode & GAMUT_MAP_EN)) {
scale_data = &payload->scale_off[0][0];
tbl_off = base + scale_off;
tbl_len = GAMUT_3D_SCALE_OFF_TBL_NUM * GAMUT_3D_SCALE_OFF_SZ;
for (i = 0; i < tbl_len; i++)
SDE_REG_WRITE(hw, tbl_off + (i * sizeof(u32)),
scale_data[i]);
}
SDE_REG_WRITE(hw, base, *opcode);
return 0;
}
void sde_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_3d_gamut *payload;
struct sde_hw_cp_cfg *hw_cfg = cfg;
u32 op_mode;
if (!ctx || !cfg) {
DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg);
return;
}
op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut.base);
if (!hw_cfg->payload) {
DRM_DEBUG_DRIVER("disable gamut feature\n");
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gamut.base, 0);
return;
}
payload = hw_cfg->payload;
sde_write_3d_gamut(&ctx->hw, payload, ctx->cap->sblk->gamut.base,
&op_mode);
}