All of lore.kernel.org
 help / color / mirror / Atom feed
From: Archit Taneja <architt@codeaurora.org>
To: dri-devel@lists.freedesktop.org, robdclark@gmail.com,
	hali@codeaurora.org
Cc: linux-arm-msm@vger.kernel.org
Subject: [PATCH 07/12] drm/msm/dsi: Set up link clocks for DSIv2
Date: Wed, 14 Oct 2015 18:28:59 +0530	[thread overview]
Message-ID: <1444827544-25656-8-git-send-email-architt@codeaurora.org> (raw)
In-Reply-To: <1444827544-25656-1-git-send-email-architt@codeaurora.org>

DSIv2 (DSI on older A family chips) has slightly different link clock
requirements.

First, we have an extra clock called src_clk (with a dedicated RCG).
This is required by the DSI controller to process the pixel data
coming from MDP. It needs to be set at the rate "pclk * bytes_per_pixel".

We also need to explicitly configure esc_clk. On DSI6G chips, we don't
need to set a rate to esc_clk because its RCG is always sourced from
crystal clock (19.2 Mhz in all cases), which is within the escape clock
frequency range in the mipi DSI spec. For chips with DSIv2, the crystal
clock rate may not be within the required range (27Mhz on APQ8064).
Therefore, we derive it from the DSI byte clock. We calculate an esc_clck
rate that is within the mipi spec and also divisible by the byte clock
rate.

When setting rate and enabling the link clocks, we make sure that byte_clk
is configured before esc_clk, and src_clk before pixel_clk. We create two
different link_enable funcs for DSI6G and DSIv2 since the sequences are
different.

We also obtain two extra source clocks (dsi_src_clk and esc_src_clk) and
set their parent to the clocks provided by DSI PLL.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/msm/dsi/dsi_host.c | 193 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 188 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 008726f..16c5cfb 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -113,6 +113,14 @@ struct msm_dsi_host {
 	struct clk *pixel_clk_src;
 
 	u32 byte_clk_rate;
+	u32 esc_clk_rate;
+
+	/* DSI v2 specific clocks */
+	struct clk *src_clk;
+	struct clk *esc_clk_src;
+	struct clk *dsi_clk_src;
+
+	u32 src_clk_rate;
 
 	struct gpio_desc *disp_en_gpio;
 	struct gpio_desc *te_gpio;
@@ -318,7 +326,8 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host)
 static int dsi_clk_init(struct msm_dsi_host *msm_host)
 {
 	struct device *dev = &msm_host->pdev->dev;
-	const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg;
+	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+	const struct msm_dsi_config *cfg = cfg_hnd->cfg;
 	int i, ret = 0;
 
 	/* get bus clocks */
@@ -377,6 +386,34 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host)
 		goto exit;
 	}
 
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+		msm_host->src_clk = devm_clk_get(dev, "src_clk");
+		if (IS_ERR(msm_host->src_clk)) {
+			ret = PTR_ERR(msm_host->src_clk);
+			pr_err("%s: can't find dsi_src_clk. ret=%d\n",
+				__func__, ret);
+			msm_host->src_clk = NULL;
+			goto exit;
+		}
+
+		msm_host->esc_clk_src = devm_clk_get(dev, "esc_clk_src");
+		if (IS_ERR(msm_host->esc_clk_src)) {
+			ret = PTR_ERR(msm_host->esc_clk_src);
+			pr_err("%s: can't find esc_clk_src. ret=%d\n",
+				__func__, ret);
+			msm_host->esc_clk_src = NULL;
+			goto exit;
+		}
+
+		msm_host->dsi_clk_src = devm_clk_get(dev, "dsi_clk_src");
+		if (IS_ERR(msm_host->dsi_clk_src)) {
+			ret = PTR_ERR(msm_host->dsi_clk_src);
+			pr_err("%s: can't find dsi_clk_src. ret=%d\n",
+				__func__, ret);
+			msm_host->dsi_clk_src = NULL;
+			goto exit;
+		}
+	}
 exit:
 	return ret;
 }
@@ -416,7 +453,7 @@ static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host)
 		clk_disable_unprepare(msm_host->bus_clks[i]);
 }
 
-static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host)
 {
 	int ret;
 
@@ -463,11 +500,98 @@ error:
 	return ret;
 }
 
-static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+static int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
 {
+	int ret;
+
+	DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d",
+		msm_host->mode->clock, msm_host->byte_clk_rate,
+		msm_host->esc_clk_rate, msm_host->src_clk_rate);
+
+	ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
+	if (ret) {
+		pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
+		goto error;
+	}
+
+	ret = clk_set_rate(msm_host->esc_clk, msm_host->esc_clk_rate);
+	if (ret) {
+		pr_err("%s: Failed to set rate esc clk, %d\n", __func__, ret);
+		goto error;
+	}
+
+	ret = clk_set_rate(msm_host->src_clk, msm_host->src_clk_rate);
+	if (ret) {
+		pr_err("%s: Failed to set rate src clk, %d\n", __func__, ret);
+		goto error;
+	}
+
+	ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000);
+	if (ret) {
+		pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret);
+		goto error;
+	}
+
+	ret = clk_prepare_enable(msm_host->byte_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+		goto error;
+	}
+
+	ret = clk_prepare_enable(msm_host->esc_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable dsi esc clk\n", __func__);
+		goto esc_clk_err;
+	}
+
+	ret = clk_prepare_enable(msm_host->src_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable dsi src clk\n", __func__);
+		goto src_clk_err;
+	}
+
+	ret = clk_prepare_enable(msm_host->pixel_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+		goto pixel_clk_err;
+	}
+
+	return 0;
+
+pixel_clk_err:
+	clk_disable_unprepare(msm_host->src_clk);
+src_clk_err:
 	clk_disable_unprepare(msm_host->esc_clk);
-	clk_disable_unprepare(msm_host->pixel_clk);
+esc_clk_err:
 	clk_disable_unprepare(msm_host->byte_clk);
+error:
+	return ret;
+}
+
+static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+{
+	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G)
+		return dsi_link_clk_enable_6g(msm_host);
+	else
+		return dsi_link_clk_enable_v2(msm_host);
+}
+
+static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+{
+	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
+		clk_disable_unprepare(msm_host->esc_clk);
+		clk_disable_unprepare(msm_host->pixel_clk);
+		clk_disable_unprepare(msm_host->byte_clk);
+	} else {
+		clk_disable_unprepare(msm_host->pixel_clk);
+		clk_disable_unprepare(msm_host->src_clk);
+		clk_disable_unprepare(msm_host->esc_clk);
+		clk_disable_unprepare(msm_host->byte_clk);
+	}
 }
 
 static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable)
@@ -502,6 +626,7 @@ unlock_ret:
 static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
 {
 	struct drm_display_mode *mode = msm_host->mode;
+	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
 	u8 lanes = msm_host->lanes;
 	u32 bpp = dsi_get_bpp(msm_host->format);
 	u32 pclk_rate;
@@ -521,6 +646,47 @@ static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
 
 	DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate);
 
+	msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk);
+
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+		unsigned int esc_mhz, esc_div;
+		unsigned long byte_mhz;
+
+		msm_host->src_clk_rate = (pclk_rate * bpp) / 8;
+
+		/*
+		 * esc clock is byte clock followed by a 4 bit divider,
+		 * we need to find an escape clock frequency within the
+		 * mipi DSI spec range within the maximum divider limit
+		 * We iterate here between an escape clock frequencey
+		 * between 20 Mhz to 5 Mhz and pick up the first one
+		 * that can be supported by our divider
+		 */
+
+		byte_mhz = msm_host->byte_clk_rate / 1000000;
+
+		for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) {
+			esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz);
+
+			/*
+			 * TODO: Ideally, we shouldn't know what sort of divider
+			 * is available in mmss_cc, we're just assuming that
+			 * it'll always be a 4 bit divider. Need to come up with
+			 * a better way here.
+			 */
+			if (esc_div >= 1 && esc_div <= 16)
+				break;
+		}
+
+		if (esc_mhz < 5)
+			return -EINVAL;
+
+		msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div;
+
+		DBG("esc=%d, src=%d", msm_host->esc_clk_rate,
+			msm_host->src_clk_rate);
+	}
+
 	return 0;
 }
 
@@ -1753,6 +1919,7 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
 	struct msm_dsi_pll *src_pll)
 {
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
 	struct clk *byte_clk_provider, *pixel_clk_provider;
 	int ret;
 
@@ -1778,6 +1945,22 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
 		goto exit;
 	}
 
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+		ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider);
+		if (ret) {
+			pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n",
+				__func__, ret);
+			goto exit;
+		}
+
+		ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider);
+		if (ret) {
+			pr_err("%s: can't set parent to esc_clk_src. ret=%d\n",
+				__func__, ret);
+			goto exit;
+		}
+	}
+
 exit:
 	return ret;
 }
@@ -1849,7 +2032,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
 	dsi_phy_sw_reset(msm_host);
 	ret = msm_dsi_manager_phy_enable(msm_host->id,
 					msm_host->byte_clk_rate * 8,
-					clk_get_rate(msm_host->esc_clk),
+					msm_host->esc_clk_rate,
 					&clk_pre, &clk_post);
 	dsi_bus_clk_disable(msm_host);
 	if (ret) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2015-10-14 12:58 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-14 12:58 [PATCH 00/12] drm/msm/dsi: Add support for DSI on MSM8960/APQ8064 Archit Taneja
2015-10-14 12:58 ` [PATCH 01/12] drm/msm/dsi: Update generated header for 8960 Archit Taneja
2015-10-14 12:58 ` [PATCH 02/12] drm/msm/dsi: Add support for 28nm PHY on 8960 Archit Taneja
2015-10-14 12:58 ` [PATCH 03/12] drm/msm/dsi: Add DSI PLL for 28nm 8960 PHY Archit Taneja
2015-10-14 20:35   ` Stephen Boyd
2015-10-16 13:08     ` Archit Taneja
2015-10-16 18:28       ` Stephen Boyd
2015-10-14 12:58 ` [PATCH 04/12] drm/msm/dsi: Use a better way to figure out DSI version Archit Taneja
2015-10-14 12:58 ` [PATCH 05/12] drm/msm/dsi: Delay dsi_clk_init Archit Taneja
2015-10-14 12:58 ` [PATCH 06/12] drm/msm/dsi: Parse bus clocks from a list Archit Taneja
2015-10-14 12:58 ` Archit Taneja [this message]
2015-10-14 12:59 ` [PATCH 08/12] drm/msm/dsi: Add dsi_cfg for APQ8064 Archit Taneja
2015-10-14 12:59 ` [PATCH 09/12] drm/msm/dsi: Don't use iommu for command TX buffer for DSIv2 Archit Taneja
2015-10-14 12:59 ` [PATCH 10/12] drm/msm/dsi: SFPB: Update generated headers Archit Taneja
2015-10-14 12:59 ` [PATCH 11/12] drm/msm/dsi: Enable MMSS SPFB port via syscon Archit Taneja
2015-10-14 12:59 ` [PATCH 12/12] dt-bindings: Add DSIv2 documentation Archit Taneja
2015-11-18 10:55 ` [PATCH v2 00/10] drm/msm/dsi: Add support for DSI on MSM8960/APQ8064 Archit Taneja
2015-11-18 10:55   ` [PATCH v2 01/10] drm/msm/dsi: Add support for 28nm PHY on 8960 Archit Taneja
2015-11-18 10:55   ` [PATCH v2 02/10] drm/msm/dsi: Add DSI PLL for 28nm 8960 PHY Archit Taneja
2015-11-18 10:55   ` [PATCH v2 03/10] drm/msm/dsi: Use a better way to figure out DSI version Archit Taneja
2015-11-18 10:55   ` [PATCH v2 04/10] drm/msm/dsi: Delay dsi_clk_init Archit Taneja
2015-11-18 10:55   ` [PATCH v2 05/10] drm/msm/dsi: Parse bus clocks from a list Archit Taneja
2015-11-18 10:55   ` [PATCH v2 06/10] drm/msm/dsi: Set up link clocks for DSIv2 Archit Taneja
2015-11-18 10:55   ` [PATCH v2 07/10] drm/msm/dsi: Add dsi_cfg for APQ8064 Archit Taneja
2015-11-18 10:55   ` [PATCH v2 08/10] drm/msm/dsi: Don't use iommu for command TX buffer for DSIv2 Archit Taneja
2015-11-18 10:55   ` [PATCH v2 09/10] drm/msm/dsi: Enable MMSS SPFB port via syscon Archit Taneja
2015-11-18 10:55   ` [PATCH v2 10/10] dt-bindings: Add DSIv2 documentation Archit Taneja
2015-11-18 13:18     ` Rob Herring
2015-11-18 15:24       ` Archit Taneja
     [not found]         ` <564C981F.3040907-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-11-20 19:59           ` Rob Herring
2015-11-23  6:13             ` Archit Taneja
2015-12-02  8:20               ` Stephen Boyd
2015-12-02  8:34                 ` Stephen Boyd
2015-12-07  6:51                   ` Archit Taneja
2015-12-02  9:56                 ` Archit Taneja
2015-12-03  7:16                   ` Stephen Boyd
2015-12-03 11:11                     ` Archit Taneja
2015-12-01  9:59   ` [PATCH v3 00/12] drm/msm/dsi: Add support for DSI on MSM8960/APQ8064 Archit Taneja
2015-12-01  9:59     ` [PATCH v3 01/12] drm/msm/dsi: Don't get byte/pixel source clocks from DT Archit Taneja
2015-12-01 10:00     ` [PATCH v3 02/12] drm/msm/dsi: Add support for 28nm PHY on 8960 Archit Taneja
2015-12-01 10:00     ` [PATCH v3 03/12] drm/msm/dsi: Add DSI PLL for 28nm 8960 PHY Archit Taneja
2015-12-01 10:00     ` [PATCH v3 04/12] drm/msm/dsi: Use a better way to figure out DSI version Archit Taneja
2015-12-01 10:00     ` [PATCH v3 05/12] drm/msm/dsi: Delay dsi_clk_init Archit Taneja
2015-12-01 10:00     ` [PATCH v3 06/12] drm/msm/dsi: Parse bus clocks from a list Archit Taneja
2015-12-01 10:00     ` [PATCH v3 07/12] drm/msm/dsi: Set up link clocks for DSIv2 Archit Taneja
2015-12-01 10:00     ` [PATCH v3 08/12] drm/msm/dsi: Add dsi_cfg for APQ8064 Archit Taneja
2015-12-01 10:00     ` [PATCH v3 09/12] drm/msm/dsi: Don't use iommu for command TX buffer for DSIv2 Archit Taneja
2015-12-01 10:00     ` [PATCH v3 10/12] drm/msm/dsi: Enable MMSS SPFB port via syscon Archit Taneja
2015-12-01 10:00     ` [PATCH v3 11/12] dt-bindings: msm/dsi: Fix the order in which clocks are listed Archit Taneja
2015-12-04 14:45       ` Rob Herring
2015-12-01 10:00     ` [PATCH v3 12/12] dt-bindings: msm/dsi: Add DSIv2 documentation Archit Taneja
2015-12-04 14:46       ` Rob Herring

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1444827544-25656-8-git-send-email-architt@codeaurora.org \
    --to=architt@codeaurora.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hali@codeaurora.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=robdclark@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.