diff options
| author | Ping Li <pingli@codeaurora.org> | 2014-11-11 16:20:09 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:35:44 -0700 |
| commit | e8bd84e0ca6e2eddc10d753bac0dfaafdb2193c4 (patch) | |
| tree | bba6a6762b76a99c3bd81d5d57468e6e767dbe3d | |
| parent | ea14d7ee8802ba20a68ada8501b6f537435b88f1 (diff) | |
msm: mdss: Support for gamma correction in thulium
Gama correction blocks are part of destination and layer
mixer blocks of MDP. Client of PP driver can program these
blocks and enable them. Change adds support to program and
enable the gamma correction blocks.
Change-Id: Ieba07290525c1ccf79e4abf3648baf3dfd02d266
Signed-off-by: Ping Li <pingli@codeaurora.org>
| -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; |
