Merge "msm: mdss: fix race condition in dsi clk off request"
This commit is contained in:
commit
db18e6f95e
7 changed files with 84 additions and 27 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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__);
|
||||
|
@ -2112,6 +2116,18 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
|
|||
__func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue