summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c119
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.h10
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c116
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c187
-rw-r--r--include/uapi/linux/msm_mdp.h6
6 files changed, 415 insertions, 26 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index f073a9201cc4..59f84a5a2ca0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1405,27 +1405,42 @@ static int pp_mixer_setup(u32 disp_num,
pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
/* GC_LUT is in layer mixer */
if (flags & PP_FLAGS_DIRTY_ARGC) {
- pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
- if (pgc_config->flags & MDP_PP_OPS_WRITE) {
- addr = mixer->base +
- MDSS_MDP_REG_LM_GC_LUT_BASE;
- pp_update_argc_lut(addr, pgc_config);
+ if (pp_ops[GC].pp_set_config) {
+ if (mdata->pp_block_off.lm_pgc_off == U32_MAX) {
+ pr_err("invalid pgc offset %d\n", U32_MAX);
+ } else {
+ addr = mixer->base +
+ mdata->pp_block_off.lm_pgc_off;
+ pp_ops[GC].pp_set_config(addr, pp_sts,
+ &mdss_pp_res->argc_disp_cfg[disp_num], LM);
+ }
+ } else {
+ pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
+ if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+ addr = mixer->base +
+ MDSS_MDP_REG_LM_GC_LUT_BASE;
+ pp_update_argc_lut(addr, pgc_config);
+ }
+ if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->argc_sts &= ~PP_STS_ENABLE;
+ else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->argc_sts |= PP_STS_ENABLE;
}
- if (pgc_config->flags & MDP_PP_OPS_DISABLE)
- pp_sts->argc_sts &= ~PP_STS_ENABLE;
- else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
- pp_sts->argc_sts |= PP_STS_ENABLE;
-
ctl->flush_bits |= lm_bitmask;
}
/* update LM opmode if LM needs flush */
if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
(ctl->flush_bits & lm_bitmask)) {
- addr = mixer->base + MDSS_MDP_REG_LM_OP_MODE;
- opmode = readl_relaxed(addr);
- opmode |= (1 << 0); /* GC_LUT_EN */
- writel_relaxed(opmode, addr);
+ if (pp_driver_ops.pp_opmode_config) {
+ pp_driver_ops.pp_opmode_config(LM, pp_sts,
+ &opmode, 0);
+ } else {
+ addr = mixer->base + MDSS_MDP_REG_LM_OP_MODE;
+ opmode = readl_relaxed(addr);
+ opmode |= (1 << 0); /* GC_LUT_EN */
+ writel_relaxed(opmode, addr);
+ }
}
return 0;
}
@@ -1768,15 +1783,28 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
if (flags & PP_FLAGS_DIRTY_PGC) {
pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
- if (pgc_config->flags & MDP_PP_OPS_WRITE) {
- addr = base + MDSS_MDP_REG_DSPP_GC_BASE;
- pp_update_argc_lut(addr, pgc_config);
+ if (pp_ops[GC].pp_set_config) {
+ if (mdata->pp_block_off.dspp_pgc_off == U32_MAX) {
+ pr_err("invalid pgc offset %d\n", U32_MAX);
+ } else {
+ addr = base +
+ mdata->pp_block_off.dspp_pgc_off;
+ pp_ops[GC].pp_set_config(addr, pp_sts,
+ &mdss_pp_res->pgc_disp_cfg[disp_num],
+ DSPP);
+ }
+ } else {
+ if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+ addr = base + MDSS_MDP_REG_DSPP_GC_BASE;
+ pp_update_argc_lut(addr, pgc_config);
+ }
+ if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->pgc_sts &= ~PP_STS_ENABLE;
+ else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->pgc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pgc_sts,
+ pgc_config->flags);
}
- if (pgc_config->flags & MDP_PP_OPS_DISABLE)
- pp_sts->pgc_sts &= ~PP_STS_ENABLE;
- else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
- pp_sts->pgc_sts |= PP_STS_ENABLE;
- pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
}
pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
@@ -3165,7 +3193,7 @@ int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
u32 *copyback)
{
int ret = 0;
- u32 disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0, is_lm = 0;
struct mdp_pgc_lut_data local_cfg;
struct mdp_pgc_lut_data *pgc_ptr;
u32 tbl_size, r_size, g_size, b_size;
@@ -3216,6 +3244,33 @@ int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
if (config->flags & MDP_PP_OPS_READ) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ if (pp_ops[GC].pp_get_config) {
+ char __iomem *temp_addr = NULL;
+ u32 off = 0;
+ is_lm = (PP_LOCAT(config->block) == MDSS_PP_LM_CFG);
+ off = (is_lm) ? mdata->pp_block_off.lm_pgc_off :
+ mdata->pp_block_off.dspp_pgc_off;
+ if (off == U32_MAX) {
+ pr_err("invalid offset for loc %d off %d\n",
+ PP_LOCAT(config->block), U32_MAX);
+ ret = -EINVAL;
+ goto clock_off;
+ }
+ temp_addr = (is_lm) ?
+ mdss_mdp_get_mixer_addr_off(dspp_num) :
+ mdss_mdp_get_dspp_addr_off(dspp_num);
+ if (IS_ERR_OR_NULL(temp_addr)) {
+ pr_err("invalid addr is_lm %d\n", is_lm);
+ ret = -EINVAL;
+ goto clock_off;
+ }
+ temp_addr += off;
+ ret = pp_ops[GC].pp_get_config(temp_addr, config,
+ ((is_lm) ? LM : DSPP), disp_num);
+ if (ret)
+ pr_err("gc get config failed %d\n", ret);
+ goto clock_off;
+ }
local_cfg = *config;
local_cfg.r_data =
&mdss_pp_res->gc_lut_r[disp_num][0];
@@ -3246,8 +3301,26 @@ int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
goto argc_config_exit;
}
*copyback = 1;
+clock_off:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
} else {
+ if (pp_ops[GC].pp_set_config) {
+ pr_debug("version of gc is %d\n", config->version);
+ is_lm = (PP_LOCAT(config->block) == MDSS_PP_LM_CFG);
+ ret = pp_pgc_lut_cache_params(config, mdss_pp_res,
+ ((is_lm) ? LM : DSPP), dspp_num);
+ if (ret) {
+ pr_err("gamut set config failed ret %d\n",
+ ret);
+ if (is_lm)
+ mdss_pp_res->pp_disp_flags[disp_num]
+ &= ~PP_FLAGS_DIRTY_ARGC;
+ else
+ mdss_pp_res->pp_disp_flags[disp_num]
+ &= ~PP_FLAGS_DIRTY_PGC;
+ }
+ goto argc_config_exit;
+ }
r_size = config->num_r_stages *
sizeof(struct mdp_ar_gc_lut_data);
g_size = config->num_g_stages *
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h
index 1db69142706b..60920d3e663f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h
@@ -19,6 +19,8 @@
#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
+#define MDSS_BLOCK_LM_NUM (MDSS_BLOCK_DISP_NUM + \
+ MDSS_MDP_INTF_MAX_LAYERMIXER)
/* PP STS related flags */
#define PP_STS_ENABLE 0x1
#define PP_STS_GAMUT_FIRST 0x2
@@ -91,9 +93,17 @@ struct mdp_pp_driver_ops {
};
struct mdss_pp_res_type_v1_7 {
+ u32 pgc_lm_table_c0[MDSS_BLOCK_LM_NUM][PGC_LUT_ENTRIES];
+ u32 pgc_lm_table_c1[MDSS_BLOCK_LM_NUM][PGC_LUT_ENTRIES];
+ u32 pgc_lm_table_c2[MDSS_BLOCK_LM_NUM][PGC_LUT_ENTRIES];
+ u32 pgc_table_c0[MDSS_BLOCK_DISP_NUM][PGC_LUT_ENTRIES];
+ u32 pgc_table_c1[MDSS_BLOCK_DISP_NUM][PGC_LUT_ENTRIES];
+ u32 pgc_table_c2[MDSS_BLOCK_DISP_NUM][PGC_LUT_ENTRIES];
u32 igc_table_c0_c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
u32 igc_table_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
u32 hist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
+ struct mdp_pgc_lut_data_v1_7 pgc_dspp_v17_data[MDSS_BLOCK_DISP_NUM];
+ struct mdp_pgc_lut_data_v1_7 pgc_lm_v17_data[MDSS_BLOCK_LM_NUM];
struct mdp_igc_lut_data_v1_7 igc_v17_data[MDSS_BLOCK_DISP_NUM];
struct mdp_hist_lut_data_v1_7 hist_lut_v17_data[MDSS_BLOCK_DISP_NUM];
struct mdp_gamut_data_v1_7 gamut_v17_data[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 92cb78353048..a4048f898faa 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c
@@ -478,3 +478,119 @@ int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
}
return ret;
}
+
+
+static int pp_pgc_lut_cache_params_v1_7(struct mdp_pgc_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res,
+ int location, int cnt)
+{
+ int ret = 0, max_cnt = 0;
+ u32 sz = 0;
+ struct mdp_pgc_lut_data_v1_7 *v17_cache_data = NULL, v17_usr_config;
+ struct mdss_pp_res_type_v1_7 *res_cache = NULL;
+ if (location != DSPP && location != LM) {
+ pr_err("Invalid location for pgc %d\n", location);
+ return -EINVAL;
+ }
+ max_cnt = (location == DSPP) ? MDSS_BLOCK_DISP_NUM :
+ MDSS_BLOCK_LM_NUM;
+ if (cnt >= max_cnt) {
+ pr_err("invalid layer count %d max is %d location is %d\n",
+ cnt, max_cnt, location);
+ return -EINVAL;
+ }
+ res_cache = mdss_pp_res->pp_data_res;
+ if (!res_cache) {
+ pr_err("invalid resource payload\n");
+ return -EINVAL;
+ }
+ if (copy_from_user(&v17_usr_config, config->cfg_payload,
+ sizeof(v17_usr_config))) {
+ pr_err("failed to copy from user config info\n");
+ return -EFAULT;
+ }
+ if (v17_usr_config.len != PGC_LUT_ENTRIES) {
+ pr_err("invalid entries for pgc act %d exp %d\n",
+ v17_usr_config.len, PGC_LUT_ENTRIES);
+ return -EFAULT;
+ }
+ if (config->flags & MDP_PP_OPS_READ) {
+ pr_err("ops read not supported\n");
+ return -EINVAL;
+ }
+ if (!(config->flags & MDP_PP_OPS_WRITE)) {
+ pr_debug("ops write not set flags %d\n", config->flags);
+ if (location == DSPP)
+ mdss_pp_res->pgc_disp_cfg[cnt].flags = config->flags;
+ else
+ mdss_pp_res->argc_disp_cfg[cnt].flags = config->flags;
+ return 0;
+ }
+ if (location == DSPP) {
+ mdss_pp_res->pgc_disp_cfg[cnt] = *config;
+ v17_cache_data = &res_cache->pgc_dspp_v17_data[cnt];
+ v17_cache_data->c0_data = &res_cache->pgc_table_c0[cnt][0];
+ v17_cache_data->c1_data = &res_cache->pgc_table_c1[cnt][0];
+ v17_cache_data->c2_data = &res_cache->pgc_table_c2[cnt][0];
+ mdss_pp_res->pgc_disp_cfg[cnt].cfg_payload = v17_cache_data;
+ } else {
+ mdss_pp_res->argc_disp_cfg[cnt] = *config;
+ v17_cache_data = &res_cache->pgc_lm_v17_data[cnt];
+ v17_cache_data->c0_data = &res_cache->pgc_lm_table_c0[cnt][0];
+ v17_cache_data->c1_data = &res_cache->pgc_lm_table_c1[cnt][0];
+ v17_cache_data->c2_data = &res_cache->pgc_lm_table_c2[cnt][0];
+ mdss_pp_res->argc_disp_cfg[cnt].cfg_payload = v17_cache_data;
+ }
+ v17_cache_data->len = 0;
+ sz = PGC_LUT_ENTRIES * sizeof(u32);
+ if (copy_from_user(v17_cache_data->c0_data, v17_usr_config.c0_data,
+ sz)) {
+ pr_err("failed to copy c0_data from user sz %d\n", sz);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ if (copy_from_user(v17_cache_data->c1_data, v17_usr_config.c1_data,
+ sz)) {
+ pr_err("failed to copy c1_data from user sz %d\n", sz);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ if (copy_from_user(v17_cache_data->c2_data, v17_usr_config.c2_data,
+ sz)) {
+ pr_err("failed to copy c2_data from user sz %d\n", sz);
+ ret = -EFAULT;
+ goto bail_out;
+ }
+ v17_cache_data->len = PGC_LUT_ENTRIES;
+ return 0;
+bail_out:
+ if (location == DSPP)
+ mdss_pp_res->pgc_disp_cfg[cnt].flags = 0;
+ else
+ mdss_pp_res->argc_disp_cfg[cnt].flags = 0;
+ return ret;
+}
+
+int pp_pgc_lut_cache_params(struct mdp_pgc_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res, int loc,
+ int cnt)
+{
+ int ret = 0;
+ if (!config || !mdss_pp_res) {
+ pr_err("invalid param config %p pp_res %p\n",
+ config, mdss_pp_res);
+ return -EINVAL;
+ }
+ switch (config->version) {
+ case mdp_pgc_v1_7:
+ ret = pp_pgc_lut_cache_params_v1_7(config, mdss_pp_res,
+ loc, cnt);
+ break;
+ default:
+ pr_err("unsupported igc version %d\n",
+ config->version);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h
index 905c5f93b061..f29c34bc3437 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h
@@ -28,4 +28,7 @@ int pp_igc_lut_cache_params(struct mdp_igc_lut_data *config,
struct mdss_pp_res_type *mdss_pp_res,
u32 copy_from_kernel);
+int pp_pgc_lut_cache_params(struct mdp_pgc_lut_data *config,
+ struct mdss_pp_res_type *mdss_pp_res,
+ int location, int cnt);
#endif
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
index 43002de9c442..ba1d8e5addb1 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
@@ -62,7 +62,6 @@
#define IGC_DATA_MASK (BIT(12) - 1)
#define IGC_DSPP_OP_MODE_EN BIT(0)
-
#define MDSS_MDP_DSPP_OP_PA_LUTV_FIRST_EN BIT(21)
#define REG_SSPP_VIG_HIST_LUT_BASE 0x1200
#define REG_DSPP_HIST_LUT_BASE 0x1400
@@ -72,6 +71,18 @@
#define ENHIST_UPPER_VALUE_MASK 0x3FF0000
#define ENHIST_BIT_SHIFT 16
+#define PGC_OPMODE_OFF 0
+#define PGC_C0_LUT_INDEX 4
+#define PGC_INDEX_OFF 4
+#define PGC_C1C2_LUT_OFF 8
+#define PGC_LUT_SWAP 0x1C
+#define PGC_LUT_SEL 0x20
+#define PGC_DATA_MASK (BIT(10) - 1)
+#define PGC_ODD_SHIFT 16
+#define PGC_SWAP 1
+#define PGC_8B_ROUND BIT(1)
+#define PGC_ENABLE BIT(0)
+
static struct mdss_pp_res_type_v1_7 config_data;
static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
@@ -101,6 +112,11 @@ static int pp_igc_set_config(char __iomem *base_addr,
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_pgc_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type);
+static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num);
void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
{
@@ -118,8 +134,8 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
ops->pp_ops[PCC].pp_get_config = pp_pcc_get_config;
/* GC ops */
- ops->pp_ops[GC].pp_set_config = NULL;
- ops->pp_ops[GC].pp_get_config = NULL;
+ ops->pp_ops[GC].pp_set_config = pp_pgc_set_config;
+ ops->pp_ops[GC].pp_get_config = pp_pgc_get_config;
/* PA ops */
ops->pp_ops[PA].pp_set_config = NULL;
@@ -177,6 +193,8 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts,
break;
case LM:
+ if (pp_sts->argc_sts & PP_STS_ENABLE)
+ pr_debug("pgc in LM enabled\n");
break;
default:
pr_err("Invalid block type %d\n", location);
@@ -901,3 +919,166 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
exit:
return ret;
}
+
+
+static int pp_pgc_set_config(char __iomem *base_addr,
+ struct pp_sts_type *pp_sts, void *cfg_data,
+ u32 block_type)
+{
+ char __iomem *c0 = NULL, *c1 = NULL, *c2 = NULL;
+ u32 val = 0, i = 0;
+ struct mdp_pgc_lut_data *pgc_data = NULL;
+ struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL;
+
+ if (!base_addr || !cfg_data || !pp_sts) {
+ pr_err("invalid params base_addr %p cfg_data %p pp_sts_type %p\n",
+ base_addr, cfg_data, pp_sts);
+ return -EINVAL;
+ }
+ pgc_data = (struct mdp_pgc_lut_data *) cfg_data;
+ pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *)
+ pgc_data->cfg_payload;
+ if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) {
+ pr_err("invalid pgc version %d payload %p\n",
+ pgc_data->version, pgc_data_v17);
+ return -EINVAL;
+ }
+ if (!(pgc_data->flags & ~(MDP_PP_OPS_READ))) {
+ pr_info("only read ops is set %d", pgc_data->flags);
+ return 0;
+ }
+ if (!(pgc_data->flags & MDP_PP_OPS_WRITE)) {
+ pr_info("only read ops is set %d", pgc_data->flags);
+ goto set_ops;
+ }
+ if (pgc_data_v17->len != PGC_LUT_ENTRIES || !pgc_data_v17->c0_data ||
+ !pgc_data_v17->c1_data || !pgc_data_v17->c2_data) {
+ pr_err("Invalid params entries %d c0_data %p c1_data %p c2_data %p\n",
+ pgc_data_v17->len, pgc_data_v17->c0_data,
+ pgc_data_v17->c1_data, pgc_data_v17->c2_data);
+ return -EINVAL;
+ }
+ if (block_type != DSPP && block_type != LM) {
+ pr_err("invalid block type %d\n", block_type);
+ return -EINVAL;
+ }
+ c0 = base_addr + PGC_C0_LUT_INDEX;
+ c1 = c0 + PGC_C1C2_LUT_OFF;
+ c2 = c1 + PGC_C1C2_LUT_OFF;
+ /* set the indexes to zero */
+ writel_relaxed(0, c0 + PGC_INDEX_OFF);
+ writel_relaxed(0, c1 + PGC_INDEX_OFF);
+ writel_relaxed(0, c2 + PGC_INDEX_OFF);
+ for (i = 0; i < PGC_LUT_ENTRIES; i += 2) {
+ val = pgc_data_v17->c0_data[i] & PGC_DATA_MASK;
+ val |= (pgc_data_v17->c0_data[i + 1] & PGC_DATA_MASK) <<
+ PGC_ODD_SHIFT;
+ writel_relaxed(val, c0);
+ val = pgc_data_v17->c1_data[i] & PGC_DATA_MASK;
+ val |= (pgc_data_v17->c1_data[i + 1] & PGC_DATA_MASK) <<
+ PGC_ODD_SHIFT;
+ writel_relaxed(val, c1);
+ val = pgc_data_v17->c2_data[i] & PGC_DATA_MASK;
+ val |= (pgc_data_v17->c2_data[i + 1] & PGC_DATA_MASK) <<
+ PGC_ODD_SHIFT;
+ writel_relaxed(val, c2);
+ }
+ if (block_type == DSPP) {
+ val = PGC_SWAP;
+ writel_relaxed(val, base_addr + PGC_LUT_SWAP);
+ }
+set_ops:
+ if (pgc_data->flags & MDP_PP_OPS_DISABLE) {
+ pp_sts->pgc_sts &= ~PP_STS_ENABLE;
+ writel_relaxed(0, base_addr + PGC_OPMODE_OFF);
+ } else if (pgc_data->flags & MDP_PP_OPS_ENABLE) {
+ val = PGC_ENABLE;
+ writel_relaxed(val, base_addr + PGC_OPMODE_OFF);
+ pp_sts->pgc_sts |= PP_STS_ENABLE;
+ }
+ return 0;
+}
+
+static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data,
+ u32 block_type, u32 disp_num)
+{
+ int ret = 0;
+ char __iomem *c0 = NULL, *c1 = NULL, *c2 = NULL;
+ u32 *c0_data = NULL, *c1_data = NULL, *c2_data = NULL;
+ u32 val = 0, i = 0, sz = 0;
+ struct mdp_pgc_lut_data *pgc_data = NULL;
+ struct mdp_lut_cfg_data *pgc_cfg_data = NULL;
+ struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL;
+ if (!base_addr || !cfg_data) {
+ pr_err("invalid params base_addr %p cfg_data %p block_type %d\n",
+ base_addr, cfg_data, block_type);
+ return -EINVAL;
+ }
+ pgc_cfg_data = (struct mdp_lut_cfg_data *) cfg_data;
+ if (pgc_cfg_data->lut_type != mdp_lut_pgc) {
+ pr_err("incorrect lut type passed %d\n",
+ pgc_cfg_data->lut_type);
+ return -EINVAL;
+ }
+ pgc_data = &pgc_cfg_data->data.pgc_lut_data;
+ pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *)
+ pgc_data->cfg_payload;
+ if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) {
+ pr_err("invalid pgc version %d payload %p\n",
+ pgc_data->version, pgc_data_v17);
+ return -EINVAL;
+ }
+ if (!(pgc_data->flags & MDP_PP_OPS_READ)) {
+ pr_info("read ops is not set %d", pgc_data->flags);
+ return -EINVAL;
+ }
+ sz = PGC_LUT_ENTRIES * sizeof(u32);
+ if (!access_ok(VERIFY_WRITE, pgc_data_v17->c0_data, sz) ||
+ !access_ok(VERIFY_WRITE, pgc_data_v17->c1_data, sz) ||
+ !access_ok(VERIFY_WRITE, pgc_data_v17->c2_data, sz)) {
+ pr_err("incorrect payload for PGC read size %d\n",
+ PGC_LUT_ENTRIES);
+ return -EFAULT;
+ }
+ c0_data = kzalloc(sz * 3, GFP_KERNEL);
+ if (!c0_data) {
+ pr_err("memory allocation failure sz %d", sz * 3);
+ return -ENOMEM;
+ }
+ c1_data = c0_data + PGC_LUT_ENTRIES;
+ c2_data = c1_data + PGC_LUT_ENTRIES;
+ c0 = base_addr + PGC_C0_LUT_INDEX;
+ c1 = c0 + PGC_C1C2_LUT_OFF;
+ c2 = c1 + PGC_C1C2_LUT_OFF;
+ /* set the indexes to zero */
+ writel_relaxed(0, c0 + 4);
+ writel_relaxed(0, c1 + 4);
+ writel_relaxed(0, c2 + 4);
+ for (i = 0; i < PGC_LUT_ENTRIES; i += 2) {
+ val = readl_relaxed(c0);
+ c0_data[i] = val & PGC_DATA_MASK;
+ c0_data[i + 1] = (val >> PGC_ODD_SHIFT) & PGC_DATA_MASK;
+ val = readl_relaxed(c1);
+ c1_data[i] = val & PGC_DATA_MASK;
+ c1_data[i + 1] = (val >> PGC_ODD_SHIFT) & PGC_DATA_MASK;
+ val = readl_relaxed(c2);
+ c2_data[i] = val & PGC_DATA_MASK;
+ c2_data[i + 1] = (val >> PGC_ODD_SHIFT) & PGC_DATA_MASK;
+ }
+ if (copy_to_user(pgc_data_v17->c0_data, c0_data, sz)) {
+ pr_err("failed to copyuser c0 data of sz %d\n", sz);
+ ret = -EFAULT;
+ }
+ if (!ret && copy_to_user(pgc_data_v17->c1_data, c1_data, sz)) {
+ pr_err("failed to copyuser c1 data of sz %d\n", sz);
+ ret = -EFAULT;
+ }
+ if (!ret && copy_to_user(pgc_data_v17->c2_data, c2_data, sz)) {
+ pr_err("failed to copyuser c2 data of sz %d\n", sz);
+ ret = -EFAULT;
+ }
+ if (!ret)
+ pgc_data_v17->len = PGC_LUT_ENTRIES;
+ kfree(c0_data);
+ return ret;
+}
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index e37219d15f55..72595ecf2cd4 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -900,6 +900,12 @@ struct mdp_pgc_lut_data {
void *cfg_payload;
};
+enum {
+ mdp_pgc_v1_7 = 1,
+ mdp_pgc_vmax,
+};
+
+#define PGC_LUT_ENTRIES 1024
struct mdp_pgc_lut_data_v1_7 {
uint32_t len;
uint32_t *c0_data;