Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eccb5991 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: fix race condition in dsi clk off request"

parents 7b2ba845 79805d69
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2892,6 +2892,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
+2 −1
Original line number Diff line number Diff line
@@ -523,7 +523,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;

+25 −3
Original line number Diff line number Diff line
@@ -722,8 +722,30 @@ 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;
@@ -744,7 +766,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
@@ -810,7 +832,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);
+15 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, 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
@@ -194,6 +194,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
@@ -203,7 +204,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
@@ -235,4 +236,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_ */
+37 −15
Original line number Diff line number Diff line
@@ -1945,7 +1945,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__);
@@ -1976,6 +1980,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
@@ -1988,18 +2004,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;
@@ -2028,24 +2050,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: