| /* 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); |
| |
| } |