summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h7
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c180
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;