diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-18 01:54:47 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-11-18 01:54:46 -0800 |
commit | db18e6f95ecf8e086edd1347553b8438cd95b078 (patch) | |
tree | fda5e28f116a3e09ef772177e0546c29d88e6965 /drivers | |
parent | 07d79c74098a99fe2f8a552e12af4206b4b7c898 (diff) | |
parent | 5d2b103d523f4651e9f7101d003ba1377f699206 (diff) |
Merge "msm: mdss: fix race condition in dsi clk off request"
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 3 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_clk.c | 27 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_clk.h | 15 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_host.c | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_layer.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/msm_mdss_io_8974.c | 52 |
7 files changed, 84 insertions, 27 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/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index c9168242da60..5f8b45413e32 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2811,12 +2811,6 @@ static int dsi_event_thread(void *data) pr_debug("%s: Handling underflow event\n", __func__); __dsi_fifo_error_handler(ctrl, true); - } else { - pr_err("%s: ctrl recovery not defined\n", - __func__); - MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", - "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", - "vbif_nrt", "dbg_bus", "vbif_dbg_bus", "panic"); } mutex_unlock(&ctrl->mutex); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 036e4e39efda..73350b3a5a6f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -852,7 +852,7 @@ static int __validate_layer_reconfig(struct mdp_input_layer *layer, */ if (pipe->csc_coeff_set != layer->color_space) { src_fmt = mdss_mdp_get_format_params(layer->buffer.format); - if (pipe->src_fmt->is_yuv && src_fmt->is_yuv) { + if (pipe->src_fmt->is_yuv && src_fmt && src_fmt->is_yuv) { status = -EPERM; pr_err("csc change is not permitted on used pipe\n"); } 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: |