summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDhaval Patel <pdhaval@codeaurora.org>2016-04-15 14:18:47 -0700
committerHarsh Sahu <hsahu@codeaurora.org>2016-11-11 12:07:14 -0800
commit5d2b103d523f4651e9f7101d003ba1377f699206 (patch)
tree28f67bfcda0a18d6431055e91be8f234a5e9521d /drivers
parente2ef952c4e59f40ed17c9a89a814980668c77366 (diff)
msm: mdss: fix race condition in dsi clk off request
DSI clocks are requested from mdp and dsi for different use cases. The master clocks(DSI0 clocks) are refcounted to avoid toggling during slave clock ON/OFF sequence. Same applies to split controller clocks if broadcast mode is enabled. Now, mdp client can remove the dsi client's vote in below case: - MDP requested clocks in ECG state - clk_ctrl has removed both votes from ctrl-0 using dsi client handler. - DSI turns ON clock for ctrl-1 - clk_ctrl turns on clk for ctrl-0 using dsi client handler. - clk_ctrl increase the ctrl-1 refcount to 1 - clk_ctrl turns on clk for ctrl-1 - MDP request to turn OFF the clk for ctrl-1 - clk_ctrl turns on clk for ctrl-0 using dsi client handler - clk_ctrl increase the ctrl-1 refcount to 2 - clk_ctrl turns off clk for ctrl-1 - clk_ctrl turns off clk(twice) for ctrl-0 using dsi client handler. This race condition leads to dsi0 clocks off event when interface is using clocks. This change start tracking extra vote based on calling client id. Change-Id: I4812330453dedacd16dad1d920a2bacc3f67042b Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_clk.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_clk.h15
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c52
5 files changed, 83 insertions, 20 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index cf7a398c13ce..8dccab8a81be 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2985,6 +2985,12 @@ static int mdss_dsi_cont_splash_config(struct mdss_panel_info *pinfo,
mdss_dsi_panel_pwm_enable(ctrl_pdata);
ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT |
CTRL_STATE_MDP_ACTIVE | CTRL_STATE_DSI_ACTIVE);
+
+ /*
+ * MDP client removes this extra vote during splash reconfigure
+ * for command mode panel from interface. DSI removes the vote
+ * during suspend-resume for video mode panel.
+ */
if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL)
clk_handle = ctrl_pdata->mdp_clk_handle;
else
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 3536cb2d294d..3a347681f434 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -557,7 +557,8 @@ struct mdss_dsi_ctrl_pdata {
void *clk_mngr;
void *dsi_clk_handle;
void *mdp_clk_handle;
- int m_vote_cnt;
+ int m_dsi_vote_cnt;
+ int m_mdp_vote_cnt;
/* debugfs structure */
struct mdss_dsi_debugfs_info *debugfs_info;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.c b/drivers/video/fbdev/msm/mdss_dsi_clk.c
index a7d1c251fab0..755d6092ea11 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_clk.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_clk.c
@@ -795,8 +795,29 @@ error:
return rc;
}
+bool is_dsi_clk_in_ecg_state(void *client)
+{
+ struct mdss_dsi_clk_client_info *c = client;
+ struct mdss_dsi_clk_mngr *mngr;
+ bool is_ecg = false;
+
+ if (!client) {
+ pr_err("Invalid client params\n");
+ goto end;
+ }
+
+ mngr = c->mngr;
+
+ mutex_lock(&mngr->clk_mutex);
+ is_ecg = (c->core_clk_state == MDSS_DSI_CLK_EARLY_GATE);
+ mutex_unlock(&mngr->clk_mutex);
+
+end:
+ return is_ecg;
+}
+
int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
- enum mdss_dsi_clk_state state)
+ enum mdss_dsi_clk_state state, u32 index)
{
int rc = 0;
struct mdss_dsi_clk_client_info *c = client;
@@ -817,7 +838,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
c->name, mngr->name, clk, state, c->core_clk_state,
c->link_clk_state);
- MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state);
+ MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
/*
* Refcount handling rules:
* 1. Increment refcount whenever ON is called
@@ -883,7 +904,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n",
c->name, mngr->name, changed, c->core_refcount,
c->core_clk_state, c->link_refcount, c->link_clk_state);
- MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state);
+ MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
if (changed) {
rc = dsi_recheck_clk_state(mngr);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.h b/drivers/video/fbdev/msm/mdss_dsi_clk.h
index 9fe45254fe6d..0b88ddb57166 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_clk.h
+++ b/drivers/video/fbdev/msm/mdss_dsi_clk.h
@@ -197,6 +197,7 @@ int mdss_dsi_clk_deregister(void *client);
* @client: client handle.
* @clk: Type of clock requested (enum mdss_dsi_clk_type).
* @state: clock state requested.
+ * @index: controller index.
*
* This routine is used to request a new clock state for a specific clock. If
* turning ON the clocks, this guarantees that clocks will be on before
@@ -206,7 +207,7 @@ int mdss_dsi_clk_deregister(void *client);
* @return: error code.
*/
int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
- enum mdss_dsi_clk_state state);
+ enum mdss_dsi_clk_state state, u32 index);
/**
* mdss_dsi_clk_set_link_rate() - set clock rate for link clocks
@@ -238,4 +239,16 @@ int mdss_dsi_clk_set_link_rate(void *client, enum mdss_dsi_link_clk_type clk,
* @return:error code.
*/
int mdss_dsi_clk_force_toggle(void *client, u32 clk);
+
+/**
+ * is_dsi_clk_in_ecg_state() - Checks the current state of clocks
+ * @client: client handle.
+ *
+ * This routine returns checks the clocks status for client and return
+ * success code based on it.
+ *
+ * @return:true: if clocks are in ECG state
+ * false: for all other cases
+ */
+bool is_dsi_clk_in_ecg_state(void *client);
#endif /* _MDSS_DSI_CLK_H_ */
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index b5b5a026733e..0c43a2642ede 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -2081,7 +2081,11 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
{
int rc = 0;
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- int i;
+ int i, *vote_cnt;
+
+ void *m_clk_handle;
+ bool is_ecg = false;
+ int state = MDSS_DSI_CLK_OFF;
if (!ctrl) {
pr_err("%s: Invalid arg\n", __func__);
@@ -2113,6 +2117,18 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
}
/*
+ * it should add and remove extra votes based on voting clients to avoid
+ * removal of legitimate vote from DSI client.
+ */
+ if (mctrl && (clk_handle == ctrl->dsi_clk_handle)) {
+ m_clk_handle = mctrl->dsi_clk_handle;
+ vote_cnt = &mctrl->m_dsi_vote_cnt;
+ } else if (mctrl) {
+ m_clk_handle = mctrl->mdp_clk_handle;
+ vote_cnt = &mctrl->m_mdp_vote_cnt;
+ }
+
+ /*
* When DSI is used in split mode, the link clock for master controller
* has to be turned on first before the link clock for slave can be
* turned on. In case the current controller is a slave, an ON vote is
@@ -2124,18 +2140,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
__func__, ctrl->ndx, clk_type, clk_state,
__builtin_return_address(0), mctrl ? 1 : 0);
if (mctrl && (clk_type & MDSS_DSI_LINK_CLK)) {
- rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle,
- MDSS_DSI_ALL_CLKS,
- MDSS_DSI_CLK_ON);
+ if (clk_state != MDSS_DSI_CLK_ON) {
+ /* preserve clk state; do not turn off forcefully */
+ is_ecg = is_dsi_clk_in_ecg_state(m_clk_handle);
+ if (is_ecg)
+ state = MDSS_DSI_CLK_EARLY_GATE;
+ }
+
+ rc = mdss_dsi_clk_req_state(m_clk_handle,
+ MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON, mctrl->ndx);
if (rc) {
pr_err("%s: failed to turn on mctrl clocks, rc=%d\n",
__func__, rc);
goto error;
}
- ctrl->m_vote_cnt++;
+ (*vote_cnt)++;
}
- rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state);
+ rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state, ctrl->ndx);
if (rc) {
pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
goto error;
@@ -2164,24 +2186,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
* for ON, since the previous ECG state must have
* removed two votes to let clocks turn off.
*
- * To satisfy the above requirement, m_vote_cnt keeps track of
+ * To satisfy the above requirement, vote_cnt keeps track of
* the number of ON votes for master requested by slave. For
- * every OFF/ECG state request, Either 2 or m_vote_cnt number of
+ * every OFF/ECG state request, Either 2 or vote_cnt number of
* votes are removed depending on which is lower.
*/
- for (i = 0; (i < ctrl->m_vote_cnt && i < 2); i++) {
- rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle,
- MDSS_DSI_ALL_CLKS,
- MDSS_DSI_CLK_OFF);
+ for (i = 0; (i < *vote_cnt && i < 2); i++) {
+ rc = mdss_dsi_clk_req_state(m_clk_handle,
+ MDSS_DSI_ALL_CLKS, state, mctrl->ndx);
if (rc) {
pr_err("%s: failed to set mctrl clk state, rc = %d\n",
__func__, rc);
goto error;
}
}
- ctrl->m_vote_cnt -= i;
- pr_debug("%s: ctrl=%d, m_vote_cnt=%d\n", __func__, ctrl->ndx,
- ctrl->m_vote_cnt);
+ (*vote_cnt) -= i;
+ pr_debug("%s: ctrl=%d, vote_cnt=%d dsi_vote_cnt=%d mdp_vote_cnt:%d\n",
+ __func__, ctrl->ndx, *vote_cnt, mctrl->m_dsi_vote_cnt,
+ mctrl->m_mdp_vote_cnt);
}
error: