msm: mdss: Flush changes to post processing immediately
Current post processing changes wait for a display update to write its data
to registers. Trigger post processing configuration at time of update so
that the updated features will be updated at next vsync. Needed by
destination side post processing features in particular since their updates
are made independently of display updates and effect objective display
quality.
Change-Id: Ib5a2b4c33e45bece74dea2d8e17b5c3d239206b8
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 79115d8..ce82200 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1439,32 +1439,32 @@
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
- ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
+ ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
©back);
break;
case mdp_op_pcc_cfg:
- ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+ ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
©back);
break;
case mdp_op_lut_cfg:
switch (mdp_pp.data.lut_cfg_data.lut_type) {
case mdp_lut_igc:
- ret = mdss_mdp_igc_lut_config(
+ ret = mdss_mdp_igc_lut_config(mfd->ctl,
(struct mdp_igc_lut_data *)
&mdp_pp.data.lut_cfg_data.data,
©back);
break;
case mdp_lut_pgc:
- ret = mdss_mdp_argc_config(
+ ret = mdss_mdp_argc_config(mfd->ctl,
&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
©back);
break;
case mdp_lut_hist:
- ret = mdss_mdp_hist_lut_config(
+ ret = mdss_mdp_hist_lut_config(mfd->ctl,
(struct mdp_hist_lut_data *)
&mdp_pp.data.lut_cfg_data.data, ©back);
break;
@@ -1475,12 +1475,12 @@
}
break;
case mdp_op_dither_cfg:
- ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
- ©back);
+ ret = mdss_mdp_dither_config(mfd->ctl,
+ &mdp_pp.data.dither_cfg_data, ©back);
break;
case mdp_op_gamut_cfg:
- ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
- ©back);
+ ret = mdss_mdp_gamut_config(mfd->ctl,
+ &mdp_pp.data.gamut_cfg_data, ©back);
break;
case mdp_bl_scale_cfg:
ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
@@ -1666,7 +1666,7 @@
if (ret)
return ret;
- ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+ ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
if ((ret == 0) && hist_data_addr) {
ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
sizeof(u32) * hist.bin_cnt);
@@ -1684,7 +1684,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_start(&hist_req);
+ ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
@@ -1692,7 +1692,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_stop(block);
+ ret = mdss_mdp_histogram_stop(mfd->ctl, block);
break;
case MSMFB_GET_PAGE_PROTECTION:
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index cc7ccd3..e85246f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2012-2013, 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
@@ -345,6 +346,7 @@
int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
+
int mdss_mdp_pp_resume(u32 mixer_num);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
@@ -353,18 +355,34 @@
int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pa_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *cfg_ptr,
+ u32 *copyback);
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback);
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr);
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block);
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr);
void mdss_mdp_hist_intr_done(u32 isr);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b528d1c..6b1388e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -571,7 +571,7 @@
ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB888;
break;
}
- mdss_mdp_dither_config(&dither, NULL);
+ mdss_mdp_dither_config(ctl, &dither, NULL);
}
return ctl;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 2320e76..298d2b9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -610,15 +610,21 @@
struct pp_sts_type *pp_sts;
u32 data, col_state;
unsigned long flag;
- int i;
+ int i, ret = 0;
+
+ if (!mixer || !ctl)
+ return -EINVAL;
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
- return 0;
+ return -EINVAL;
base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
if (hist_info->col_en) {
/* HIST_EN & AUTO_CLEAR */
opmode |= (1 << 16) | (1 << 17);
@@ -634,7 +640,6 @@
MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
hist_info->col_state = HIST_START;
}
- hist_info->is_kick_ready = true;
spin_unlock_irqrestore(&mdss_hist_lock, flag);
mutex_unlock(&mdss_mdp_hist_mutex);
}
@@ -646,7 +651,7 @@
/* nothing to update */
if ((!flags) && (!(hist_info->col_en)))
- return 0;
+ goto dspp_exit;
pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
@@ -734,8 +739,11 @@
opmode |= (1 << 22);
MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
- ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
- return 0;
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
+ wmb();
+dspp_exit:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
}
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
@@ -925,11 +933,15 @@
return 0;
}
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl, struct mdp_pa_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 pa_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -963,6 +975,8 @@
pa_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
@@ -1092,11 +1106,16 @@
MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
}
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 base, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1126,8 +1145,9 @@
pcc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
-
}
static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
@@ -1184,12 +1204,17 @@
MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
}
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
struct mdp_igc_lut_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1251,6 +1276,8 @@
igc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_update_gc_one_lut(u32 offset,
@@ -1348,7 +1375,9 @@
MDSS_MDP_REG_WRITE(offset + 4, 1);
}
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 argc_offset = 0, disp_num, dspp_num = 0;
@@ -1356,6 +1385,9 @@
struct mdp_pgc_lut_data *pgc_ptr;
u32 tbl_size;
+ if (!ctl)
+ return -EINVAL;
+
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1445,13 +1477,20 @@
}
argc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback)
{
int i, ret = 0;
u32 hist_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1494,12 +1533,19 @@
}
enhist_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback)
{
u32 disp_num;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1511,16 +1557,22 @@
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
mutex_unlock(&mdss_pp_mutex);
+ mdss_mdp_pp_setup(ctl);
return 0;
}
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback)
{
int i, j, size_total = 0, ret = 0;
u32 offset, disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1598,6 +1650,8 @@
}
gamut_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
@@ -1614,7 +1668,8 @@
hist_info->hist_cnt_read++;
}
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req)
{
u32 ctl_base, done_shift_bit;
struct pp_hist_col_info *hist_info;
@@ -1623,6 +1678,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(req->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1680,10 +1738,24 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_start_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret) {
+ mdss_mdp_pp_setup(ctl);
+ /* wait for a frame to let histrogram enable itself */
+ usleep(41666);
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ mutex_lock(&mdss_mdp_hist_mutex);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ hist_info->is_kick_ready = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ }
+ }
return ret;
}
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
{
int i, ret = 0;
u32 dspp_num, disp_num, ctl_base, done_bit;
@@ -1691,6 +1763,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
(block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1737,11 +1812,14 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_stop_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr)
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr)
{
int i, j, wait_ret, ret = 0;
u32 timeout, v_base;
@@ -1750,6 +1828,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(hist->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1788,6 +1869,8 @@
spin_unlock_irqrestore(&mdss_hist_lock, flag);
timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
mutex_unlock(&mdss_mdp_hist_mutex);
+ /* flush updates before wait*/
+ mdss_mdp_pp_setup(ctl);
wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
@@ -1817,8 +1900,8 @@
}
if (hist_info->col_state != HIST_READY) {
ret = -ENODATA;
- pr_debug("%s: collection state is not ready: %d",
- __func__, hist_info->col_state);
+ pr_debug("%s: state is not ready: %d",
+ __func__, hist_info->col_state);
goto hist_collect_exit;
}
} else {