diff options
| author | Ping Li <pingli@codeaurora.org> | 2015-12-16 18:46:12 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:14:45 -0700 |
| commit | da613e9e0b3e1098a9748013fddb37d87db474f4 (patch) | |
| tree | 18b7ea994ff706ada62a0099cc4bdc832345196b | |
| parent | bc6c912958babe08a1dfa5e87461feea0921b982 (diff) | |
msm: mdss: maintain AD state through idle power collapse
When device enters the idle power collapse mode, the entire
AD HW block is powered down, which will cause the previous
AD settings get lost. So when device exits the idle power
collapse mode, we need to store AD to previous state.
In order to achieve this, we need to switch AD mode to 0x85 first
and manually write the last AD strength value to AD register. Keep
this setting for couple of frames, in the meantime, kick off AD
calculator with t_filter_control value of 0 to ramp up the AD
strength from 0 to current target strength. Then switch the mode
back to auto strength (0x81).
Change-Id: Iddc12dbb0da06675141fa9fe049cfe90110defb9
Signed-off-by: Ping Li <pingli@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 180 |
4 files changed, 161 insertions, 30 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index ee3f9bdb24e3..b93fb55400aa 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -304,6 +304,7 @@ struct msm_fb_data_type { bool allow_bl_update; u32 bl_level_scaled; struct mutex bl_lock; + bool ipc_resume; struct platform_device *pdev; diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 2e74ff1d56eb..03fe9cc6b43b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -521,6 +521,11 @@ struct mdss_ad_info { struct mdss_mdp_vsync_handler handle; u32 last_str; u32 last_bl; + u32 last_ad_data; + u16 last_calib[4]; + bool last_ad_data_valid; + bool last_calib_valid; + u32 ipc_frame_count; u32 bl_data; u32 calc_itr; uint32_t bl_lin[AD_BL_LIN_LEN]; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index b9305c85bf1b..7a1c5c5be74a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -3565,6 +3565,7 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl) MDSS_MDP_REG_DISP_INTF_SEL); if (ctl->mfd && ctl->panel_data) { + ctl->mfd->ipc_resume = true; mdss_mdp_pp_resume(ctl->mfd); if (is_dsc_compression(&ctl->panel_data->panel_info)) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index c57097c35628..520302023827 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -357,6 +357,8 @@ static u32 igc_limited[IGC_LUT_ENTRIES] = { #define PP_AD_STATE_RUN 0x10 #define PP_AD_STATE_VSYNC 0x20 #define PP_AD_STATE_BL_LIN 0x40 +#define PP_AD_STATE_IPC_RESUME 0x80 +#define PP_AD_STATE_IPC_RESET 0x100 #define PP_AD_STATE_IS_INITCFG(st) (((st) & PP_AD_STATE_INIT) &&\ ((st) & PP_AD_STATE_CFG)) @@ -374,8 +376,8 @@ static u32 igc_limited[IGC_LUT_ENTRIES] = { #define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\ ((sts) & PP_AD_STS_DIRTY_CFG)) -/* Bits 0 and 1 */ -#define MDSS_AD_INPUT_AMBIENT (0x03) +/* Bits 0 and 1 and 5 */ +#define MDSS_AD_INPUT_AMBIENT (0x23) /* Bits 3 and 7 */ #define MDSS_AD_INPUT_STRENGTH (0x88) /* @@ -388,6 +390,10 @@ static u32 igc_limited[IGC_LUT_ENTRIES] = { #define MDSS_AD_RUNNING_AUTO_STR(ad) (((ad)->state & PP_AD_STATE_RUN) &&\ ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_STR)) #define MDSS_AD_AUTO_TRIGGER 0x80 +#define MDSS_AD_T_FILTER_CTRL_0 0 +#define MDSS_AD_IPC_FRAME_COUNT 2 +#define MDSS_AD_MODE_IPC_BIT 0x4 +#define MDSS_AD_MODE_MAN_IPC 0x5 #define SHARP_STRENGTH_DEFAULT 32 #define SHARP_EDGE_THR_DEFAULT 112 @@ -500,7 +506,7 @@ static inline int pp_validate_dspp_mfd_block(struct msm_fb_data_type *mfd, int block); static int pp_mfd_release_all(struct msm_fb_data_type *mfd); static int pp_mfd_ad_release_all(struct msm_fb_data_type *mfd); - +static int mdss_mdp_ad_ipc_reset(struct msm_fb_data_type *mfd); static u32 last_sts, last_state; static inline void mdss_mdp_pp_get_dcm_state(struct mdss_mdp_pipe *pipe, @@ -2030,6 +2036,14 @@ 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); + + if (ad->state & PP_AD_STATE_IPC_RESET) { + writel_relaxed(ad->cfg.t_filter_recursion, + ad_hw->base + MDSS_MDP_REG_AD_TFILT_CTRL); + writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER, + ad_hw->base + MDSS_MDP_REG_AD_MODE_SEL); + } + pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass); writel_relaxed(ad_bypass, ad_hw->base); mutex_unlock(&ad->lock); @@ -2144,6 +2158,14 @@ int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl) pp_mixer_setup(ctl->mixer_right); pp_dspp_setup(disp_num, ctl->mixer_right); } + + if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw) && + valid_ad_panel) { + ret = mdss_mdp_ad_ipc_reset(ctl->mfd); + if (ret < 0) + pr_warn("ad_setup(disp%d) returns %d\n", disp_num, ret); + } + /* clear dirty flag */ if (disp_num < MDSS_BLOCK_DISP_NUM) { mdss_pp_res->pp_disp_flags[disp_num] = 0; @@ -2274,6 +2296,17 @@ int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd) } mutex_lock(&ad->lock); + if (mfd->ipc_resume) { + mfd->ipc_resume = false; + if (PP_AD_STATE_RUN & ad->state) { + ad->ipc_frame_count = 0; + ad->state |= PP_AD_STATE_IPC_RESUME; + ad->cfg.mode |= MDSS_AD_MODE_IPC_BIT; + pr_debug("switch mode to %d, last_ad_data = %d\n", + ad->cfg.mode, ad->last_ad_data); + } + } + if (PP_AD_STATE_CFG & ad->state) ad->sts |= PP_AD_STS_DIRTY_CFG; if (PP_AD_STATE_INIT & ad->state) @@ -2281,7 +2314,9 @@ int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd) if ((PP_AD_STATE_DATA & ad->state) && (ad->sts & PP_STS_ENABLE)) ad->sts |= PP_AD_STS_DIRTY_DATA; - ad->state &= ~PP_AD_STATE_VSYNC; + + if (PP_AD_STATE_RUN & ad->state) + ad->state &= ~PP_AD_STATE_VSYNC; mutex_unlock(&ad->lock); return 0; @@ -5195,6 +5230,8 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd, } else if (init_cfg->ops & MDP_PP_AD_CFG) { memcpy(&ad->cfg, &init_cfg->params.cfg, sizeof(struct mdss_ad_cfg)); + if (ad->state & PP_AD_STATE_IPC_RESUME) + ad->cfg.mode |= MDSS_AD_MODE_IPC_BIT; ad->cfg.backlight_scale = MDSS_MDP_AD_BL_SCALE; ad->sts |= PP_AD_STS_DIRTY_CFG; mdp5_data = mfd_to_mdp5_data(mfd); @@ -5266,6 +5303,7 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd, case MDSS_AD_MODE_AUTO_STR: if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, MDSS_AD_INPUT_AMBIENT)) { + pr_err("Invalid mode %x\n", ad->cfg.mode); ret = -EINVAL; goto error; } @@ -5288,6 +5326,7 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd, case MDSS_AD_MODE_MAN_STR: if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, MDSS_AD_INPUT_STRENGTH)) { + pr_err("Invalid mode %x\n", ad->cfg.mode); ret = -EINVAL; goto error; } @@ -5344,6 +5383,8 @@ static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw, writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL); break; case MDSS_AD_MODE_AUTO_STR: + ad->last_ad_data = ad->ad_data; + ad->last_ad_data_valid = true; writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL); writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL); break; @@ -5355,6 +5396,15 @@ static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw, writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL); writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN); break; + case MDSS_AD_MODE_MAN_IPC: + if (!ad->last_ad_data_valid) { + ad->last_ad_data = ad->ad_data; + ad->last_ad_data_valid = true; + } + writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL); + writel_relaxed(ad->last_ad_data, base + MDSS_MDP_REG_AD_AL); + writel_relaxed(ad->last_str, base + MDSS_MDP_REG_AD_STR_MAN); + break; default: pr_warn("Invalid mode! %d\n", ad->cfg.mode); break; @@ -5487,6 +5537,8 @@ static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad) temp |= ad->cfg.filter[0] & 0xFFFF; writel_relaxed(temp, base + MDSS_MDP_REG_AD_AL_FILT); case MDSS_AD_MODE_AUTO_STR: + memcpy(ad->last_calib, ad->cfg.calib, sizeof(ad->last_calib)); + ad->last_calib_valid = true; pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL, ad->cfg.al_calib_lut); writel_relaxed(ad->cfg.strength_limit, @@ -5505,7 +5557,32 @@ static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad) writel_relaxed(ad->cfg.backlight_scale, base + MDSS_MDP_REG_AD_BL_MAX); writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER, - base + MDSS_MDP_REG_AD_MODE_SEL); + base + MDSS_MDP_REG_AD_MODE_SEL); + pr_debug("stab_itr = %d\n", ad->cfg.stab_itr); + break; + case MDSS_AD_MODE_MAN_IPC: + if (!ad->last_calib_valid) { + memcpy(ad->last_calib, ad->cfg.calib, + sizeof(ad->last_calib)); + ad->last_calib_valid = true; + } + writel_relaxed(MDSS_AD_T_FILTER_CTRL_0, + base + MDSS_MDP_REG_AD_TFILT_CTRL); + pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL, + ad->cfg.al_calib_lut); + writel_relaxed(ad->cfg.strength_limit, + base + MDSS_MDP_REG_AD_STR_LIM); + temp = ad->last_calib[3] << 16; + temp |= ad->last_calib[2] & 0xFFFF; + writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_CD); + temp_calib = ad->last_calib[0] & 0xFFFF; + temp = ad->last_calib[1] << 16; + temp |= temp_calib; + writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_AB); + writel_relaxed(ad->cfg.backlight_scale, + base + MDSS_MDP_REG_AD_BL_MAX); + writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER, + base + MDSS_MDP_REG_AD_MODE_SEL); pr_debug("stab_itr = %d\n", ad->cfg.stab_itr); break; default: @@ -5555,6 +5632,35 @@ static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd, return 0; } +static int mdss_mdp_ad_ipc_reset(struct msm_fb_data_type *mfd) +{ + int ret = 0; + struct mdss_ad_info *ad; + + if (!mfd) { + pr_err("mfd = 0x%p\n", mfd); + return -EINVAL; + } + + ret = mdss_mdp_get_ad(mfd, &ad); + if (ret == -ENODEV || ret == -EPERM) { + pr_debug("AD not supported on device, disp num %d\n", + mfd->index); + return 0; + } else if (ret || !ad) { + pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + ret, ad); + return ret; + } + + mutex_lock(&ad->lock); + if (ad->state & PP_AD_STATE_RUN && ad->state & PP_AD_STATE_IPC_RESET) + ad->state &= ~PP_AD_STATE_IPC_RESET; + mutex_unlock(&ad->lock); + + return 0; +} + static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) { int ret = 0; @@ -5602,33 +5708,46 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) mdata = mdss_mdp_get_mdata(); mutex_lock(&ad->lock); + if (ad->state & PP_AD_STATE_RUN && ad->state & PP_AD_STATE_IPC_RESUME) { + if (ad->ipc_frame_count == MDSS_AD_IPC_FRAME_COUNT) { + ad->state &= ~PP_AD_STATE_IPC_RESUME; + ad->state |= PP_AD_STATE_IPC_RESET; + ad->cfg.mode &= ~MDSS_AD_MODE_IPC_BIT; + if (ad->last_ad_data != ad->ad_data) + ad->sts |= PP_AD_STS_DIRTY_DATA; + if (memcmp(ad->last_calib, ad->cfg.calib, + sizeof(ad->last_calib))) + ad->sts |= PP_AD_STS_DIRTY_CFG; + pr_debug("switch mode to %d, last_ad_data = %d\n", + ad->cfg.mode, ad->last_ad_data); + } else { + ad->ipc_frame_count++; + } + } + if (ad->sts != last_sts || ad->state != last_state) { last_sts = ad->sts; last_state = ad->state; pr_debug("begining: ad->sts = 0x%08x, state = 0x%08x\n", ad->sts, ad->state); } - if (!PP_AD_STS_IS_DIRTY(ad->sts) && - (ad->sts & PP_AD_STS_DIRTY_DATA)) { - /* - * Write inputs to regs when the data has been updated or - * Assertive Display is up and running as long as there are - * no updates to AD init or cfg - */ + + if (ad->sts & PP_AD_STS_DIRTY_DATA) { ad->sts &= ~PP_AD_STS_DIRTY_DATA; ad->state |= PP_AD_STATE_DATA; pr_debug("dirty data, last_bl = %d\n", ad->last_bl); bl = bl_mfd->ad_bl_level; - if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && - (ad->last_bl != bl)) { + if (ad->last_bl != bl) { ad->last_bl = bl; linear_map(bl, &ad->bl_data, bl_mfd->panel_info->bl_max, MDSS_MDP_AD_BL_SCALE); } - ad->calc_itr = ad->cfg.stab_itr; - ad->sts |= PP_AD_STS_DIRTY_VSYNC; + if (!(ad->state & PP_AD_STATE_IPC_RESUME)) { + ad->calc_itr = ad->cfg.stab_itr; + ad->sts |= PP_AD_STS_DIRTY_VSYNC; + } ad->reg_sts |= PP_AD_STS_DIRTY_DATA; } @@ -5637,12 +5756,6 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) ad->state |= PP_AD_STATE_CFG; ad->reg_sts |= PP_AD_STS_DIRTY_CFG; - - if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, ad->ad_data_mode)) { - ad->sts &= ~PP_AD_STS_DIRTY_DATA; - ad->state &= ~PP_AD_STATE_DATA; - pr_debug("Mode switched, data invalidated!\n"); - } } if (ad->sts & PP_AD_STS_DIRTY_INIT) { ad->sts &= ~PP_AD_STS_DIRTY_INIT; @@ -5688,11 +5801,18 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) ad->state &= ~PP_AD_STATE_CFG; ad->state &= ~PP_AD_STATE_DATA; ad->state &= ~PP_AD_STATE_BL_LIN; + ad->state &= ~PP_AD_STATE_IPC_RESUME; + ad->state &= ~PP_AD_STATE_IPC_RESET; ad->ad_data = 0; ad->ad_data_mode = 0; ad->last_bl = 0; + ad->last_ad_data = 0; + ad->last_calib_valid = false; + ad->last_ad_data_valid = false; + ad->ipc_frame_count = 0; ad->calc_itr = 0; ad->calc_hw_num = PP_AD_BAD_HW_NUM; + memset(&ad->last_calib, 0, sizeof(ad->last_calib)); memset(&ad->bl_lin, 0, sizeof(uint32_t) * AD_BL_LIN_LEN); memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) * @@ -5777,12 +5897,11 @@ static void pp_ad_calc_worker(struct work_struct *work) if ((PP_AD_STATE_RUN & ad->state) && ad->calc_itr > 0) ad->calc_itr--; - if (mdata->ad_debugen) { - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - pr_info("itr number %d str %d\n", ad->calc_itr, - readl_relaxed(base + MDSS_MDP_REG_AD_STR_OUT)); - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); - } + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + ad->last_str = 0xFF & readl_relaxed(base + MDSS_MDP_REG_AD_STR_OUT); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); + if (mdata->ad_debugen) + pr_debug("itr number %d str %d\n", ad->calc_itr, ad->last_str); mdp5_data->ad_events++; sysfs_notify_dirent(mdp5_data->ad_event_sd); if (!ad->calc_itr) { @@ -5952,6 +6071,11 @@ int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets) mdata->ad_cfgs[i].calc_itr = 0; mdata->ad_cfgs[i].last_str = 0xFFFFFFFF; mdata->ad_cfgs[i].last_bl = 0; + mdata->ad_cfgs[i].last_ad_data = 0; + memset(mdata->ad_cfgs[i].last_calib, 0, + sizeof(mdata->ad_cfgs[i].last_calib)); + mdata->ad_cfgs[i].last_calib_valid = false; + mdata->ad_cfgs[i].last_ad_data_valid = false; mutex_init(&mdata->ad_cfgs[i].lock); mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler; mdata->ad_cfgs[i].handle.cmd_post_flush = true; |
