summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c25
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.h20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c305
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v3.c127
4 files changed, 458 insertions, 19 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index d65985a13cf1..fefb4067443a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -2315,6 +2315,10 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
&mdss_pp_res->igc_disp_cfg[disp_num],
DSPP);
}
+ if (pp_driver_ops.igc_set_dither_strength)
+ pp_driver_ops.igc_set_dither_strength(base, pp_sts,
+ &mdss_pp_res->igc_disp_cfg[disp_num],
+ DSPP);
}
if (flags & PP_FLAGS_DIRTY_ENHIST) {
@@ -7454,16 +7458,25 @@ static int pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
break;
case MDSS_MDP_HW_REV_300:
case MDSS_MDP_HW_REV_301:
+ /*
+ * Some of the REV_300 PP features are same as REV_107.
+ * Get the driver ops for both the versions and update the
+ * payload/function pointers.
+ */
+ mdss_pp_res->pp_data_v1_7 = NULL;
+ mdss_pp_res->pp_data_v3 = NULL;
+ pp_cfg = pp_get_driver_ops_v1_7(ops);
+ if (IS_ERR_OR_NULL(pp_cfg)) {
+ ret = -EINVAL;
+ break;
+ }
+ mdss_pp_res->pp_data_v1_7 = pp_cfg;
pp_cfg = pp_get_driver_ops_v3(ops);
if (IS_ERR_OR_NULL(pp_cfg)) {
+ mdss_pp_res->pp_data_v1_7 = NULL;
ret = -EINVAL;
} else {
- mdss_pp_res->pp_data_v1_7 = pp_cfg;
- /* Currently all caching data is used from v17 for V3
- * hence setting the pointer to NULL. Will be used if we
- * have to add any caching specific to V3.
- */
- mdss_pp_res->pp_data_v3 = NULL;
+ mdss_pp_res->pp_data_v3 = pp_cfg;
}
break;
default:
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h
index 9a6e9ea3300c..93406f0b4f13 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h
@@ -106,6 +106,9 @@ struct mdp_pp_driver_ops {
int (*get_hist_isr_info)(u32 *isr_mask);
bool (*is_sspp_hist_supp)(void);
void (*gamut_clk_gate_en)(char __iomem *base_addr);
+ int (*igc_set_dither_strength)(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
};
struct mdp_pa_dither_res_data_v1_7 {
@@ -138,6 +141,23 @@ struct mdss_pp_res_type_v1_7 {
struct mdp_pa_dither_res_data_v1_7 pa_dither_data[MDSS_BLOCK_DISP_NUM];
};
+struct mdp_igc_lut_data_config {
+ uint32_t table_fmt;
+ uint32_t len;
+ uint32_t *c0_c1_data;
+ uint32_t *c2_data;
+ uint32_t strength;
+};
+
+struct mdss_pp_res_type_v3 {
+ int (*igc_set_config)(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
+ u32 igc_table_c0_c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+ u32 igc_table_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+ struct mdp_igc_lut_data_config igc_v3_data[MDSS_BLOCK_DISP_NUM];
+};
+
struct mdss_pp_res_type {
/* logical info */
u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
index ec9c1800787f..882145d4ff6c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
@@ -94,6 +94,15 @@ static u32 pp_igc_srgb[IGC_LUT_ENTRIES] = {
3809, 3844, 3879, 3915, 3950, 3986, 4022, 4059, 4095
};
+static int pp_igc_lut_cache_params_v3(struct mdp_igc_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res,
+ u32 copy_from_kernel);
+
+static int pp_igc_lut_cache_params_pipe_v3(struct mdp_igc_lut_data *config,
+ struct mdss_mdp_pipe *pipe,
+ u32 copy_from_kernel);
+
+
static int pp_hist_lut_cache_params_v1_7(struct mdp_hist_lut_data *config,
struct mdss_pp_res_type *mdss_pp_res)
{
@@ -991,6 +1000,21 @@ int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
ret);
}
break;
+ case mdp_igc_v3:
+ if (res_cache->block == DSPP) {
+ ret = pp_igc_lut_cache_params_v3(config,
+ res_cache->mdss_pp_res, copy_from_kernel);
+ if (ret)
+ pr_err("cache DSPP IGC params fail ret %d version %d\n",
+ ret, config->version);
+ } else {
+ ret = pp_igc_lut_cache_params_pipe_v3(config,
+ res_cache->pipe_res, copy_from_kernel);
+ if (ret)
+ pr_err("cache SSPP IGC params fail ret %d version %d\n",
+ ret, config->version);
+ }
+ break;
default:
pr_err("unsupported igc version %d\n",
config->version);
@@ -1329,6 +1353,7 @@ int pp_copy_layer_igc_payload(struct mdp_overlay_pp_params *pp_info)
{
void *cfg_payload = NULL;
int ret = 0;
+ size_t sz = 0;
switch (pp_info->igc_cfg.version) {
case mdp_igc_v1_7:
@@ -1343,22 +1368,34 @@ int pp_copy_layer_igc_payload(struct mdp_overlay_pp_params *pp_info)
ret = copy_from_user(cfg_payload,
pp_info->igc_cfg.cfg_payload,
sizeof(struct mdp_igc_lut_data_v1_7));
- if (ret) {
- pr_err("layer list copy from user failed, IGC cfg payload = %p\n",
- pp_info->igc_cfg.cfg_payload);
- ret = -EFAULT;
- kfree(cfg_payload);
- cfg_payload = NULL;
+ break;
+ case mdp_igc_v3:
+ cfg_payload = kmalloc(
+ sizeof(struct mdp_igc_lut_data_payload),
+ GFP_KERNEL);
+ if (!cfg_payload) {
+ ret = -ENOMEM;
goto exit;
}
+ sz = offsetof(struct mdp_igc_lut_data_payload, strength) +
+ sizeof(u32);
+ ret = copy_from_user(cfg_payload,
+ pp_info->igc_cfg.cfg_payload, sz);
break;
default:
pr_debug("No version set, fallback to legacy IGC version\n");
cfg_payload = NULL;
break;
}
-
exit:
+ if (ret) {
+ pr_err("layer list copy from user failed, IGC cfg payload = %p\n",
+ pp_info->igc_cfg.cfg_payload);
+ ret = -EFAULT;
+ kfree(cfg_payload);
+ cfg_payload = NULL;
+ goto exit;
+ }
pp_info->igc_cfg.cfg_payload = cfg_payload;
return ret;
}
@@ -1579,3 +1616,257 @@ int pp_pa_dither_cache_params(struct mdp_dither_cfg_data *config,
return ret;
}
+static int pp_igc_lut_cache_params_v3(struct mdp_igc_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res,
+ u32 copy_from_kernel)
+{
+ int ret = 0;
+ struct mdss_pp_res_type_v3 *res_cache;
+ struct mdp_igc_lut_data_payload v3_usr_config;
+ struct mdp_igc_lut_data_config *v3_cache_data, *v3_kernel_data = NULL;
+ u32 disp_num, len = 0;
+
+ if (!config || !mdss_pp_res) {
+ pr_err("invalid param config %p pp_res %p\n",
+ config, mdss_pp_res);
+ return -EINVAL;
+ }
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX)) {
+ pr_err("invalid config block %d\n", config->block);
+ return -EINVAL;
+ }
+ if (!mdss_pp_res->pp_data_v3) {
+ pr_err("invalid pp_data_v3 %p\n", mdss_pp_res->pp_data_v3);
+ return -EINVAL;
+ }
+ if (config->ops & MDP_PP_OPS_READ) {
+ pr_err("read op is not supported\n");
+ return -EINVAL;
+ }
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+ if (!(config->ops & MDP_PP_OPS_WRITE)) {
+ pr_debug("op for igc %d\n", config->ops);
+ mdss_pp_res->igc_disp_cfg[disp_num] = *config;
+ goto igc_config_exit;
+ }
+ res_cache = mdss_pp_res->pp_data_v3;
+ v3_cache_data = &res_cache->igc_v3_data[disp_num];
+ if (!v3_cache_data->c0_c1_data || !v3_cache_data->c2_data) {
+ pr_err("invalid payload c0_c1_data %p c2_data %p\n",
+ v3_cache_data->c0_c1_data, v3_cache_data->c2_data);
+ goto igc_config_exit;
+ }
+ if (!copy_from_kernel) {
+ if (copy_from_user(&v3_usr_config,
+ config->cfg_payload,
+ sizeof(v3_usr_config))) {
+ pr_err("failed to copy igc config\n");
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ len = v3_usr_config.len;
+ } else {
+ if (!config->cfg_payload) {
+ pr_err("can't copy config info NULL payload\n");
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ v3_kernel_data = config->cfg_payload;
+ len = v3_kernel_data->len;
+ }
+ if (copy_from_kernel && (!v3_kernel_data->c0_c1_data ||
+ !v3_kernel_data->c2_data)) {
+ pr_err("copy from kernel invalid params c0_c1_data %p c2_data %p\n",
+ v3_kernel_data->c0_c1_data,
+ v3_kernel_data->c2_data);
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ if (len != IGC_LUT_ENTRIES) {
+ pr_err("Invalid table size %d exp %d\n",
+ len, IGC_LUT_ENTRIES);
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ if (copy_from_kernel) {
+ memcpy(v3_cache_data->c0_c1_data,
+ v3_kernel_data->c0_c1_data,
+ len * sizeof(u32));
+ memcpy(v3_cache_data->c2_data, v3_kernel_data->c2_data,
+ len * sizeof(u32));
+ v3_cache_data->len = len;
+ v3_cache_data->strength = v3_kernel_data->strength;
+ v3_cache_data->table_fmt = v3_kernel_data->table_fmt;
+ } else {
+ ret = copy_from_user(v3_cache_data->c0_c1_data,
+ (u8 *)v3_usr_config.c0_c1_data,
+ len * sizeof(u32));
+ if (ret) {
+ pr_err("copy from user failed for c0_c1_data size %zd ret %d\n",
+ len * sizeof(u32), ret);
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ ret = copy_from_user(v3_cache_data->c2_data,
+ (u8 *)v3_usr_config.c2_data,
+ len * sizeof(u32));
+ if (ret) {
+ pr_err("copy from user failed for c2_data size %zd ret %d\n",
+ len * sizeof(u32), ret);
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ v3_cache_data->len = len;
+ v3_cache_data->strength = v3_usr_config.strength;
+ v3_cache_data->table_fmt = v3_usr_config.table_fmt;
+ }
+ mdss_pp_res->igc_disp_cfg[disp_num] = *config;
+ mdss_pp_res->igc_disp_cfg[disp_num].cfg_payload =
+ (void *)v3_cache_data;
+igc_config_exit:
+ return ret;
+}
+
+static int pp_igc_lut_cache_params_pipe_v3(
+ struct mdp_igc_lut_data *config, struct mdss_mdp_pipe *pipe,
+ u32 copy_from_kernel)
+{
+ struct mdp_igc_lut_data_config *v3_cache_data = NULL;
+ struct mdp_igc_lut_data_payload v3_usr_config;
+ u32 *c0_c1_data, *c2_data, len;
+ int ret = 0, fix_up = 0, i = 0;
+ u32 table_fmt = mdp_igc_rec_max, strength = 0;
+
+ if (!config || !pipe) {
+ pr_err("invalid param config %p pipe %p\n",
+ config, pipe);
+ return -EINVAL;
+ }
+ if (config->ops & MDP_PP_OPS_READ) {
+ pr_err("read op is not supported\n");
+ return -EINVAL;
+ }
+
+ if (!(config->ops & MDP_PP_OPS_WRITE)) {
+ pr_debug("op for gamut %d\n", config->ops);
+ goto igc_config_exit;
+ }
+
+ if (!config->cfg_payload) {
+ pr_err("can't copy config info NULL payload\n");
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+
+ v3_cache_data = pipe->pp_res.igc_cfg_payload;
+ if (!v3_cache_data)
+ v3_cache_data = kzalloc(sizeof(*v3_cache_data), GFP_KERNEL);
+ if (!v3_cache_data) {
+ ret = -ENOMEM;
+ goto igc_config_exit;
+ } else {
+ pipe->pp_res.igc_cfg_payload = v3_cache_data;
+ pipe->pp_cfg.igc_cfg.cfg_payload = v3_cache_data;
+ }
+
+ if (copy_from_kernel) {
+ memcpy(v3_cache_data, config->cfg_payload,
+ sizeof(*v3_cache_data));
+ table_fmt = v3_cache_data->table_fmt;
+ len = v3_cache_data->len;
+ strength = 0;
+ } else {
+ memcpy(&v3_usr_config, config->cfg_payload,
+ sizeof(v3_usr_config));
+ table_fmt = v3_usr_config.table_fmt;
+ len = v3_usr_config.len;
+ strength = v3_usr_config.strength;
+ }
+ switch (table_fmt) {
+ case mdp_igc_custom:
+ if (len != IGC_LUT_ENTRIES) {
+ pr_err("invalid igc len %d exp %d\n", len,
+ IGC_LUT_ENTRIES);
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ if (!copy_from_kernel)
+ break;
+ c0_c1_data = v3_cache_data->c0_c1_data;
+ c2_data = v3_cache_data->c2_data;
+ if (!c0_c1_data || !c2_data) {
+ pr_err("invalid param c0_c1_data %p c2_data %p\n",
+ c0_c1_data, c2_data);
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ break;
+ case mdp_igc_rec709:
+ c0_c1_data = pp_igc_709;
+ c2_data = pp_igc_709;
+ v3_usr_config.len = IGC_LUT_ENTRIES;
+ copy_from_kernel = 1;
+ fix_up = 1;
+ break;
+ case mdp_igc_srgb:
+ c0_c1_data = pp_igc_srgb;
+ c2_data = pp_igc_srgb;
+ v3_usr_config.len = IGC_LUT_ENTRIES;
+ copy_from_kernel = 1;
+ fix_up = 1;
+ break;
+ case mdp_igc_rec601:
+ c0_c1_data = pp_igc_601;
+ c2_data = pp_igc_601;
+ v3_usr_config.len = IGC_LUT_ENTRIES;
+ copy_from_kernel = 1;
+ fix_up = 1;
+ break;
+ default:
+ pr_err("invalid format %d\n", table_fmt);
+ ret = -EINVAL;
+ goto igc_config_exit;
+ }
+ v3_cache_data->c0_c1_data = pipe->pp_res.igc_c0_c1;
+ v3_cache_data->c2_data = pipe->pp_res.igc_c2;
+ v3_cache_data->len = IGC_LUT_ENTRIES;
+ v3_cache_data->strength = strength;
+ v3_cache_data->table_fmt = table_fmt;
+ if (copy_from_kernel) {
+ memcpy(v3_cache_data->c0_c1_data, c0_c1_data,
+ IGC_LUT_ENTRIES * sizeof(u32));
+ memcpy(v3_cache_data->c2_data, c2_data,
+ IGC_LUT_ENTRIES * sizeof(u32));
+ if (fix_up) {
+ for (i = 0; i < IGC_LUT_ENTRIES; i++)
+ v3_cache_data->c0_c1_data[i]
+ |= (v3_cache_data->c0_c1_data[i]
+ << IGC_C1_SHIFT);
+ }
+ } else {
+ if (copy_from_user(v3_cache_data->c0_c1_data,
+ (u8 *)v3_usr_config.c0_c1_data,
+ IGC_LUT_ENTRIES * sizeof(u32))) {
+ pr_err("error in copying the c0_c1_data of size %zd\n",
+ IGC_LUT_ENTRIES * sizeof(u32));
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ if (copy_from_user(v3_cache_data->c2_data,
+ (u8 *)v3_usr_config.c2_data,
+ IGC_LUT_ENTRIES * sizeof(u32))) {
+ pr_err("error in copying the c2_data of size %zd\n",
+ IGC_LUT_ENTRIES * sizeof(u32));
+ ret = -EFAULT;
+ }
+ }
+igc_config_exit:
+ if (ret || (config->ops & MDP_PP_OPS_DISABLE)) {
+ kfree(v3_cache_data);
+ pipe->pp_cfg.igc_cfg.cfg_payload = NULL;
+ pipe->pp_res.igc_cfg_payload = NULL;
+ }
+ return ret;
+}
+
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
index 3d277ae5db5f..88407b3d920b 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
@@ -66,6 +66,8 @@ static u32 dither_depth_map[DITHER_DEPTH_MAP_INDEX] = {
#define PA_DITHER_REG_OFF 0x2C
+#define IGC_DITHER_STRENGTH_REG_OFF 0x7E0
+
/* histogram prototypes */
static int pp_get_hist_offset(u32 block, u32 *ctl_off);
static int pp_hist_set_config(char __iomem *base_addr,
@@ -115,21 +117,53 @@ static int pp_pa_dither_set_config(char __iomem *base_addr,
struct pp_sts_type *pp_sts, void *cfg_data,
u32 block_type);
+/* IGC prototypes */
+static int pp_igc_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
+static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num);
+static int pp_igc_get_version(u32 *version);
+static int pp_igc_dither_set_strength(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
+
static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
u32 *opmode, int side);
+static int pp_driver_init(struct mdp_pp_driver_ops *ops);
-void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops)
+static struct mdss_pp_res_type_v3 config_data;
+
+static int pp_driver_init(struct mdp_pp_driver_ops *ops)
{
- void *pp_cfg = NULL;
+ int i = 0;
+
+ if (!ops->pp_ops[IGC].pp_set_config) {
+ pr_err("IGC function is not set\n");
+ return -EINVAL;
+ }
+ config_data.igc_set_config = ops->pp_ops[IGC].pp_set_config;
+ for (i = 0; i < MDSS_BLOCK_DISP_NUM; i++) {
+ config_data.igc_v3_data[i].c0_c1_data =
+ &config_data.igc_table_c0_c1[i][0];
+ config_data.igc_v3_data[i].c2_data =
+ &config_data.igc_table_c2[i][0];
+ config_data.igc_v3_data[i].len = IGC_LUT_ENTRIES;
+ config_data.igc_v3_data[i].strength = 0;
+ config_data.igc_v3_data[i].table_fmt = mdp_igc_rec_max;
+ }
+ return 0;
+}
+void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops)
+{
if (!ops) {
pr_err("PP driver ops invalid %p\n", ops);
return ERR_PTR(-EINVAL);
}
- pp_cfg = pp_get_driver_ops_v1_7(ops);
- if (IS_ERR_OR_NULL(pp_cfg))
- return NULL;
+ if (pp_driver_init(ops))
+ return ERR_PTR(-EINVAL);
/* PA ops */
ops->pp_ops[PA].pp_set_config = pp_pa_set_config;
ops->pp_ops[PA].pp_get_config = pp_pa_get_config;
@@ -154,13 +188,18 @@ void *pp_get_driver_ops_v3(struct mdp_pp_driver_ops *ops)
ops->pp_ops[PA_DITHER].pp_set_config = pp_pa_dither_set_config;
ops->pp_ops[PA_DITHER].pp_get_config = NULL;
+ ops->pp_ops[IGC].pp_get_config = pp_igc_get_config;
+ ops->pp_ops[IGC].pp_get_version = pp_igc_get_version;
+ ops->pp_ops[IGC].pp_set_config = pp_igc_set_config;
+
/* Set opmode pointers */
ops->pp_opmode_config = pp_opmode_config;
ops->get_hist_offset = pp_get_hist_offset;
ops->gamut_clk_gate_en = NULL;
+ ops->igc_set_dither_strength = pp_igc_dither_set_strength;
- return pp_cfg;
+ return &config_data;
}
static int pp_get_hist_offset(u32 block, u32 *ctl_off)
@@ -905,3 +944,79 @@ dither_set_sts:
}
return 0;
}
+
+static int pp_igc_dither_set_strength(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type)
+{
+ struct mdp_igc_lut_data *lut_cfg_data = cfg_data;
+ struct mdp_igc_lut_data_config *v3_data = NULL;
+
+ if (!base_addr || !cfg_data || (block_type != DSPP) || !pp_sts
+ || (lut_cfg_data->version != mdp_igc_v3)) {
+ pr_err("invalid params base_addr %p cfg_data %p block_type %d igc version %d\n",
+ base_addr, cfg_data, block_type, (lut_cfg_data ?
+ lut_cfg_data->version : mdp_pp_unknown));
+ return -EINVAL;
+ }
+
+ if ((lut_cfg_data->ops & MDP_PP_OPS_DISABLE) ||
+ !(lut_cfg_data->ops & MDP_PP_OPS_WRITE))
+ return 0;
+
+ if (!lut_cfg_data->cfg_payload) {
+ pr_err("invalid payload igc dither strenth\n");
+ return -EINVAL;
+ }
+ v3_data = lut_cfg_data->cfg_payload;
+ writel_relaxed(v3_data->strength,
+ base_addr + IGC_DITHER_STRENGTH_REG_OFF);
+ return 0;
+}
+
+static int pp_igc_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type)
+{
+ struct mdp_igc_lut_data *lut_cfg_data = NULL, v17_cfg_data = {0};
+ struct mdp_igc_lut_data_config *v3_data = NULL;
+ struct mdp_igc_lut_data_v1_7 v17_lut_data = {0};
+ int ret = 0;
+
+ if (!base_addr || !pp_sts || !cfg_data || !config_data.igc_set_config) {
+ pr_err("invalid payload base_addr %p pp_sts %p cfg_data %p igc_set_config %p\n",
+ base_addr, pp_sts, cfg_data,
+ config_data.igc_set_config);
+ return -EINVAL;
+ }
+ lut_cfg_data = cfg_data;
+ v3_data = lut_cfg_data->cfg_payload;
+ if (v3_data) {
+ v17_lut_data.c0_c1_data = v3_data->c0_c1_data;
+ v17_lut_data.c2_data = v3_data->c2_data;
+ v17_lut_data.len = v3_data->len;
+ v17_lut_data.table_fmt = v3_data->table_fmt;
+ }
+ memcpy(&v17_cfg_data, lut_cfg_data, sizeof(v17_cfg_data));
+ v17_cfg_data.version = mdp_igc_v1_7;
+ ret = config_data.igc_set_config(base_addr, pp_sts, &v17_cfg_data,
+ block_type);
+ return ret;
+}
+
+static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num)
+{
+ return -EINVAL;
+}
+
+static int pp_igc_get_version(u32 *version)
+{
+ if (!version) {
+ pr_err("invalid param version");
+ return -EINVAL;
+ }
+ *version = mdp_igc_v3;
+ return 0;
+}
+