aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngrid Gallardo <ingridg@codeaurora.org>2017-03-09 14:14:54 +0900
committerDevin Kim <dojip.kim@lge.com>2017-03-14 09:48:31 -0700
commita033d772d1900b7e0da3d943ba9d02b773f0c53c (patch)
tree63f93ab6df007dfa65e2a39ab5d73c5c60291a76
parent35dba3c7b3e25a994a3ceb5949d8f0dd5216f835 (diff)
msm: mdss: fix race conditions when enabling mdp clocksandroid-wear-7.1.1_r0.15
During the early wakeup event for command mode panels the enable of power, clocks and restore of the controllers status happen in a different thread context. This can cause a race condition with multiple threads that also try to enable the power resources and assume that the status of the controllers has been restored. Prevent race condition for multiple threads trying to enable the resources, by making sure that the complete power on, clocks and restore of the controllers happen before return from the first call to enable the clocks. This fixes random ping pong timeouts observed due above described race conditions. Bug: 35217359 Change-Id: Ie3607797994a5d4f533c4d4838718b0229e32dc6 Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org> Signed-off-by: guilbert.lee <guilbert.lee@lge.com> Signed-off-by: Devin Kim <dojip.kim@lge.com>
-rw-r--r--drivers/video/msm/mdss/mdss_mdp.c37
-rw-r--r--drivers/video/msm/mdss/mdss_mdp.h8
-rw-r--r--drivers/video/msm/mdss/mdss_mdp_ctl.c13
-rw-r--r--drivers/video/msm/mdss/mdss_mdp_intf_cmd.c27
-rw-r--r--drivers/video/msm/mdss/mdss_mdp_overlay.c2
5 files changed, 52 insertions, 35 deletions
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index c573925f448e..c0b592e500db 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -691,16 +691,22 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
return ret;
}
-int mdss_mdp_vsync_clk_enable(int enable)
+int mdss_mdp_vsync_clk_enable(int enable, bool locked)
{
int ret = 0;
pr_debug("clk enable=%d\n", enable);
- mutex_lock(&mdp_clk_lock);
+
+ if (!locked)
+ mutex_lock(&mdp_clk_lock);
+
if (mdss_res->vsync_ena != enable) {
mdss_res->vsync_ena = enable;
ret = mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
}
- mutex_unlock(&mdp_clk_lock);
+
+ if (!locked)
+ mutex_unlock(&mdp_clk_lock);
+
return ret;
}
@@ -733,14 +739,19 @@ void mdss_mdp_set_clk_rate(unsigned long rate)
}
}
-unsigned long mdss_mdp_get_clk_rate(u32 clk_idx)
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked)
{
unsigned long clk_rate = 0;
struct clk *clk = mdss_mdp_get_clk(clk_idx);
- mutex_lock(&mdp_clk_lock);
- if (clk)
+ if (clk) {
+ if (!locked)
+ mutex_lock(&mdp_clk_lock);
+
clk_rate = clk_get_rate(clk);
- mutex_unlock(&mdp_clk_lock);
+
+ if (!locked)
+ mutex_unlock(&mdp_clk_lock);
+ }
return clk_rate;
}
@@ -806,7 +817,7 @@ static int mdss_mdp_idle_pc_restore(void)
}
mdss_hw_init(mdata);
mdss_iommu_ctrl(0);
- mdss_mdp_ctl_restore();
+ mdss_mdp_ctl_restore(true);
mdata->idle_pc = false;
end:
@@ -907,10 +918,10 @@ void mdss_mdp_clk_ctrl(int enable)
}
}
- mutex_unlock(&mdp_clk_lock);
-
if (enable && changed)
mdss_mdp_idle_pc_restore();
+
+ mutex_unlock(&mdp_clk_lock);
}
static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
@@ -984,7 +995,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
mdss_mdp_irq_clk_register(mdata, "vsync_clk", MDSS_CLK_MDP_VSYNC);
mdss_mdp_set_clk_rate(MDP_CLK_DEFAULT_RATE);
- pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC));
+ pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC, false));
return 0;
}
@@ -1150,11 +1161,9 @@ static void mdss_hw_rev_init(struct mdss_data_type *mdata)
if (mdata->mdp_rev)
return;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
mdata->mdp_rev = MDSS_REG_READ(mdata, MDSS_REG_HW_VERSION);
pr_info_once("MDP Rev=%x\n", mdata->mdp_rev);
mdss_mdp_hw_rev_caps_init(mdata);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}
/**
@@ -1420,7 +1429,9 @@ static ssize_t mdss_mdp_show_capabilities(struct device *dev,
#define SPRINT(fmt, ...) \
(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
mdss_hw_rev_init(mdata);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
SPRINT("mdp_version=5\n");
SPRINT("hw_rev=%d\n", mdata->mdp_rev);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 63a388061531..9b10121df4b1 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -228,7 +228,7 @@ struct mdss_mdp_ctl {
struct mdss_mdp_vsync_handler *);
int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl,
struct mdss_mdp_ctl *sctl, int new_fps);
- int (*restore_fnc) (struct mdss_mdp_ctl *ctl);
+ int (*restore_fnc)(struct mdss_mdp_ctl *ctl, bool locked);
struct blocking_notifier_head notifier_head;
@@ -701,8 +701,8 @@ void mdss_mdp_footswitch_ctrl_splash(int on);
void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
-unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
-int mdss_mdp_vsync_clk_enable(int enable);
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked);
+int mdss_mdp_vsync_clk_enable(int enable, bool locked);
void mdss_mdp_clk_ctrl(int enable);
struct mdss_data_type *mdss_mdp_get_mdata(void);
int mdss_mdp_secure_display_ctrl(unsigned int enable);
@@ -916,6 +916,6 @@ int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
-void mdss_mdp_ctl_restore(void);
+void mdss_mdp_ctl_restore(bool locked);
int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl);
#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 52910d45c9c4..c5af3d79aba6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1995,19 +1995,25 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
/*
* mdss_mdp_ctl_restore() - restore mdp ctl path
+ * @locked - boolean to signal that clock lock is already acquired
*
* This function is called whenever MDP comes out of a power collapse as
* a result of a screen update. It restores the MDP controller's software
* state to the hardware registers.
+ * Function does not enable the clocks, so caller must make sure
+ * clocks are enabled before calling.
+ * The locked boolean in the parametrs signals that synchronization
+ * with mdp clocks access is not required downstream.
+ * Only call this function setting this value to true if the clocks access
+ * synchronization is guaranteed by the caller.
*/
-void mdss_mdp_ctl_restore(void)
+void mdss_mdp_ctl_restore(bool locked)
{
struct mdss_mdp_ctl *ctl = NULL;
struct mdss_mdp_ctl *sctl;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 cnum;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
for (cnum = MDSS_MDP_CTL0; cnum < mdata->nctl; cnum++) {
ctl = mdata->ctl_off + cnum;
if (!mdss_mdp_ctl_is_power_on(ctl))
@@ -2023,9 +2029,8 @@ void mdss_mdp_ctl_restore(void)
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
}
if (ctl->restore_fnc)
- ctl->restore_fnc(ctl);
+ ctl->restore_fnc(ctl, locked);
}
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}
static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index cde188301ba6..3a58049b6004 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -113,7 +113,7 @@ exit:
static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_mixer *mixer, bool enable)
+ struct mdss_mdp_mixer *mixer, bool enable, bool locked)
{
struct mdss_mdp_pp_tear_check *te = NULL;
struct mdss_panel_info *pinfo;
@@ -130,10 +130,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
pinfo = &ctl->panel_data->panel_info;
te = &ctl->panel_data->panel_info.te;
- mdss_mdp_vsync_clk_enable(1);
+ mdss_mdp_vsync_clk_enable(1, locked);
vsync_clk_speed_hz =
- mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+ mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC, locked);
total_lines = mdss_panel_get_vtotal(pinfo);
@@ -193,14 +193,15 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
return 0;
}
-static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, bool enable)
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, bool enable,
+ bool locked)
{
int rc = 0;
struct mdss_mdp_mixer *mixer;
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
if (mixer) {
- rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable);
+ rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable, locked);
if (rc)
goto err;
}
@@ -208,7 +209,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, bool enable)
if (!(ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE)) {
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
if (mixer)
- rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable);
+ rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable, locked);
}
err:
return rc;
@@ -793,13 +794,11 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
return 0;
}
-int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl, bool locked)
{
pr_debug("%s: called for ctl%d\n", __func__, ctl->num);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
- if (mdss_mdp_cmd_tearcheck_setup(ctl, true))
+ if (mdss_mdp_cmd_tearcheck_setup(ctl, true, locked))
pr_warn("%s: tearcheck setup failed\n", __func__);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
return 0;
}
@@ -867,7 +866,7 @@ int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
mdss_mdp_cmd_clk_off(ctx);
flush_work(&ctx->pp_done_work);
- mdss_mdp_cmd_tearcheck_setup(ctl, false);
+ mdss_mdp_cmd_tearcheck_setup(ctl, false, false);
if (mdss_panel_is_power_on(panel_power_state)) {
pr_debug("%s: intf stopped with panel on\n", __func__);
@@ -1047,7 +1046,9 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
* explictly call the restore function to enable
* tearcheck logic.
*/
- mdss_mdp_cmd_restore(ctl);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ mdss_mdp_cmd_restore(ctl, false);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
/* Turn on panel so that it can exit low power mode */
ret = mdss_mdp_cmd_panel_on(ctl, sctl);
@@ -1099,7 +1100,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
mdss_mdp_cmd_pingpong_done, ctl);
- ret = mdss_mdp_cmd_tearcheck_setup(ctl, true);
+ ret = mdss_mdp_cmd_tearcheck_setup(ctl, true, true);
if (ret) {
pr_err("tearcheck setup failed\n");
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index e3f2790d4d63..c97bba2f421e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -3621,7 +3621,7 @@ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd)
goto error;
}
- ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
+ ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC, false);
pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
rc = __mdss_mdp_ctl_handoff(ctl, mdata);