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

Commit 331cdb45 authored by Sandeep Panda's avatar Sandeep Panda
Browse files

drm/msm/dsi-staging: fix dsi underflow errors during clock switch



Currently in dsi driver, for command mode panels the dsi bit clock
can be changed via sysfs node. This creates a race condition where
at the same time sysfs update was triggered and a commit was triggered
to come out of idle screen. When this scenario occurs then dsi might
go into bad state and throw FIFO errors, if one of the dsi clock got
enabled with old rate as part of the commit and the other dsi clock
got enabled with new rate triggered from sysfs node. Fix this race
condition by making clock update and sysfs node write mutually exclusive.

Change-Id: I7c361ccccc9ce7bdac8d46ecb892ae5f5c7c98e2
Signed-off-by: default avatarSandeep Panda <spanda@codeaurora.org>
parent c543b1e1
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -261,13 +261,13 @@ void *dsi_register_clk_handle(void *clk_mngr, char *client);
int dsi_deregister_clk_handle(void *client);

/**
 * dsi_display_link_clk_force_update_ctrl() - force to set link clks
 * dsi_display_link_clk_force_update() - force to set link clks
 * @handle:     Handle of desired DSI clock client.
 *
 * return: error code in case of failure or 0 for success.
 */

int dsi_display_link_clk_force_update_ctrl(void *handle);
int dsi_display_link_clk_force_update(void *handle);

/**
 * dsi_display_clk_ctrl() - set frequencies for link clks
@@ -332,4 +332,14 @@ int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk);
 * @clk:       list of src clocks.
 */
void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk);

/**
 * dsi_clk_req_state() - request to change dsi clock state
 * @client:       DSI clocl client pointer.
 * @clk:          DSI clock list.
 * @state:        Requested state of the clock.
 */
int dsi_clk_req_state(void *client, enum dsi_clk_type clk,
	enum dsi_clk_state state);

#endif /* _DSI_CLK_H_ */
+1 −40
Original line number Diff line number Diff line
@@ -1255,9 +1255,7 @@ int dsi_clk_req_state(void *client, enum dsi_clk_type clk,
	return rc;
}

DEFINE_MUTEX(dsi_mngr_clk_mutex);

static int dsi_display_link_clk_force_update(void *client)
int dsi_display_link_clk_force_update(void *client)
{
	int rc = 0;
	struct dsi_clk_client_info *c = client;
@@ -1304,43 +1302,6 @@ static int dsi_display_link_clk_force_update(void *client)

}

int dsi_display_link_clk_force_update_ctrl(void *handle)
{
	int rc = 0;

	if (!handle) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&dsi_mngr_clk_mutex);

	rc = dsi_display_link_clk_force_update(handle);

	mutex_unlock(&dsi_mngr_clk_mutex);

	return rc;
}

int dsi_display_clk_ctrl(void *handle,
	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
{
	int rc = 0;

	if (!handle) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&dsi_mngr_clk_mutex);
	rc = dsi_clk_req_state(handle, clk_type, clk_state);
	if (rc)
		pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
	mutex_unlock(&dsi_mngr_clk_mutex);

	return rc;
}

void *dsi_register_clk_handle(void *clk_mngr, char *client)
{
	void *handle = NULL;
+42 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@
#define DSI_CLOCK_BITRATE_RADIX 10
#define MAX_TE_SOURCE_ID  2

DEFINE_MUTEX(dsi_display_clk_mutex);

static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY] = {
@@ -4571,6 +4573,43 @@ int dsi_display_splash_res_cleanup(struct dsi_display *display)
	return rc;
}

static int dsi_display_link_clk_force_update_ctrl(void *handle)
{
	int rc = 0;

	if (!handle) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&dsi_display_clk_mutex);

	rc = dsi_display_link_clk_force_update(handle);

	mutex_unlock(&dsi_display_clk_mutex);

	return rc;
}

int dsi_display_clk_ctrl(void *handle,
	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
{
	int rc = 0;

	if (!handle) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&dsi_display_clk_mutex);
	rc = dsi_clk_req_state(handle, clk_type, clk_state);
	if (rc)
		pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
	mutex_unlock(&dsi_display_clk_mutex);

	return rc;
}

static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
{
	int rc = 0;
@@ -4659,6 +4698,7 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,

	mutex_lock(&display->display_lock);

	mutex_lock(&dsi_display_clk_mutex);
	display->cached_clk_rate = clk_rate;
	rc = dsi_display_update_dsi_bitrate(display, clk_rate);
	if (!rc) {
@@ -4671,12 +4711,14 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,
		atomic_set(&display->clkrate_change_pending, 0);
		display->cached_clk_rate = 0;

		mutex_unlock(&dsi_display_clk_mutex);
		mutex_unlock(&display->display_lock);

		return rc;
	}
	atomic_set(&display->clkrate_change_pending, 1);

	mutex_unlock(&dsi_display_clk_mutex);
	mutex_unlock(&display->display_lock);

	return count;