diff options
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 119 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.h | 10 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c | 116 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c | 187 | ||||
| -rw-r--r-- | include/uapi/linux/msm_mdp.h | 6 |
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; |
