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

Commit c449fd9e authored by Aravind Venkateswaran's avatar Aravind Venkateswaran Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/dsi-staging: separate link HS and LP clocks



Separate DSI high speed (HS) clocks from low power (LP) clock, so that
we can have better control in enabling and disabling these clocks
independently. Some DSI hardware versions need LP clocks to be turned on
before programming DSI PHY.

Change-Id: I05efde2bb2a7f737e2f952554b41e3ab74e990e5
Signed-off-by: default avatarAravind Venkateswaran <aravindh@codeaurora.org>
parent 21aa8ba1
Loading
Loading
Loading
Loading
+44 −15
Original line number Diff line number Diff line
@@ -43,6 +43,13 @@ enum dsi_link_clk_type {
	DSI_LINK_CLK_MAX,
};

enum dsi_link_clk_op_type {
	DSI_LINK_CLK_SET_RATE = BIT(0),
	DSI_LINK_CLK_PREPARE = BIT(1),
	DSI_LINK_CLK_ENABLE = BIT(2),
	DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2),
};

enum dsi_clk_type {
	DSI_CORE_CLK = BIT(0),
	DSI_LINK_CLK = BIT(1),
@@ -50,6 +57,12 @@ enum dsi_clk_type {
	DSI_CLKS_MAX = BIT(2),
};

enum dsi_lclk_type {
	DSI_LINK_NONE = 0,
	DSI_LINK_LP_CLK = BIT(0),
	DSI_LINK_HS_CLK = BIT(1),
};

struct dsi_clk_ctrl_info {
	enum dsi_clk_type clk_type;
	enum dsi_clk_state clk_state;
@@ -82,23 +95,29 @@ struct dsi_core_clk_info {
};

/**
 * struct dsi_link_clk_info - Link clock information for DSI hardware.
 * @byte_clk:        Handle to DSI byte clock.
 * @pixel_clk:       Handle to DSI pixel clock.
 * @esc_clk:         Handle to DSI escape clock.
 * struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW
 * @byte_clk:        Handle to DSI byte_clk.
 * @pixel_clk:       Handle to DSI pixel_clk.
 * @byte_intf_clk:   Handle to DSI byte intf. clock.
 */
struct dsi_link_clk_info {
struct dsi_link_hs_clk_info {
	struct clk *byte_clk;
	struct clk *pixel_clk;
	struct clk *esc_clk;
	struct clk *byte_intf_clk;
};

/**
 * struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW.
 * @esc_clk:         Handle to DSI escape clock.
 */
struct dsi_link_lp_clk_info {
	struct clk *esc_clk;
};

/**
 * struct link_clk_freq - Clock frequency information for Link clocks
 * @byte_clk_rate:   Frequency of DSI byte clock in KHz.
 * @pixel_clk_rate:  Frequency of DSI pixel clock in KHz.
 * @byte_clk_rate:   Frequency of DSI byte_clk in KHz.
 * @pixel_clk_rate:  Frequency of DSI pixel_clk in KHz.
 * @esc_clk_rate:    Frequency of DSI escape clock in KHz.
 */
struct link_clk_freq {
@@ -111,48 +130,56 @@ struct link_clk_freq {
 * typedef *pre_clockoff_cb() - Callback before clock is turned off
 * @priv: private data pointer.
 * @clk_type: clock which is being turned off.
 * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
 * @new_state: next state for the clock.
 *
 * @return: error code.
 */
typedef int (*pre_clockoff_cb)(void *priv,
			       enum dsi_clk_type clk_type,
			       enum dsi_lclk_type l_type,
			       enum dsi_clk_state new_state);

/**
 * typedef *post_clockoff_cb() - Callback after clock is turned off
 * @priv: private data pointer.
 * @clk_type: clock which was turned off.
 * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
 * @curr_state: current state for the clock.
 *
 * @return: error code.
 */
typedef int (*post_clockoff_cb)(void *priv,
				enum dsi_clk_type clk_type,
				enum dsi_lclk_type l_type,
				enum dsi_clk_state curr_state);

/**
 * typedef *post_clockon_cb() - Callback after clock is turned on
 * @priv: private data pointer.
 * @clk_type: clock which was turned on.
 * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
 * @curr_state: current state for the clock.
 *
 * @return: error code.
 */
typedef int (*post_clockon_cb)(void *priv,
			       enum dsi_clk_type clk_type,
			       enum dsi_lclk_type l_type,
			       enum dsi_clk_state curr_state);

/**
 * typedef *pre_clockon_cb() - Callback before clock is turned on
 * @priv: private data pointer.
 * @clk_type: clock which is being turned on.
 * @l_type: specifies if the clock is HS or LP type.Valid only for link clocks.
 * @new_state: next state for the clock.
 *
 * @return: error code.
 */
typedef int (*pre_clockon_cb)(void *priv,
			      enum dsi_clk_type clk_type,
			      enum dsi_lclk_type l_type,
			      enum dsi_clk_state new_state);


@@ -160,7 +187,8 @@ typedef int (*pre_clockon_cb)(void *priv,
 * struct dsi_clk_info - clock information for DSI hardware.
 * @name:                    client name.
 * @c_clks[MAX_DSI_CTRL]     array of core clock configurations
 * @l_clks[MAX_DSI_CTRL]     array of link clock configurations
 * @l_lp_clks[MAX_DSI_CTRL]  array of low power(esc) clock configurations
 * @l_hs_clks[MAX_DSI_CTRL]  array of high speed clock configurations
 * @bus_handle[MAX_DSI_CTRL] array of bus handles
 * @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped
 *                           to core and link clock configurations
@@ -175,7 +203,8 @@ typedef int (*pre_clockon_cb)(void *priv,
struct dsi_clk_info {
	char name[MAX_STRING_LEN];
	struct dsi_core_clk_info c_clks[MAX_DSI_CTRL];
	struct dsi_link_clk_info l_clks[MAX_DSI_CTRL];
	struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL];
	struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL];
	u32 bus_handle[MAX_DSI_CTRL];
	u32 ctrl_index[MAX_DSI_CTRL];
	pre_clockoff_cb pre_clkoff_cb;
@@ -189,8 +218,8 @@ struct dsi_clk_info {

/**
 * struct dsi_clk_link_set - Pair of clock handles to describe link clocks
 * @byte_clk:     Handle to DSi byte clock.
 * @pixel_clk:    Handle to DSI pixel clock.
 * @byte_clk:     Handle to DSi byte_clk.
 * @pixel_clk:    Handle to DSI pixel_clk.
 */
struct dsi_clk_link_set {
	struct clk *byte_clk;
@@ -264,9 +293,9 @@ int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq,


/**
 * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
 * dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk
 * @client:       DSI clock client pointer.
 * @pixel_clk: Pixel clock rate in Hz.
 * @pixel_clk:    Pixel_clk rate in Hz.
 * @index:        Index of the DSI controller.
 * return: error code in case of failure or 0 for success.
 */
+283 −134
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ struct dsi_core_clks {
};

struct dsi_link_clks {
	struct dsi_link_clk_info clks;
	struct dsi_link_hs_clk_info hs_clks;
	struct dsi_link_lp_clk_info lp_clks;
	struct link_clk_freq freq;
};

@@ -124,7 +125,7 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index)
	struct dsi_clk_mngr *mngr;

	mngr = c->mngr;
	rc = clk_set_rate(mngr->link_clks[index].clks.pixel_clk, pixel_clk);
	rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk);
	if (rc)
		pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc);
	else
@@ -147,7 +148,7 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
	struct dsi_clk_mngr *mngr;

	mngr = c->mngr;
	rc = clk_set_rate(mngr->link_clks[index].clks.byte_clk, byte_clk);
	rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
	if (rc)
		pr_err("failed to set clk rate for byte clk, rc=%d\n", rc);
	else
@@ -285,38 +286,39 @@ int dsi_core_clk_stop(struct dsi_core_clks *c_clks)
	return rc;
}

static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index)
static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
		int index)
{
	int rc = 0;
	struct dsi_clk_mngr *mngr;
	struct dsi_link_clks *l_clks;

	if (index >= MAX_DSI_CTRL) {
		pr_err("Invalid DSI ctrl index\n");
		return -EINVAL;
	}

	l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]);
	if (mngr->is_cont_splash_enabled)
		return 0;

	/*
	 * In an ideal world, cont_splash_enabled should not be required inside
	 * the clock manager. But, in the current driver cont_splash_enabled
	 * flag is set inside mdp driver and there is no interface event
	 * associated with this flag setting.
	 */
	rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate);
	if (rc) {
		pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
		goto error;
	}
	if (mngr->is_cont_splash_enabled)
		return 0;

	rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->freq.byte_clk_rate);
	rc = clk_set_rate(link_hs_clks->byte_clk,
		l_clks->freq.byte_clk_rate);
	if (rc) {
		pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
		goto error;
	}

	rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->freq.pix_clk_rate);
	rc = clk_set_rate(link_hs_clks->pixel_clk,
		l_clks->freq.pix_clk_rate);
	if (rc) {
		pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
		goto error;
@@ -327,8 +329,8 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index)
	 * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
	 * todo: this needs to be revisited when support for CPHY is added
	 */
	if (l_clks->clks.byte_intf_clk) {
		rc = clk_set_rate(l_clks->clks.byte_intf_clk,
	if (link_hs_clks->byte_intf_clk) {
		rc = clk_set_rate(link_hs_clks->byte_intf_clk,
			(l_clks->freq.byte_clk_rate / 2));
		if (rc) {
			pr_err("set_rate failed for byte_intf_clk rc = %d\n",
@@ -340,30 +342,24 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index)
	return rc;
}

static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
static int dsi_link_hs_clk_prepare(struct dsi_link_hs_clk_info *link_hs_clks)
{
	int rc = 0;

	rc = clk_prepare(l_clks->clks.esc_clk);
	if (rc) {
		pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc);
		goto esc_clk_err;
	}

	rc = clk_prepare(l_clks->clks.byte_clk);
	rc = clk_prepare(link_hs_clks->byte_clk);
	if (rc) {
		pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc);
		goto byte_clk_err;
	}

	rc = clk_prepare(l_clks->clks.pixel_clk);
	rc = clk_prepare(link_hs_clks->pixel_clk);
	if (rc) {
		pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc);
		goto pixel_clk_err;
	}

	if (l_clks->clks.byte_intf_clk) {
		rc = clk_prepare(l_clks->clks.byte_intf_clk);
	if (link_hs_clks->byte_intf_clk) {
		rc = clk_prepare(link_hs_clks->byte_intf_clk);
		if (rc) {
			pr_err("Failed to prepare dsi byte intf clk, rc=%d\n",
				rc);
@@ -374,48 +370,39 @@ static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
	return rc;

byte_intf_clk_err:
	clk_unprepare(l_clks->clks.pixel_clk);
	clk_unprepare(link_hs_clks->pixel_clk);
pixel_clk_err:
	clk_unprepare(l_clks->clks.byte_clk);
	clk_unprepare(link_hs_clks->byte_clk);
byte_clk_err:
	clk_unprepare(l_clks->clks.esc_clk);
esc_clk_err:
	return rc;
}

static void dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
static void dsi_link_hs_clk_unprepare(struct dsi_link_hs_clk_info *link_hs_clks)
{
	if (l_clks->clks.byte_intf_clk)
		clk_unprepare(l_clks->clks.byte_intf_clk);
	clk_unprepare(l_clks->clks.pixel_clk);
	clk_unprepare(l_clks->clks.byte_clk);
	clk_unprepare(l_clks->clks.esc_clk);
	if (link_hs_clks->byte_intf_clk)
		clk_unprepare(link_hs_clks->byte_intf_clk);
	clk_unprepare(link_hs_clks->pixel_clk);
	clk_unprepare(link_hs_clks->byte_clk);
}

static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
static int dsi_link_hs_clk_enable(struct dsi_link_hs_clk_info *link_hs_clks)
{
	int rc = 0;

	rc = clk_enable(l_clks->clks.esc_clk);
	if (rc) {
		pr_err("Failed to enable dsi esc clk, rc=%d\n", rc);
		goto esc_clk_err;
	}

	rc = clk_enable(l_clks->clks.byte_clk);
	rc = clk_enable(link_hs_clks->byte_clk);
	if (rc) {
		pr_err("Failed to enable dsi byte clk, rc=%d\n", rc);
		goto byte_clk_err;
	}

	rc = clk_enable(l_clks->clks.pixel_clk);
	rc = clk_enable(link_hs_clks->pixel_clk);
	if (rc) {
		pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc);
		goto pixel_clk_err;
	}

	if (l_clks->clks.byte_intf_clk) {
		rc = clk_enable(l_clks->clks.byte_intf_clk);
	if (link_hs_clks->byte_intf_clk) {
		rc = clk_enable(link_hs_clks->byte_intf_clk);
		if (rc) {
			pr_err("Failed to enable dsi byte intf clk, rc=%d\n",
				rc);
@@ -426,28 +413,26 @@ static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
	return rc;

byte_intf_clk_err:
	clk_disable(l_clks->clks.pixel_clk);
	clk_disable(link_hs_clks->pixel_clk);
pixel_clk_err:
	clk_disable(l_clks->clks.byte_clk);
	clk_disable(link_hs_clks->byte_clk);
byte_clk_err:
	clk_disable(l_clks->clks.esc_clk);
esc_clk_err:
	return rc;
}

static void dsi_link_clk_disable(struct dsi_link_clks *l_clks)
static void dsi_link_hs_clk_disable(struct dsi_link_hs_clk_info *link_hs_clks)
{
	if (l_clks->clks.byte_intf_clk)
		clk_disable(l_clks->clks.byte_intf_clk);
	clk_disable(l_clks->clks.esc_clk);
	clk_disable(l_clks->clks.pixel_clk);
	clk_disable(l_clks->clks.byte_clk);
	if (link_hs_clks->byte_intf_clk)
		clk_disable(link_hs_clks->byte_intf_clk);
	clk_disable(link_hs_clks->pixel_clk);
	clk_disable(link_hs_clks->byte_clk);
}

/**
 * dsi_link_clk_start() - enable dsi link clocks
 */
static int dsi_link_clk_start(struct dsi_link_clks *clks, int index)
static int dsi_link_hs_clk_start(struct dsi_link_hs_clk_info *link_hs_clks,
	enum dsi_link_clk_op_type op_type, int index)
{
	int rc = 0;

@@ -456,28 +441,34 @@ static int dsi_link_clk_start(struct dsi_link_clks *clks, int index)
		return -EINVAL;
	}

	rc = dsi_link_clk_set_rate(clks, index);
	if (op_type & DSI_LINK_CLK_SET_RATE) {
		rc = dsi_link_hs_clk_set_rate(link_hs_clks, index);
		if (rc) {
		pr_err("failed to set clk rates, rc = %d\n", rc);
			pr_err("failed to set HS clk rates, rc = %d\n", rc);
			goto error;
		}
	}

	rc = dsi_link_clk_prepare(clks);
	if (op_type & DSI_LINK_CLK_PREPARE) {
		rc = dsi_link_hs_clk_prepare(link_hs_clks);
		if (rc) {
		pr_err("failed to prepare link clks, rc = %d\n", rc);
			pr_err("failed to prepare link HS clks, rc = %d\n", rc);
			goto error;
		}
	}

	rc = dsi_link_clk_enable(clks);
	if (op_type & DSI_LINK_CLK_ENABLE) {
		rc = dsi_link_hs_clk_enable(link_hs_clks);
		if (rc) {
		pr_err("failed to enable link clks, rc = %d\n", rc);
			pr_err("failed to enable link HS clks, rc = %d\n", rc);
			goto error_unprepare;
		}
	}

	pr_debug("Link clocks are enabled\n");
	pr_debug("HS Link clocks are enabled\n");
	return rc;
error_unprepare:
	dsi_link_clk_unprepare(clks);
	dsi_link_hs_clk_unprepare(link_hs_clks);
error:
	return rc;
}
@@ -485,13 +476,69 @@ static int dsi_link_clk_start(struct dsi_link_clks *clks, int index)
/**
 * dsi_link_clk_stop() - Stop DSI link clocks.
 */
int dsi_link_clk_stop(struct dsi_link_clks *clks)
static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks)
{
	struct dsi_link_clks *l_clks;

	l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);

	dsi_link_hs_clk_disable(link_hs_clks);
	dsi_link_hs_clk_unprepare(link_hs_clks);

	pr_debug("HS Link clocks disabled\n");

	return 0;
}

static int dsi_link_lp_clk_start(struct dsi_link_lp_clk_info *link_lp_clks)
{
	int rc = 0;
	struct dsi_clk_mngr *mngr;
	struct dsi_link_clks *l_clks;

	l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);

	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
	if (!mngr)
		return -EINVAL;
	/*
	 * In an ideal world, cont_splash_enabled should not be required inside
	 * the clock manager. But, in the current driver cont_splash_enabled
	 * flag is set inside mdp driver and there is no interface event
	 * associated with this flag setting. Also, set rate for clock need not
	 * be called for every enable call. It should be done only once when
	 * coming out of suspend.
	 */
	if (mngr->is_cont_splash_enabled)
		goto prepare;

	rc = clk_set_rate(link_lp_clks->esc_clk, l_clks->freq.esc_clk_rate);
	if (rc) {
		pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
		goto error;
	}

prepare:
	rc = clk_prepare_enable(link_lp_clks->esc_clk);
	if (rc) {
		pr_err("Failed to enable dsi esc clk\n");
		clk_unprepare(l_clks->lp_clks.esc_clk);
	}
error:
	pr_debug("LP Link clocks are enabled\n");
	return rc;
}

static int dsi_link_lp_clk_stop(
	struct dsi_link_lp_clk_info *link_lp_clks)
{
	dsi_link_clk_disable(clks);
	dsi_link_clk_unprepare(clks);
	struct dsi_link_clks *l_clks;

	pr_debug("Link clocks disabled\n");
	l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);

	clk_disable_unprepare(l_clks->lp_clks.esc_clk);

	pr_debug("LP Link clocks are disabled\n");
	return 0;
}

@@ -556,7 +603,7 @@ static int dsi_display_core_clk_enable(struct dsi_core_clks *clks,
}

static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
	u32 ctrl_count, u32 master_ndx)
	enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
{
	int rc = 0;
	int i;
@@ -570,27 +617,56 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,

	m_clks = &clks[master_ndx];

	rc = dsi_link_clk_start(m_clks, master_ndx);
	if (l_type & DSI_LINK_LP_CLK) {
		rc = dsi_link_lp_clk_start(&m_clks->lp_clks);
		if (rc) {
		pr_err("failed to turn on master clocks, rc=%d\n", rc);
			pr_err("failed to turn on master lp link clocks, rc=%d\n",
				rc);
			goto error;
		}
	}

	if (l_type & DSI_LINK_HS_CLK) {
		rc = dsi_link_hs_clk_start(&m_clks->hs_clks,
			DSI_LINK_CLK_START, master_ndx);
		if (rc) {
			pr_err("failed to turn on master hs link clocks, rc=%d\n",
				rc);
			goto error;
		}
	}

	/* Turn on rest of the core clocks */
	for (i = 0; i < ctrl_count; i++) {
		clk = &clks[i];
		if (!clk || (clk == m_clks))
			continue;

		rc = dsi_link_clk_start(clk, i);
		if (l_type & DSI_LINK_LP_CLK) {
			rc = dsi_link_lp_clk_start(&clk->lp_clks);
			if (rc) {
			pr_err("failed to turn on clocks, rc=%d\n", rc);
				pr_err("failed to turn on lp link clocks, rc=%d\n",
					rc);
				goto error_disable_master;
			}
		}

		if (l_type & DSI_LINK_HS_CLK) {
			rc = dsi_link_hs_clk_start(&clk->hs_clks,
				DSI_LINK_CLK_START, i);
			if (rc) {
				pr_err("failed to turn on hs link clocks, rc=%d\n",
					rc);
				goto error_disable_master;
			}
		}
	}
	return rc;

error_disable_master:
	(void)dsi_link_clk_stop(m_clks);
	if (l_type == DSI_LINK_LP_CLK)
		(void)dsi_link_lp_clk_stop(&m_clks->lp_clks);
	else if (l_type == DSI_LINK_HS_CLK)
		(void)dsi_link_hs_clk_stop(&m_clks->hs_clks);
error:
	return rc;
}
@@ -646,7 +722,7 @@ static int dsi_display_core_clk_disable(struct dsi_core_clks *clks,
}

static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
	u32 ctrl_count, u32 master_ndx)
	enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
{
	int rc = 0;
	int i;
@@ -667,15 +743,100 @@ static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
		if (!clk || (clk == m_clks))
			continue;

		rc = dsi_link_clk_stop(clk);
		if (l_type & DSI_LINK_LP_CLK) {
			rc = dsi_link_lp_clk_stop(&clk->lp_clks);
			if (rc)
			pr_err("failed to turn off clocks, rc=%d\n", rc);
				pr_err("failed to turn off lp link clocks, rc=%d\n",
					rc);
		}

	rc = dsi_link_clk_stop(m_clks);
		if (l_type & DSI_LINK_HS_CLK) {
			rc = dsi_link_hs_clk_stop(&clk->hs_clks);
			if (rc)
		pr_err("failed to turn off master clocks, rc=%d\n", rc);
				pr_err("failed to turn off hs link clocks, rc=%d\n",
					rc);
		}
	}

	if (l_type & DSI_LINK_LP_CLK) {
		rc = dsi_link_lp_clk_stop(&m_clks->lp_clks);
		if (rc)
			pr_err("failed to turn off master lp link clocks, rc=%d\n",
				rc);
	}

	if (l_type & DSI_LINK_HS_CLK) {
		rc = dsi_link_hs_clk_stop(&m_clks->hs_clks);
		if (rc)
			pr_err("failed to turn off master hs link clocks, rc=%d\n",
				rc);
	}

	return rc;
}

static int dsi_clk_update_link_clk_state(struct dsi_link_clks *l_clks,
	enum dsi_lclk_type l_type, u32 l_state, bool enable)
{
	int rc = 0;
	struct dsi_clk_mngr *mngr;

	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
	if (!mngr)
		return -EINVAL;

	if (enable) {
		if (mngr->pre_clkon_cb) {
			rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
				l_type, l_state);
			if (rc) {
				pr_err("pre link clk on cb failed for type %d\n",
					l_type);
				goto error;
			}
		}
		rc = dsi_display_link_clk_enable(l_clks, l_type,
				mngr->dsi_ctrl_count, mngr->master_ndx);
		if (rc) {
			pr_err("failed to start link clk type %d rc=%d\n",
				l_type, rc);
			goto error;
		}

		if (mngr->post_clkon_cb) {
			rc = mngr->post_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
				l_type, l_state);
			if (rc) {
				pr_err("post link clk on cb failed for type %d\n",
					l_type);
				goto error;
			}
		}
	} else {
		if (mngr->pre_clkoff_cb) {
			rc = mngr->pre_clkoff_cb(mngr->priv_data,
				DSI_LINK_CLK, l_type, l_state);
			if (rc)
				pr_err("pre link clk off cb failed\n");
		}

		rc = dsi_display_link_clk_disable(l_clks, l_type,
			mngr->dsi_ctrl_count, mngr->master_ndx);
		if (rc) {
			pr_err("failed to stop link clk type %d, rc = %d\n",
			       l_type, rc);
			goto error;
		}

		if (mngr->post_clkoff_cb) {
			rc = mngr->post_clkoff_cb(mngr->priv_data,
				DSI_LINK_CLK, l_type, l_state);
			if (rc)
				pr_err("post link clk off cb failed\n");
		}
	}

error:
	return rc;
}

@@ -710,6 +871,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
		if (mngr->core_clk_state == DSI_CLK_OFF) {
			rc = mngr->pre_clkon_cb(mngr->priv_data,
						DSI_CORE_CLK,
						DSI_LINK_NONE,
						DSI_CLK_ON);
			if (rc) {
				pr_err("failed to turn on MDP FS rc= %d\n", rc);
@@ -726,6 +888,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
		if (mngr->post_clkon_cb) {
			rc = mngr->post_clkon_cb(mngr->priv_data,
						 DSI_CORE_CLK,
						 DSI_LINK_NONE,
						 DSI_CLK_ON);
			if (rc)
				pr_err("post clk on cb failed, rc = %d\n", rc);
@@ -735,25 +898,15 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,

	if (l_clks) {
		if (l_state == DSI_CLK_ON) {
			if (mngr->pre_clkon_cb) {
				rc = mngr->pre_clkon_cb(mngr->priv_data,
					DSI_LINK_CLK, l_state);
			rc = dsi_clk_update_link_clk_state(l_clks,
				DSI_LINK_LP_CLK, l_state, true);
			if (rc)
					pr_err("pre link clk on cb failed\n");
			}
			rc = dsi_display_link_clk_enable(l_clks,
					mngr->dsi_ctrl_count, mngr->master_ndx);
			if (rc) {
				pr_err("failed to start link clk rc= %d\n", rc);
				goto error;
			}
			if (mngr->post_clkon_cb) {
				rc = mngr->post_clkon_cb(mngr->priv_data,
							DSI_LINK_CLK,
							l_state);

			rc = dsi_clk_update_link_clk_state(l_clks,
				DSI_LINK_HS_CLK, l_state, true);
			if (rc)
					pr_err("post link clk on cb failed\n");
			}
				goto error;
		} else {
			/*
			 * Two conditions that need to be checked for Link
@@ -784,36 +937,26 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
				}

				rc = dsi_display_link_clk_enable(l_clks,
					(DSI_LINK_LP_CLK & DSI_LINK_HS_CLK),
					mngr->dsi_ctrl_count, mngr->master_ndx);
				if (rc) {
					pr_err("Link clks did not start\n");
					pr_err("LP Link clks did not start\n");
					goto error;
				}
				l_c_on = true;
				pr_debug("ECG: core and Link_on\n");
			}

			if (mngr->pre_clkoff_cb) {
				rc = mngr->pre_clkoff_cb(mngr->priv_data,
					DSI_LINK_CLK, l_state);
			rc = dsi_clk_update_link_clk_state(l_clks,
				DSI_LINK_HS_CLK, l_state, false);
			if (rc)
					pr_err("pre link clk off cb failed\n");
			}

			rc = dsi_display_link_clk_disable(l_clks,
				mngr->dsi_ctrl_count, mngr->master_ndx);
			if (rc) {
				pr_err("failed to stop link clk, rc = %d\n",
				       rc);
				goto error;
			}

			if (mngr->post_clkoff_cb) {
				rc = mngr->post_clkoff_cb(mngr->priv_data,
					DSI_LINK_CLK, l_state);
			rc = dsi_clk_update_link_clk_state(l_clks,
				DSI_LINK_LP_CLK, l_state, false);
			if (rc)
					pr_err("post link clk off cb failed\n");
			}
				goto error;

			/*
			 * This check is to save unnecessary clock state
			 * change when going from EARLY_GATE to OFF. In the
@@ -872,6 +1015,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
		if (mngr->pre_clkoff_cb) {
			rc = mngr->pre_clkoff_cb(mngr->priv_data,
						 DSI_CORE_CLK,
						 DSI_LINK_NONE,
						 c_state);
			if (rc)
				pr_err("pre core clk off cb failed\n");
@@ -888,6 +1032,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
			if (mngr->post_clkoff_cb) {
				rc = mngr->post_clkoff_cb(mngr->priv_data,
						DSI_CORE_CLK,
						DSI_LINK_NONE,
						DSI_CLK_OFF);
				if (rc)
					pr_err("post clkoff cb fail, rc = %d\n",
@@ -1095,6 +1240,7 @@ static int dsi_display_link_clk_force_update(void *client)
	}

	rc = dsi_display_link_clk_disable(l_clks,
			(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
			mngr->dsi_ctrl_count, mngr->master_ndx);
	if (rc) {
		pr_err("%s, failed to stop link clk, rc = %d\n",
@@ -1103,6 +1249,7 @@ static int dsi_display_link_clk_force_update(void *client)
	}

	rc = dsi_display_link_clk_enable(l_clks,
			(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
			mngr->dsi_ctrl_count, mngr->master_ndx);
	if (rc) {
		pr_err("%s, failed to start link clk rc= %d\n",
@@ -1268,8 +1415,10 @@ void *dsi_display_clk_mngr_register(struct dsi_clk_info *info)
	for (i = 0; i < mngr->dsi_ctrl_count; i++) {
		memcpy(&mngr->core_clks[i].clks, &info->c_clks[i],
			sizeof(struct dsi_core_clk_info));
		memcpy(&mngr->link_clks[i].clks, &info->l_clks[i],
			sizeof(struct dsi_link_clk_info));
		memcpy(&mngr->link_clks[i].hs_clks, &info->l_hs_clks[i],
			sizeof(struct dsi_link_hs_clk_info));
		memcpy(&mngr->link_clks[i].lp_clks, &info->l_lp_clks[i],
			sizeof(struct dsi_link_lp_clk_info));
		mngr->core_clks[i].bus_handle = info->bus_handle[i];
		mngr->ctrl_index[i] = info->ctrl_index[i];
	}
+26 −23

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -97,7 +97,8 @@ struct dsi_ctrl_power_info {
/**
 * struct dsi_ctrl_clk_info - clock information for DSI controller
 * @core_clks:          Core clocks needed to access DSI controller registers.
 * @link_clks:          Link clocks required to transmit data over DSI link.
 * @hs_link_clks:       Clocks required to transmit high speed data over DSI
 * @lp_link_clks:       Clocks required to perform low power ops over DSI
 * @rcg_clks:           Root clock generation clocks generated in MMSS_CC. The
 *			output of the PLL is set as parent for these root
 *			clocks. These clocks are specific to controller
@@ -111,7 +112,8 @@ struct dsi_ctrl_power_info {
struct dsi_ctrl_clk_info {
	/* Clocks parsed from DT */
	struct dsi_core_clk_info core_clks;
	struct dsi_link_clk_info link_clks;
	struct dsi_link_hs_clk_info hs_link_clks;
	struct dsi_link_lp_clk_info lp_link_clks;
	struct dsi_clk_link_set rcg_clks;

	/* Clocks set by DSI Manager */
+14 −4
Original line number Diff line number Diff line
@@ -2893,6 +2893,7 @@ static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en)

int dsi_pre_clkoff_cb(void *priv,
			   enum dsi_clk_type clk,
			   enum dsi_lclk_type l_type,
			   enum dsi_clk_state new_state)
{
	int rc = 0, i;
@@ -2960,6 +2961,7 @@ int dsi_pre_clkoff_cb(void *priv,

int dsi_post_clkon_cb(void *priv,
			   enum dsi_clk_type clk,
			   enum dsi_lclk_type l_type,
			   enum dsi_clk_state curr_state)
{
	int rc = 0;
@@ -3048,6 +3050,7 @@ int dsi_post_clkon_cb(void *priv,

int dsi_post_clkoff_cb(void *priv,
			    enum dsi_clk_type clk_type,
			    enum dsi_lclk_type l_type,
			    enum dsi_clk_state curr_state)
{
	int rc = 0;
@@ -3075,6 +3078,7 @@ int dsi_post_clkoff_cb(void *priv,

int dsi_pre_clkon_cb(void *priv,
			  enum dsi_clk_type clk_type,
			  enum dsi_lclk_type l_type,
			  enum dsi_clk_state new_state)
{
	int rc = 0;
@@ -4312,10 +4316,16 @@ static int dsi_display_bind(struct device *dev,
			goto error_ctrl_deinit;
		}

		memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks,
		memcpy(&info.c_clks[i],
				(&display_ctrl->ctrl->clk_info.core_clks),
				sizeof(struct dsi_core_clk_info));
		memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks,
			sizeof(struct dsi_link_clk_info));
		memcpy(&info.l_hs_clks[i],
				(&display_ctrl->ctrl->clk_info.hs_link_clks),
				sizeof(struct dsi_link_hs_clk_info));
		memcpy(&info.l_lp_clks[i],
				(&display_ctrl->ctrl->clk_info.lp_link_clks),
				sizeof(struct dsi_link_lp_clk_info));

		info.c_clks[i].phandle = &priv->phandle;
		info.bus_handle[i] =
			display_ctrl->ctrl->axi_bus_info.bus_handle;
Loading