diff options
| author | Carl Vanderlip <carlv@codeaurora.org> | 2013-12-11 13:27:00 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:24:26 -0700 |
| commit | ecde0d8ccdc798540bdb3cc68ad62882cd7e96a0 (patch) | |
| tree | e1ce0ee881833aea50a156bb4229f3de123c2fe3 /drivers/video/fbdev | |
| parent | 14df43f7ed1d25e38a3717baa9f2c48ac5375ef9 (diff) | |
msm: mdss: Support demo mode for post processing
Add demo mode feature for numerous post processing features. In dual pipe
case, demo mode allows for either the left or right pipe's feature to be
disabled to showcase its effects. Features supported include assertive
display, gamut mapping, panel gamma correction, inverse gamma correction,
dithering, picture adjustment (v2 only), and polynomial color correction.
Change-Id: I8bceeffc11967ff23497df7739e6f99c30d2b10f
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
Signed-off-by: Ping Li <quicpingli@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 196 |
2 files changed, 173 insertions, 24 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 9e0e9cc4afc9..df285ab7f5cb 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -285,6 +285,7 @@ struct mdss_mdp_ad { struct mdss_ad_info { u8 num; u8 calc_hw_num; + u32 ops; u32 sts; u32 reg_sts; u32 state; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index cd65bbe33c61..545e14fc69fc 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -214,6 +214,10 @@ static u32 igc_limited[IGC_LUT_ENTRIES] = { #define PP_AD_BAD_HW_NUM 255 +#define MDSS_SIDE_NONE 0 +#define MDSS_SIDE_LEFT 1 +#define MDSS_SIDE_RIGHT 2 + #define PP_AD_STATE_INIT 0x2 #define PP_AD_STATE_CFG 0x4 #define PP_AD_STATE_DATA 0x8 @@ -302,8 +306,8 @@ struct mdss_pp_res_type { struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM]; uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE]; u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE]; - /* physical info */ struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM]; + /* physical info */ struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP]; }; @@ -350,8 +354,9 @@ static void pp_enhist_config(unsigned long flags, char __iomem *addr, static void pp_dither_config(char __iomem *addr, struct pp_sts_type *pp_sts, struct mdp_dither_cfg_data *dither_cfg); -static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode, - int mdp_rev); +static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num, + struct pp_sts_type *pp_sts, int mdp_rev, + u32 *opmode); static void pp_sharp_config(char __iomem *addr, struct pp_sts_type *pp_sts, struct mdp_sharp_cfg *sharp_config); @@ -385,11 +390,15 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl); static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad); -static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode); static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd, struct mdss_ad_info *ad); +static void pp_ad_bypass_config(struct mdss_ad_info *ad, + struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode); static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd); static void pp_ad_cfg_lut(char __iomem *addr, u32 *data); +static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num); +static inline bool pp_sts_is_enabled(u32 sts, int side); +static inline void pp_sts_set_split_bits(u32 *sts, u32 bits); static u32 last_sts, last_state; @@ -528,6 +537,7 @@ static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg, pp_sts->gamut_sts &= ~PP_STS_ENABLE; else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE) pp_sts->gamut_sts |= PP_STS_ENABLE; + pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags); } static void pp_pa_config(unsigned long flags, char __iomem *addr, @@ -696,6 +706,7 @@ static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts, if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK) pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK; + pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags); } static void pp_pcc_config(unsigned long flags, char __iomem *addr, @@ -710,6 +721,7 @@ static void pp_pcc_config(unsigned long flags, char __iomem *addr, pp_sts->pcc_sts &= ~PP_STS_ENABLE; else if (pcc_config->ops & MDP_PP_OPS_ENABLE) pp_sts->pcc_sts |= PP_STS_ENABLE; + pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops); } } @@ -737,6 +749,7 @@ static void pp_igc_config(unsigned long flags, char __iomem *addr, pp_sts->igc_sts &= ~PP_STS_ENABLE; else if (igc_config->ops & MDP_PP_OPS_ENABLE) pp_sts->igc_sts |= PP_STS_ENABLE; + pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops); } } @@ -1348,12 +1361,20 @@ static void pp_dither_config(char __iomem *addr, pp_sts->dither_sts &= ~PP_STS_ENABLE; else if (dither_cfg->flags & MDP_PP_OPS_ENABLE) pp_sts->dither_sts |= PP_STS_ENABLE; + pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags); } -static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode, - int mdp_rev) +static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num, + struct pp_sts_type *pp_sts, int mdp_rev, + u32 *opmode) { - if (pp_sts->pa_sts & PP_STS_ENABLE) + int side; + side = pp_num_to_side(ctl, num); + + if (side < 0) + return; + + if (pp_sts_is_enabled(pp_sts->pa_sts, side)) *opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */ if (mdp_rev >= MDSS_MDP_HW_REV_103) { if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK) @@ -1381,10 +1402,10 @@ static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode, if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK) *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK; } - if (pp_sts->pcc_sts & PP_STS_ENABLE) + if (pp_sts_is_enabled(pp_sts->pcc_sts, side)) *opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */ - if (pp_sts->igc_sts & PP_STS_ENABLE) { + if (pp_sts_is_enabled(pp_sts->igc_sts, side)) { *opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */ (pp_sts->igc_tbl_idx << 1); } @@ -1392,14 +1413,14 @@ static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode, *opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */ MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */ } - if (pp_sts->dither_sts & PP_STS_ENABLE) + if (pp_sts_is_enabled(pp_sts->dither_sts, side)) *opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */ - if (pp_sts->gamut_sts & PP_STS_ENABLE) { + if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) { *opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */ if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST) *opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER; } - if (pp_sts->pgc_sts & PP_STS_ENABLE) + if (pp_sts_is_enabled(pp_sts->pgc_sts, side)) *opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN; } @@ -1505,6 +1526,7 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) 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 (ad_hw) { @@ -1516,12 +1538,12 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer) pp_ad_init_write(ad_hw, ad, ctl); if (ad_flags & PP_AD_STS_DIRTY_CFG) pp_ad_cfg_write(ad_hw, ad); - pp_ad_bypass_config(ad, &ad_bypass); + pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass); writel_relaxed(ad_bypass, ad_hw->base); mutex_unlock(&ad->lock); } - pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev); + pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode); flush_exit: writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE); @@ -1868,6 +1890,12 @@ int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config, (config->block >= MDP_BLOCK_MAX)) return -EINVAL; + if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) == + MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&mdss_pp_mutex); disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; @@ -2157,6 +2185,11 @@ int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, (config->block >= MDP_BLOCK_MAX)) return -EINVAL; + if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&mdss_pp_mutex); disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; @@ -2276,6 +2309,11 @@ int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, if (config->len != IGC_LUT_ENTRIES) return -EINVAL; + if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&mdss_pp_mutex); disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; @@ -2475,6 +2513,11 @@ int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, (PP_BLOCK(config->block) >= MDP_BLOCK_MAX)) return -EINVAL; + if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&mdss_pp_mutex); disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0; @@ -2646,6 +2689,11 @@ int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, if (config->flags & MDP_PP_OPS_READ) return -ENOTSUPP; + if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&mdss_pp_mutex); disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; mdss_pp_res->dither_disp_cfg[disp_num] = *config; @@ -2696,6 +2744,11 @@ int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, 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; + } + mutex_lock(&mdss_pp_mutex); disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; @@ -3543,6 +3596,53 @@ static struct msm_fb_data_type *mdss_get_mfd_from_index(int index) return out; } +static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num) +{ + u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; + u32 mixer_num; + + if (!ctl || !ctl->mfd) + return -EINVAL; + mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id); + if (mixer_num < 2) + return MDSS_SIDE_NONE; + else if (mixer_id[1] == num) + return MDSS_SIDE_RIGHT; + else if (mixer_id[0] == num) + return MDSS_SIDE_LEFT; + else + pr_err("invalid, not on any side"); + return -EINVAL; +} + +static inline void pp_sts_set_split_bits(u32 *sts, u32 bits) +{ + u32 tmp = *sts; + tmp &= ~MDSS_PP_SPLIT_MASK; + tmp |= bits & MDSS_PP_SPLIT_MASK; + *sts = tmp; +} + +static inline bool pp_sts_is_enabled(u32 sts, int side) +{ + bool ret = false; + /* + * If there are no sides, or if there are no split mode bits set, the + * side can't be disabled via split mode. + * + * Otherwise, if the side being checked opposes the split mode + * configuration, the side is disabled. + */ + if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK)) + ret = true; + else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT)) + ret = true; + else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT)) + ret = true; + + return ret && (sts & PP_STS_ENABLE); +} + static int mdss_ad_init_checks(struct msm_fb_data_type *mfd) { u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; @@ -3638,7 +3738,7 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd, struct mdss_ad_info *ad; struct msm_fb_data_type *bl_mfd; int lin_ret = -1, inv_ret = -1, ret = 0; - u32 ratio_temp, shift = 0; + u32 ratio_temp, shift = 0, last_ops; ret = mdss_mdp_get_ad(mfd, &ad); if (ret) @@ -3651,6 +3751,11 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd, bl_mfd = mfd; } + if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) { + pr_warn("Can't set both split bits\n"); + return -EINVAL; + } + mutex_lock(&ad->lock); if (init_cfg->ops & MDP_PP_AD_INIT) { memcpy(&ad->init, &init_cfg->params.init, @@ -3693,6 +3798,22 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd, ad->sts |= PP_AD_STS_DIRTY_CFG; } + last_ops = ad->ops & MDSS_PP_SPLIT_MASK; + ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK; + /* + * if there is a change in the split mode config, the init values + * need to be re-written to hardware (if they have already been + * written or if there is data pending to be written). Check for + * pending data (DIRTY_INIT) is not checked here since it will not + * affect the outcome of this conditional (i.e. if init hasn't + * already been written (*_STATE_INIT is set), this conditional will + * only evaluate to true (and set the DIRTY bit) if the DIRTY bit has + * already been set). + */ + if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT)) + ad->sts |= PP_AD_STS_DIRTY_INIT; + + if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) { ad->sts &= ~PP_STS_ENABLE; mutex_unlock(&ad->lock); @@ -3847,8 +3968,9 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, u32 temp; u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl; u32 num; + int side; char __iomem *base; - bool is_calc, is_dual_pipe; + bool is_calc, is_dual_pipe, split_mode; u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; u32 mixer_num; mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id); @@ -3859,6 +3981,7 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, base = ad_hw->base; is_calc = ad->calc_hw_num == ad_hw->num; + split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK); writel_relaxed(ad->init.i_control[0] & 0x1F, base + MDSS_MDP_REG_AD_CON_CTRL_0); @@ -3884,7 +4007,10 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0); writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1); - temp = ad->init.frame_w << 16; + if (split_mode) + temp = mdata->mixer_intf[ad_hw->num].width << 16; + else + temp = ad->init.frame_w << 16; temp |= ad->init.frame_h & 0xFFFF; writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE); @@ -3896,17 +4022,26 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut); if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) { - if (is_dual_pipe) { + if (is_dual_pipe && !split_mode) { num = ad_hw->num; + side = pp_num_to_side(ctl, num); tile_ctrl = 0x5; - if (is_calc) { + if ((ad->calc_hw_num + 1) == num) + tile_ctrl |= 0x10; + + if (side <= MDSS_SIDE_NONE) { + WARN(1, "error finding sides, %d", side); + frame_start = 0; + procs_start = frame_start; + frame_end = 0; + procs_end = frame_end; + } else if (side == MDSS_SIDE_LEFT) { frame_start = 0; procs_start = 0; frame_end = mdata->mixer_intf[num].width + MDSS_AD_MERGED_WIDTH; procs_end = mdata->mixer_intf[num].width; } else { - tile_ctrl |= 0x10; procs_start = ad->init.frame_w - (mdata->mixer_intf[num].width); procs_end = ad->init.frame_w; @@ -3921,8 +4056,13 @@ static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad, frame_end = 0xFFFF; procs_start = 0x0; procs_end = 0xFFFF; - tile_ctrl = 0x1; + if (split_mode) + tile_ctrl = 0x0; + else + tile_ctrl = 0x1; } + + writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START); writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END); writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START); @@ -3986,12 +4126,17 @@ static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t) } #define MDSS_PP_AD_BYPASS_DEF 0x101 -static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode) +static void pp_ad_bypass_config(struct mdss_ad_info *ad, + struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode) { - if (ad->reg_sts & PP_STS_ENABLE) + int side = pp_num_to_side(ctl, num); + + if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK), + side)) { *opmode = 0; - else + } else { *opmode = MDSS_PP_AD_BYPASS_DEF; + } } static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd, @@ -4006,6 +4151,8 @@ static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd, /* default to left mixer */ ad->calc_hw_num = mixer_id[0]; + if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY)) + ad->calc_hw_num = mixer_id[1]; return 0; } @@ -4313,6 +4460,7 @@ int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets) mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i]; mdata->ad_off[i].num = i; mdata->ad_cfgs[i].num = i; + mdata->ad_cfgs[i].ops = 0; mdata->ad_cfgs[i].reg_sts = 0; mdata->ad_cfgs[i].calc_itr = 0; mdata->ad_cfgs[i].last_str = 0xFFFFFFFF; |
