diff options
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 268 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.h | 22 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c | 263 | ||||
| -rw-r--r-- | include/uapi/linux/msm_mdp.h | 155 |
4 files changed, 674 insertions, 34 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 6eb05b0e24c3..8069990cebd8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> +#include <linux/vmalloc.h> struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = { [MDSS_MDP_CSC_RGB2RGB] = { @@ -79,7 +80,6 @@ struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = { #define CSC_LV_OFF 0x14 #define CSC_POST_OFF 0xC -#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0) #define HIST_INTR_DSPP_MASK 0xFFF000 #define HIST_V2_INTR_BIT_MASK 0xF33000 @@ -1602,6 +1602,12 @@ static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num, if (side < 0) return; + if (pp_driver_ops.pp_opmode_config) { + pp_driver_ops.pp_opmode_config(PP_OPMODE_DSPP, + pp_sts, opmode, side); + return; + } + if (pp_sts_is_enabled(pp_sts->pa_sts, side)) { *opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */ pa_side_enabled = true; @@ -1744,9 +1750,22 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) pp_dither_config(addr, pp_sts, &mdss_pp_res->dither_disp_cfg[disp_num]); } - if (flags & PP_FLAGS_DIRTY_GAMUT) - pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num], base, - pp_sts); + if (flags & PP_FLAGS_DIRTY_GAMUT) { + if (!pp_ops[GAMUT].pp_set_config) { + pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num], + base, pp_sts); + } else { + if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) { + pr_err("invalid gamut off %d\n", U32_MAX); + } else { + addr = base + + mdata->pp_block_off.dspp_gamut_off; + pp_ops[GAMUT].pp_set_config(addr, pp_sts, + &mdss_pp_res->gamut_disp_cfg[disp_num], + DSPP); + } + } + } if (flags & PP_FLAGS_DIRTY_PGC) { pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num]; @@ -3317,15 +3336,190 @@ static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config) return -EINVAL; if (config->tbl_size[7] != GAMUT_T7_SIZE) return -EINVAL; - return 0; } +static int pp_gamut_cache_params_v1_7(struct mdp_gamut_cfg_data *config) +{ + u32 disp_num, tbl_sz; + struct mdss_pp_res_type_v1_7 *res_cache; + struct mdp_gamut_data_v1_7 *v17_data, v17_config; + u32 gamut_size = 0, scal_coff_size = 0, sz = 0, index = 0; + u32 *tbl_gamut = NULL; + int ret = 0, i = 0; + + if (!config) { + pr_err("invalid param config %p\n", config); + 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_res) { + pr_err("invalid pp_data_res %p\n", mdss_pp_res->pp_data_res); + return -EINVAL; + } + res_cache = mdss_pp_res->pp_data_res; + if (config->flags & MDP_PP_OPS_READ) { + pr_err("read op is not supported\n"); + return -EINVAL; + } else { + disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; + mdss_pp_res->gamut_disp_cfg[disp_num] = *config; + v17_data = &res_cache->gamut_v17_data[disp_num]; + mdss_pp_res->gamut_disp_cfg[disp_num].cfg_payload = + (void *) v17_data; + tbl_gamut = v17_data->c0_data[0]; + + if (copy_from_user(&v17_config, config->cfg_payload, + sizeof(v17_config))) { + pr_err("failed to copy v17 gamut\n"); + ret = -EFAULT; + goto gamut_config_exit; + } + if ((config->flags & MDP_PP_OPS_DISABLE)) { + pr_debug("disable gamut\n"); + ret = 0; + goto gamut_memory_free_exit; + } + if (v17_config.mode != mdp_gamut_coarse_mode && + v17_config.mode != mdp_gamut_fine_mode) { + pr_err("invalid gamut mode %d\n", v17_config.mode); + return -EINVAL; + } + if (!(config->flags & MDP_PP_OPS_WRITE)) { + pr_debug("op for gamut %d\n", config->flags); + goto gamut_config_exit; + } + tbl_sz = (v17_config.mode == mdp_gamut_fine_mode) ? + MDP_GAMUT_TABLE_V1_7_SZ : + MDP_GAMUT_TABLE_V1_7_COARSE_SZ; + memcpy(v17_data, &v17_config, sizeof(v17_config)); + + /* sanity check for sizes */ + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + if (v17_config.tbl_size[i] != tbl_sz) { + pr_err("invalid tbl_sz %d exp %d for mode %d\n", + v17_config.tbl_size[i], tbl_sz, + v17_config.mode); + goto gamut_config_exit; + } + gamut_size += v17_config.tbl_size[i]; + if (i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM) + continue; + if (v17_config.tbl_scale_off_sz[i] != + MDP_GAMUT_SCALE_OFF_SZ) { + pr_err("invalid scale_sz %d exp %d for mode %d\n", + v17_config.tbl_scale_off_sz[i], + MDP_GAMUT_SCALE_OFF_SZ, + v17_config.mode); + goto gamut_config_exit; + } + scal_coff_size += v17_config.tbl_scale_off_sz[i]; + + } + /* gamut size should be accounted for c0, c1c2 table */ + sz = gamut_size * 2 + scal_coff_size; + if (sz > GAMUT_TOTAL_TABLE_SIZE_V1_7) { + pr_err("Invalid table size act %d max %d\n", + sz, GAMUT_TOTAL_TABLE_SIZE_V1_7); + ret = -EINVAL; + goto gamut_config_exit; + } + /* Allocate for fine mode other modes will fit */ + if (!tbl_gamut) + tbl_gamut = vmalloc(GAMUT_TOTAL_TABLE_SIZE_V1_7 * + sizeof(u32)); + if (!tbl_gamut) { + pr_err("failed to allocate buffer for gamut size %zd", + (GAMUT_TOTAL_TABLE_SIZE_V1_7 * sizeof(u32))); + ret = -ENOMEM; + goto gamut_config_exit; + } + index = 0; + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + ret = copy_from_user(&tbl_gamut[index], + v17_config.c0_data[i], + (sizeof(u32) * v17_config.tbl_size[i])); + if (ret) { + pr_err("copying c0 table %d from userspace failed size %zd ret %d\n", + i, (sizeof(u32) * + v17_config.tbl_size[i]), ret); + ret = -EINVAL; + goto gamut_memory_free_exit; + } + v17_data->c0_data[i] = &tbl_gamut[index]; + index += v17_config.tbl_size[i]; + ret = copy_from_user(&tbl_gamut[index], + v17_config.c1_c2_data[i], + (sizeof(u32) * v17_config.tbl_size[i])); + if (ret) { + pr_err("copying c1_c2 table %d from userspace failed size %zd ret %d\n", + i, (sizeof(u32) * + v17_config.tbl_size[i]), ret); + ret = -EINVAL; + goto gamut_memory_free_exit; + } + v17_data->c1_c2_data[i] = &tbl_gamut[index]; + index += v17_config.tbl_size[i]; + } + for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) { + ret = copy_from_user(&tbl_gamut[index], + v17_config.scale_off_data[i], + (sizeof(u32) * + v17_config.tbl_scale_off_sz[i])); + if (ret) { + pr_err("copying scale offset table %d from userspace failed size %zd ret %d\n", + i, (sizeof(u32) * + v17_config.tbl_scale_off_sz[i]), ret); + ret = -EINVAL; + goto gamut_memory_free_exit; + } + v17_data->scale_off_data[i] = &tbl_gamut[index]; + index += v17_config.tbl_scale_off_sz[i]; + } + } +gamut_config_exit: + return ret; +gamut_memory_free_exit: + vfree(tbl_gamut); + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + v17_data->c0_data[i] = NULL; + v17_data->c1_c2_data[i] = NULL; + if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM) + v17_data->scale_off_data[i] = NULL; + } + return ret; +} + +static int pp_gamut_cache_params(struct mdp_gamut_cfg_data *config) +{ + int ret = 0; + if (!config) { + pr_err("invalid param config %p\n", config); + return -EINVAL; + } + switch (config->version) { + case mdp_gamut_v1_7: + ret = pp_gamut_cache_params_v1_7(config); + break; + default: + pr_err("unsupported gamut version %d\n", + config->version); + ret = -EINVAL; + break; + } + return ret; +} + int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback) { int i, j, ret = 0; - + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); u32 disp_num, dspp_num = 0; uint16_t *tbl_off; struct mdp_gamut_cfg_data local_cfg; @@ -3339,9 +3533,6 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, (config->block >= MDP_BLOCK_MAX)) return -EINVAL; - if (pp_gm_has_invalid_lut_size(config)) - return -EINVAL; - if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { pr_warn("Can't set both split bits\n"); return -EINVAL; @@ -3358,7 +3549,32 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, goto gamut_config_exit; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - + if (pp_ops[GAMUT].pp_get_config) { + addr = mdss_mdp_get_dspp_addr_off(disp_num); + if (IS_ERR_OR_NULL(addr)) { + pr_err("invalid dspp base addr %p\n", + addr); + ret = -EINVAL; + goto gamut_clk_off; + } + if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) { + pr_err("invalid gamut parmas off %d\n", + mdata->pp_block_off.dspp_gamut_off); + ret = -EINVAL; + goto gamut_clk_off; + } + addr += mdata->pp_block_off.dspp_gamut_off; + ret = pp_ops[GAMUT].pp_get_config(addr, config, DSPP, + disp_num); + if (ret) + pr_err("gamut get config failed %d\n", ret); + goto gamut_clk_off; + } + if (pp_gm_has_invalid_lut_size(config)) { + pr_err("invalid lut size for gamut\n"); + ret = -EINVAL; + goto gamut_clk_off; + } addr = mdss_mdp_get_dspp_addr_off(dspp_num) + MDSS_MDP_REG_DSPP_GAMUT_BASE; for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { @@ -3367,7 +3583,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, GFP_KERNEL); if (!r_tbl[i]) { pr_err("%s: alloc failed\n", __func__); - goto gamut_config_exit; + ret = -ENOMEM; + goto gamut_clk_off; } /* Reset gamut LUT index to 0 */ writel_relaxed(data, addr); @@ -3380,7 +3597,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, if (ret) { pr_err("%s: copy tbl to usr failed\n", __func__); - goto gamut_config_exit; + ret = -EFAULT; + goto gamut_clk_off; } } for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { @@ -3389,7 +3607,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, GFP_KERNEL); if (!g_tbl[i]) { pr_err("%s: alloc failed\n", __func__); - goto gamut_config_exit; + ret = -ENOMEM; + goto gamut_clk_off; } /* Reset gamut LUT index to 0 */ writel_relaxed(data, addr); @@ -3402,7 +3621,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, if (ret) { pr_err("%s: copy tbl to usr failed\n", __func__); - goto gamut_config_exit; + ret = -EFAULT; + goto gamut_clk_off; } } for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { @@ -3411,7 +3631,8 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, GFP_KERNEL); if (!b_tbl[i]) { pr_err("%s: alloc failed\n", __func__); - goto gamut_config_exit; + ret = -ENOMEM; + goto gamut_clk_off; } /* Reset gamut LUT index to 0 */ writel_relaxed(data, addr); @@ -3424,12 +3645,26 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, if (ret) { pr_err("%s: copy tbl to usr failed\n", __func__); - goto gamut_config_exit; + ret = -EFAULT; + goto gamut_clk_off; } } *copyback = 1; +gamut_clk_off: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); } else { + if (pp_ops[GAMUT].pp_set_config) { + pr_debug("version of gamut is %d\n", config->version); + ret = pp_gamut_cache_params(config); + if (ret) { + pr_err("gamut config failed version %d ret %d\n", + config->version, ret); + ret = -EFAULT; + goto gamut_config_exit; + } else { + goto gamut_set_dirty; + } + } local_cfg = *config; tbl_off = mdss_pp_res->gamut_tbl[disp_num]; for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { @@ -3460,6 +3695,7 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, tbl_off += local_cfg.tbl_size[i]; } mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg; +gamut_set_dirty: mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT; } gamut_config_exit: diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.h b/drivers/video/fbdev/msm/mdss_mdp_pp.h index d18fbd49b135..a5d970af5e0c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.h +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.h @@ -17,6 +17,8 @@ #include <linux/msm_mdp.h> +#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0) + /* PP STS related flags */ #define PP_STS_ENABLE 0x1 @@ -24,6 +26,12 @@ #define MDSS_SIDE_NONE 0 #define MDSS_SIDE_LEFT 1 #define MDSS_SIDE_RIGHT 2 +/* size calculated for c0,c1_c2 for 4 tables */ +#define GAMUT_COLOR_COEFF_SIZE_V1_7 (2 * MDP_GAMUT_TABLE_V1_7_SZ * 4) +/* 16 entries for c0,c1,c2 */ +#define GAMUT_SCALE_OFFSET_SIZE_V1_7 (3 * MDP_GAMUT_SCALE_OFF_SZ) +#define GAMUT_TOTAL_TABLE_SIZE_V1_7 (GAMUT_COLOR_COEFF_SIZE_V1_7 + \ + GAMUT_SCALE_OFFSET_SIZE_V1_7) /* PP Feature Operations */ enum pp_features { @@ -40,11 +48,19 @@ enum pp_features { }; enum pp_block_opmodes { - PP_OPMODE_VIG, + PP_OPMODE_VIG = 1, PP_OPMODE_DSPP, PP_OPMODE_MAX }; +enum pp_config_block { + SSPP_RGB = 1, + SSPP_DMA, + SSPP_VIG, + DSPP, + LM +}; + struct mdp_pp_feature_ops { u32 feature; int (*pp_get_config)(char __iomem *base_addr, void *cfg_data, @@ -60,6 +76,10 @@ struct mdp_pp_driver_ops { u32 *opmode, int side); }; +struct mdss_pp_res_type_v1_7 { + struct mdp_gamut_data_v1_7 gamut_v17_data[MDSS_BLOCK_DISP_NUM]; +}; + #ifdef CONFIG_ARCH_MSMTHULIUM void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops); #else 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 35e7b0da6e55..850233cb491d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c @@ -22,6 +22,28 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts, u32 *opmode, int side); +#define GAMUT_OP_MODE_OFF 0 +#define GAMUT_TABLE_INDEX 4 +#define GAMUT_TABLE_UPPER_R 8 +#define GAMUT_TABLE_LOWER_GB 0xC +#define GAMUT_C0_SCALE_OFF 0x10 +#define GAMUT_CLK_CTRL 0xD0 +#define GAMUT_CLK_STATUS 0xD4 +#define GAMUT_READ_TABLE_EN BIT(16) +#define GAMUT_TABLE_SELECT(x) ((BIT(x)) << 12) +#define GAMUT_COARSE_EN (BIT(2)) +#define GAMUT_COARSE_INDEX 1248 +#define GAMUT_FINE_INDEX 0 +#define GAMUT_ENABLE BIT(0) + +static struct mdss_pp_res_type_v1_7 config_data; + +static int pp_gamut_get_config(char __iomem *base_addr, void *cfg_data, + u32 block_type, u32 disp_num); +static int pp_gamut_set_config(char __iomem *base_addr, + struct pp_sts_type *pp_sts, void *cfg_data, + u32 block_type); + void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops) { if (!ops) { @@ -46,8 +68,8 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops) ops->pp_ops[PA].pp_get_config = NULL; /* Gamut ops */ - ops->pp_ops[GAMUT].pp_set_config = NULL; - ops->pp_ops[GAMUT].pp_get_config = NULL; + ops->pp_ops[GAMUT].pp_set_config = pp_gamut_set_config; + ops->pp_ops[GAMUT].pp_get_config = pp_gamut_get_config; /* CSC ops */ ops->pp_ops[CSC].pp_set_config = NULL; @@ -68,7 +90,7 @@ void *pp_get_driver_ops(struct mdp_pp_driver_ops *ops) /* Set opmode pointers */ ops->pp_opmode_config = pp_opmode_config; - return NULL; + return &config_data; } static void pp_opmode_config(int location, struct pp_sts_type *pp_sts, @@ -81,3 +103,238 @@ static void pp_opmode_config(int location, struct pp_sts_type *pp_sts, return; } + +static int pp_gamut_get_config(char __iomem *base_addr, void *cfg_data, + u32 block_type, u32 disp_num) +{ + u32 val = 0, sz = 0, sz_scale = 0, mode = 0, tbl_sz = 0; + u32 index_start = 0; + int i = 0, j = 0, ret = 0; + u32 *gamut_tbl = NULL, *gamut_c0 = NULL, *gamut_c1c2 = NULL; + struct mdp_gamut_cfg_data *gamut_cfg = (struct mdp_gamut_cfg_data *) + cfg_data; + struct mdp_gamut_data_v1_7 gamut_data; + + if (!base_addr || !cfg_data) { + pr_err("invalid params base_addr %p cfg_data %p\n", + base_addr, cfg_data); + return -EINVAL; + } + if (gamut_cfg->version != mdp_gamut_v1_7) { + pr_err("unsupported version of gamut %d\n", + gamut_cfg->version); + return -EINVAL; + } + if (copy_from_user(&gamut_data, gamut_cfg->cfg_payload, + sizeof(gamut_data))) { + pr_err("copy from user failed for gamut_data\n"); + return -EFAULT; + } + mode = readl_relaxed(base_addr + GAMUT_OP_MODE_OFF); + if (mode & GAMUT_COARSE_EN) { + tbl_sz = MDP_GAMUT_TABLE_V1_7_COARSE_SZ; + sz = tbl_sz * sizeof(u32); + index_start = GAMUT_COARSE_INDEX; + } else { + mode = mdp_gamut_fine_mode; + tbl_sz = MDP_GAMUT_TABLE_V1_7_SZ; + sz = tbl_sz * sizeof(u32); + index_start = GAMUT_FINE_INDEX; + } + sz_scale = MDP_GAMUT_SCALE_OFF_SZ * sizeof(u32); + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + if (!access_ok(VERIFY_WRITE, gamut_data.c0_data[i], sz)) { + pr_err("invalid c0 address for sz %d table index %d\n", + sz, (i+1)); + return -EFAULT; + } + if (!access_ok(VERIFY_WRITE, gamut_data.c1_c2_data[i], sz)) { + pr_err("invalid c1c2 address for sz %d table index %d\n", + sz, (i+1)); + return -EFAULT; + } + gamut_data.tbl_size[i] = tbl_sz; + if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM) { + if (!access_ok(VERIFY_WRITE, + gamut_data.scale_off_data[i], sz_scale)) { + pr_err("invalid scale address for sz %d color c%d\n", + sz_scale, i); + return -EFAULT; + } + gamut_data.tbl_scale_off_sz[i] = + MDP_GAMUT_SCALE_OFF_SZ; + } + } + /* allocate for c0 and c1c2 tables */ + gamut_tbl = kzalloc((sz * 2) , GFP_KERNEL); + if (!gamut_tbl) { + pr_err("failed to alloc table of sz %d\n", sz); + return -ENOMEM; + } + gamut_c0 = gamut_tbl; + gamut_c1c2 = gamut_c0 + tbl_sz; + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + val = index_start; + val |= GAMUT_READ_TABLE_EN; + val |= GAMUT_TABLE_SELECT(i); + writel_relaxed(val, (base_addr + GAMUT_TABLE_INDEX)); + for (j = 0; j < tbl_sz; j++) { + gamut_c1c2[j] = readl_relaxed(base_addr + + GAMUT_TABLE_LOWER_GB); + gamut_c0[j] = readl_relaxed(base_addr + + GAMUT_TABLE_UPPER_R); + } + if (copy_to_user(gamut_data.c0_data[i], gamut_c0, sz)) { + pr_err("copy to user failed for table %d c0 sz %d\n", + (i + 1), sz); + ret = -EFAULT; + goto bail_out; + } + if (copy_to_user(gamut_data.c1_c2_data[i], gamut_c1c2, sz)) { + pr_err("copy to user failed for table %d c1c2 sz %d\n", + (i + 1), sz); + ret = -EFAULT; + goto bail_out; + } + } + sz_scale = MDP_GAMUT_SCALE_OFF_TABLE_NUM * MDP_GAMUT_SCALE_OFF_SZ + * sizeof(u32); + if (sz < sz_scale) { + kfree(gamut_tbl); + gamut_tbl = kzalloc(sz_scale , GFP_KERNEL); + if (!gamut_tbl) { + pr_err("failed to alloc scale tbl size %d\n", + sz_scale); + ret = -ENOMEM; + goto bail_out; + } + } + gamut_c0 = gamut_tbl; + base_addr += GAMUT_C0_SCALE_OFF; + for (i = 0; + i < (MDP_GAMUT_SCALE_OFF_TABLE_NUM * MDP_GAMUT_SCALE_OFF_SZ); + i++) { + gamut_c0[i] = readl_relaxed(base_addr); + base_addr += 4; + } + for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) { + if (copy_to_user(gamut_data.scale_off_data[i], + &gamut_c0[i * MDP_GAMUT_SCALE_OFF_SZ], + (MDP_GAMUT_SCALE_OFF_SZ * sizeof(u32)))) { + pr_err("copy to user failed for scale color c%d\n", + i); + ret = -EFAULT; + goto bail_out; + } + } + if (copy_to_user(gamut_cfg->cfg_payload, &gamut_data, + sizeof(gamut_data))) { + pr_err("failed to copy the gamut info into payload\n"); + ret = -EFAULT; + } +bail_out: + kfree(gamut_tbl); + return ret; +} + +static int pp_gamut_set_config(char __iomem *base_addr, + struct pp_sts_type *pp_sts, void *cfg_data, + u32 block_type) +{ + int val = 0, ret = 0, i = 0, j = 0; + u32 index_start = 0, tbl_sz = 0; + struct mdp_gamut_cfg_data *gamut_cfg_data = NULL; + struct mdp_gamut_data_v1_7 *gamut_data = NULL; + char __iomem *base_addr_scale = base_addr; + 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; + } + gamut_cfg_data = (struct mdp_gamut_cfg_data *) cfg_data; + if (gamut_cfg_data->version != mdp_gamut_v1_7) { + pr_err("invalid gamut version %d\n", gamut_cfg_data->version); + return -EINVAL; + } + if (!(gamut_cfg_data->flags & ~(MDP_PP_OPS_READ))) { + pr_info("only read ops is set %d", gamut_cfg_data->flags); + return 0; + } + gamut_data = gamut_cfg_data->cfg_payload; + if (!gamut_data) { + pr_err("invalid payload for gamut %p\n", gamut_data); + return -EINVAL; + } + + if (gamut_data->mode != mdp_gamut_fine_mode && + gamut_data->mode != mdp_gamut_coarse_mode) { + pr_err("invalid gamut mode %d", gamut_data->mode); + return -EINVAL; + } + index_start = (gamut_data->mode == mdp_gamut_fine_mode) ? + GAMUT_FINE_INDEX : GAMUT_COARSE_INDEX; + tbl_sz = (gamut_data->mode == mdp_gamut_fine_mode) ? + MDP_GAMUT_TABLE_V1_7_SZ : MDP_GAMUT_TABLE_V1_7_COARSE_SZ; + if (!(gamut_cfg_data->flags & MDP_PP_OPS_WRITE)) + goto bail_out; + /* Sanity check for all tables */ + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + if (!gamut_data->c0_data[i] || !gamut_data->c1_c2_data[i] + || (gamut_data->tbl_size[i] != tbl_sz)) { + pr_err("invalid param for c0 %p c1c2 %p table %d size %d expected sz %d\n", + gamut_data->c0_data[i], + gamut_data->c1_c2_data[i], (i + 1), + gamut_data->tbl_size[i], tbl_sz); + ret = -EINVAL; + goto bail_out; + } + if (i < MDP_GAMUT_SCALE_OFF_TABLE_NUM && + (!gamut_data->scale_off_data[i] || + (gamut_data->tbl_scale_off_sz[i] != + MDP_GAMUT_SCALE_OFF_SZ))) { + pr_err("invalid param for scale table %p for c%d size %d expected size%d\n", + gamut_data->scale_off_data[i], i, + gamut_data->tbl_scale_off_sz[i], + MDP_GAMUT_SCALE_OFF_SZ); + ret = -EINVAL; + goto bail_out; + } + } + base_addr_scale += GAMUT_C0_SCALE_OFF; + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + val = index_start; + val |= GAMUT_TABLE_SELECT(i); + writel_relaxed(val, (base_addr + GAMUT_TABLE_INDEX)); + for (j = 0; j < gamut_data->tbl_size[i]; j++) { + writel_relaxed(gamut_data->c1_c2_data[i][j], + base_addr + GAMUT_TABLE_LOWER_GB); + writel_relaxed(gamut_data->c0_data[i][j], + base_addr + GAMUT_TABLE_UPPER_R); + } + if (i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM) + continue; + for (j = 0; j < MDP_GAMUT_SCALE_OFF_SZ; j++) { + writel_relaxed((gamut_data->scale_off_data[i][j]), + base_addr_scale); + base_addr_scale += 4; + } + } +bail_out: + if (!ret) { + val = 0; + if (gamut_cfg_data->flags & MDP_PP_OPS_DISABLE) { + pp_sts->gamut_sts &= ~PP_STS_ENABLE; + writel_relaxed(val, base_addr + GAMUT_OP_MODE_OFF); + } else if (gamut_cfg_data->flags & MDP_PP_OPS_ENABLE) { + if (gamut_data->mode == mdp_gamut_coarse_mode) + val |= GAMUT_COARSE_EN; + val |= GAMUT_ENABLE; + writel_relaxed(val, base_addr + GAMUT_OP_MODE_OFF); + pp_sts->gamut_sts |= PP_STS_ENABLE; + } + pp_sts_set_split_bits(&pp_sts->gamut_sts, + gamut_cfg_data->flags); + } + return ret; +} + diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 335bcc082e46..7eba5283018d 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -307,6 +307,7 @@ struct mdp_blit_req { uint32_t transp_mask; uint32_t flags; int sharpening_strength; /* -127 <--> 127, default 64 */ + uint8_t color_space; }; struct mdp_blit_req_list { @@ -426,19 +427,34 @@ struct mdp_qseed_cfg_data { #define MDP_CSC_FLAG_YUV_IN 0x2 #define MDP_CSC_FLAG_YUV_OUT 0x4 +#define MDP_CSC_MATRIX_COEFF_SIZE 9 +#define MDP_CSC_CLAMP_SIZE 6 +#define MDP_CSC_BIAS_SIZE 3 + struct mdp_csc_cfg { /* flags for enable CSC, toggling RGB,YUV input/output */ uint32_t flags; - uint32_t csc_mv[9]; - uint32_t csc_pre_bv[3]; - uint32_t csc_post_bv[3]; - uint32_t csc_pre_lv[6]; - uint32_t csc_post_lv[6]; + uint32_t csc_mv[MDP_CSC_MATRIX_COEFF_SIZE]; + uint32_t csc_pre_bv[MDP_CSC_BIAS_SIZE]; + uint32_t csc_post_bv[MDP_CSC_BIAS_SIZE]; + uint32_t csc_pre_lv[MDP_CSC_CLAMP_SIZE]; + uint32_t csc_post_lv[MDP_CSC_CLAMP_SIZE]; +}; + +struct mdp_csc_cfg_v1_7 { + uint32_t csc_mv[MDP_CSC_MATRIX_COEFF_SIZE]; + uint32_t csc_pre_bv[MDP_CSC_BIAS_SIZE]; + uint32_t csc_post_bv[MDP_CSC_BIAS_SIZE]; + uint32_t csc_pre_lv[MDP_CSC_CLAMP_SIZE]; + uint32_t csc_post_lv[MDP_CSC_CLAMP_SIZE]; }; struct mdp_csc_cfg_data { uint32_t block; + uint32_t version; + uint32_t flags; struct mdp_csc_cfg csc_data; + void *cfg_payload; }; struct mdp_pa_cfg { @@ -457,6 +473,16 @@ struct mdp_pa_mem_col_cfg { uint32_t val_region; }; +struct mdp_pa_mem_col_cfg_v1_7 { + uint32_t color_adjust_p0; + uint32_t color_adjust_p1; + uint32_t color_adjust_p2; + uint32_t blend_gain; + uint32_t hue_region; + uint32_t sat_region; + uint32_t val_region; +}; + #define MDP_SIX_ZONE_LUT_SIZE 384 struct mdp_pa_v2_data { @@ -466,20 +492,53 @@ struct mdp_pa_v2_data { uint32_t global_sat_adj; uint32_t global_val_adj; uint32_t global_cont_adj; + struct mdp_pa_mem_col_cfg skin_cfg; + struct mdp_pa_mem_col_cfg sky_cfg; + struct mdp_pa_mem_col_cfg fol_cfg; uint32_t six_zone_len; + uint32_t six_zone_thresh; uint32_t *six_zone_curve_p0; uint32_t *six_zone_curve_p1; +}; + +struct mdp_pa_data_v1_7 { + uint32_t global_hue_adj; + uint32_t global_sat_adj; + uint32_t global_val_adj; + uint32_t global_cont_adj; + struct mdp_pa_mem_col_cfg_v1_7 skin_cfg; + struct mdp_pa_mem_col_cfg_v1_7 sky_cfg; + struct mdp_pa_mem_col_cfg_v1_7 fol_cfg; + uint32_t six_zone_len; uint32_t six_zone_thresh; - struct mdp_pa_mem_col_cfg skin_cfg; - struct mdp_pa_mem_col_cfg sky_cfg; - struct mdp_pa_mem_col_cfg fol_cfg; + uint32_t six_zone_adj_p0; + uint32_t six_zone_adj_p1; + uint32_t *six_zone_curve_p0; + uint32_t *six_zone_curve_p1; +}; + +struct mdp_pa_v2_cfg_data { + uint32_t version; + uint32_t block; + uint32_t flags; + uint32_t mode; + struct mdp_pa_v2_data pa_v2_data; + void *cfg_payload; }; struct mdp_igc_lut_data { uint32_t block; + uint32_t version; uint32_t len, ops; uint32_t *c0_c1_data; uint32_t *c2_data; + void *cfg_payload; +}; + +struct mdp_igc_lut_data_v1_7 { + uint32_t len; + uint32_t *c0_c1_data; + uint32_t *c2_data; }; struct mdp_histogram_cfg { @@ -490,11 +549,18 @@ struct mdp_histogram_cfg { uint16_t num_bins; }; +struct mdp_hist_lut_data_v1_7 { + uint32_t len; + uint32_t *data; +}; + struct mdp_hist_lut_data { uint32_t block; + uint32_t version; uint32_t ops; uint32_t len; uint32_t *data; + void *cfg_payload; }; struct mdp_overlay_pp_params { @@ -651,6 +717,7 @@ struct mdp_overlay { uint8_t vert_deci; struct mdp_overlay_pp_params overlay_pp_cfg; struct mdp_scale_data scale; + uint8_t color_space; }; struct msmfb_overlay_3d { @@ -765,14 +832,22 @@ struct mdp_pcc_coeff { uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1; }; +struct mdp_pcc_coeff_v1_7 { + uint32_t c, r, g, b, rg, gb, rb, rgb; +}; + +struct mdp_pcc_data_v1_7 { + struct mdp_pcc_coeff_v1_7 r, g, b; +}; + struct mdp_pcc_cfg_data { + uint32_t version; uint32_t block; uint32_t ops; struct mdp_pcc_coeff r, g, b; + void *cfg_payload; }; -#define MDP_GAMUT_TABLE_NUM 8 - enum { mdp_lut_igc, mdp_lut_pgc, @@ -780,6 +855,8 @@ enum { mdp_lut_max, }; +#define GC_LUT_ENTRIES_V1_7 512 + struct mdp_ar_gc_lut_data { uint32_t x_start; uint32_t slope; @@ -787,6 +864,7 @@ struct mdp_ar_gc_lut_data { }; struct mdp_pgc_lut_data { + uint32_t version; uint32_t block; uint32_t flags; uint8_t num_r_stages; @@ -795,8 +873,15 @@ struct mdp_pgc_lut_data { struct mdp_ar_gc_lut_data *r_data; struct mdp_ar_gc_lut_data *g_data; struct mdp_ar_gc_lut_data *b_data; + void *cfg_payload; }; +struct mdp_pgc_lut_data_v1_7 { + uint32_t len; + uint32_t *c0_data; + uint32_t *c1_data; + uint32_t *c2_data; +}; struct mdp_lut_cfg_data { uint32_t lut_type; @@ -817,27 +902,62 @@ struct mdp_pa_cfg_data { struct mdp_pa_cfg pa_data; }; -struct mdp_pa_v2_cfg_data { - uint32_t block; - struct mdp_pa_v2_data pa_v2_data; +struct mdp_dither_data_v1_7 { + uint32_t g_y_depth; + uint32_t r_cr_depth; + uint32_t b_cb_depth; }; struct mdp_dither_cfg_data { + uint32_t version; uint32_t block; uint32_t flags; + uint32_t mode; uint32_t g_y_depth; uint32_t r_cr_depth; uint32_t b_cb_depth; + void *cfg_payload; +}; + +#define MDP_GAMUT_TABLE_NUM 8 +#define MDP_GAMUT_TABLE_NUM_V1_7 4 +#define MDP_GAMUT_SCALE_OFF_TABLE_NUM 3 +#define MDP_GAMUT_TABLE_V1_7_SZ 1228 +#define MDP_GAMUT_SCALE_OFF_SZ 16 +#define MDP_GAMUT_TABLE_V1_7_COARSE_SZ 32 + +enum { + mdp_gamut_v1_7 = 1, + mdp_gamut_vmax, }; + struct mdp_gamut_cfg_data { uint32_t block; uint32_t flags; + uint32_t version; + /* v1 version specific params */ uint32_t gamut_first; uint32_t tbl_size[MDP_GAMUT_TABLE_NUM]; uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM]; uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM]; uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM]; + /* params for newer versions of gamut */ + void *cfg_payload; +}; + +enum { + mdp_gamut_fine_mode = 0x1, + mdp_gamut_coarse_mode, +}; + +struct mdp_gamut_data_v1_7 { + uint32_t mode; + uint32_t tbl_size[MDP_GAMUT_TABLE_NUM_V1_7]; + uint32_t *c0_data[MDP_GAMUT_TABLE_NUM_V1_7]; + uint32_t *c1_c2_data[MDP_GAMUT_TABLE_NUM_V1_7]; + uint32_t tbl_scale_off_sz[MDP_GAMUT_SCALE_OFF_TABLE_NUM]; + uint32_t *scale_off_data[MDP_GAMUT_SCALE_OFF_TABLE_NUM]; }; struct mdp_calib_config_data { @@ -1008,6 +1128,7 @@ struct msmfb_mdp_pp { struct mdp_gamut_cfg_data gamut_cfg_data; struct mdp_calib_config_data calib_cfg; struct mdss_ad_init_cfg ad_init_cfg; + struct mdss_calib_cfg mdss_calib_cfg; struct mdss_ad_input ad_input; struct mdp_calib_config_buffer calib_buffer; struct mdp_calib_dcm_state calib_dcm; @@ -1063,7 +1184,7 @@ struct msmfb_metadata { } data; }; -#define MDP_MAX_FENCE_FD 10 +#define MDP_MAX_FENCE_FD 32 #define MDP_BUF_SYNC_FLAG_WAIT 1 #define MDP_BUF_SYNC_FLAG_RETIRE_FENCE 0x10 @@ -1147,4 +1268,10 @@ enum { MDP_WRITEBACK_MIRROR_PAUSE, MDP_WRITEBACK_MIRROR_RESUME, }; + +enum { + MDP_CSC_ITU_R_601, + MDP_CSC_ITU_R_601_FR, + MDP_CSC_ITU_R_709, +}; #endif /*_UAPI_MSM_MDP_H_*/ |
