linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] ARM: imx: pllv3 relock fixes
@ 2013-11-01  9:02 Shawn Guo
  2013-11-01  9:02 ` [PATCH 1/3] ARM: imx: add sleep for pllv3 relock Shawn Guo
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Shawn Guo @ 2013-11-01  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

The series includes a couple of pllv3 relock updates which should fix
IPU clocking problem found in HDMI testing.

Russell,

I did not add BYPASS handling in .set_rate() operation in this series,
because so far it's unclear to me if it solves any problem for us.  We
can add it later if we confirm it does help.

Shawn

Shawn Guo (3):
  ARM: imx: add sleep for pllv3 relock
  ARM: imx: pllv3 needs relock in .set_rate() call
  ARM: imx: set up pllv3 POWER and BYPASS sequentially

 arch/arm/mach-imx/clk-pllv3.c |   51 +++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 17 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] ARM: imx: add sleep for pllv3 relock
  2013-11-01  9:02 [PATCH 0/3] ARM: imx: pllv3 relock fixes Shawn Guo
@ 2013-11-01  9:02 ` Shawn Guo
  2013-11-01  9:02 ` [PATCH 2/3] ARM: imx: pllv3 needs relock in .set_rate() call Shawn Guo
  2013-11-01  9:02 ` [PATCH 3/3] ARM: imx: set up pllv3 POWER and BYPASS sequentially Shawn Guo
  2 siblings, 0 replies; 4+ messages in thread
From: Shawn Guo @ 2013-11-01  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

The pllv3 relock time varies in the range of 50us ~ 500us, depending on
the specific PLL type, e.g. 50us for ARM PLL and 450us for Audio/Video
PLL.  Let's add a usleep_range() call instead of doing busy wait during
relock.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/clk-pllv3.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index f6640b6..c9ca191 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -12,6 +12,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -66,6 +67,7 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
 			break;
 		if (time_after(jiffies, timeout))
 			break;
+		usleep_range(50, 500);
 	} while (1);
 
 	if (readl_relaxed(pll->base) & BM_PLL_LOCK)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] ARM: imx: pllv3 needs relock in .set_rate() call
  2013-11-01  9:02 [PATCH 0/3] ARM: imx: pllv3 relock fixes Shawn Guo
  2013-11-01  9:02 ` [PATCH 1/3] ARM: imx: add sleep for pllv3 relock Shawn Guo
@ 2013-11-01  9:02 ` Shawn Guo
  2013-11-01  9:02 ` [PATCH 3/3] ARM: imx: set up pllv3 POWER and BYPASS sequentially Shawn Guo
  2 siblings, 0 replies; 4+ messages in thread
From: Shawn Guo @ 2013-11-01  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

The pllv3 nees relock not only when powering up but also when rate
changes.  The patch creates a helper function clk_pllv3_wait_lock() and
moves the relock code from clk_pllv3_prepare() into there, so that
both .prepare() and .set_rate() hooks of pllv3 can call into the helper
for relocking.

Since relock is only needed when PLL is powered up while clk_set_rate()
could be called before clk is prepared, we need to add a check in
clk_pllv3_wait_lock() to skip the relock if PLL is not powered.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/clk-pllv3.c |   43 ++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index c9ca191..df17362 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -46,21 +46,15 @@ struct clk_pllv3 {
 
 #define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
 
-static int clk_pllv3_prepare(struct clk_hw *hw)
+static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
 {
-	struct clk_pllv3 *pll = to_clk_pllv3(hw);
-	unsigned long timeout;
-	u32 val;
+	unsigned long timeout = jiffies + msecs_to_jiffies(10);
+	u32 val = readl_relaxed(pll->base) & BM_PLL_POWER;
 
-	val = readl_relaxed(pll->base);
-	val &= ~BM_PLL_BYPASS;
-	if (pll->powerup_set)
-		val |= BM_PLL_POWER;
-	else
-		val &= ~BM_PLL_POWER;
-	writel_relaxed(val, pll->base);
+	/* No need to wait for lock when pll is not powered up */
+	if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
+		return 0;
 
-	timeout = jiffies + msecs_to_jiffies(10);
 	/* Wait for PLL to lock */
 	do {
 		if (readl_relaxed(pll->base) & BM_PLL_LOCK)
@@ -70,10 +64,23 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
 		usleep_range(50, 500);
 	} while (1);
 
-	if (readl_relaxed(pll->base) & BM_PLL_LOCK)
-		return 0;
+	return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
+}
+
+static int clk_pllv3_prepare(struct clk_hw *hw)
+{
+	struct clk_pllv3 *pll = to_clk_pllv3(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->base);
+	val &= ~BM_PLL_BYPASS;
+	if (pll->powerup_set)
+		val |= BM_PLL_POWER;
 	else
-		return -ETIMEDOUT;
+		val &= ~BM_PLL_POWER;
+	writel_relaxed(val, pll->base);
+
+	return clk_pllv3_wait_lock(pll);
 }
 
 static void clk_pllv3_unprepare(struct clk_hw *hw)
@@ -148,7 +155,7 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
 	val |= div;
 	writel_relaxed(val, pll->base);
 
-	return 0;
+	return clk_pllv3_wait_lock(pll);
 }
 
 static const struct clk_ops clk_pllv3_ops = {
@@ -204,7 +211,7 @@ static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate,
 	val |= div;
 	writel_relaxed(val, pll->base);
 
-	return 0;
+	return clk_pllv3_wait_lock(pll);
 }
 
 static const struct clk_ops clk_pllv3_sys_ops = {
@@ -278,7 +285,7 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
 	writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
 	writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
 
-	return 0;
+	return clk_pllv3_wait_lock(pll);
 }
 
 static const struct clk_ops clk_pllv3_av_ops = {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] ARM: imx: set up pllv3 POWER and BYPASS sequentially
  2013-11-01  9:02 [PATCH 0/3] ARM: imx: pllv3 relock fixes Shawn Guo
  2013-11-01  9:02 ` [PATCH 1/3] ARM: imx: add sleep for pllv3 relock Shawn Guo
  2013-11-01  9:02 ` [PATCH 2/3] ARM: imx: pllv3 needs relock in .set_rate() call Shawn Guo
@ 2013-11-01  9:02 ` Shawn Guo
  2 siblings, 0 replies; 4+ messages in thread
From: Shawn Guo @ 2013-11-01  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, POWER and BYPASS bits are set up in a single write to pllv3
register.  This causes problem occasionally from the IPU/HDMI testing.
Let's follow FSL BSP code to set up POWER bit, relock, and then BYPASS
sequentially.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/clk-pllv3.c |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index df17362..6136405 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -71,16 +71,24 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
 {
 	struct clk_pllv3 *pll = to_clk_pllv3(hw);
 	u32 val;
+	int ret;
 
 	val = readl_relaxed(pll->base);
-	val &= ~BM_PLL_BYPASS;
 	if (pll->powerup_set)
 		val |= BM_PLL_POWER;
 	else
 		val &= ~BM_PLL_POWER;
 	writel_relaxed(val, pll->base);
 
-	return clk_pllv3_wait_lock(pll);
+	ret = clk_pllv3_wait_lock(pll);
+	if (ret)
+		return ret;
+
+	val = readl_relaxed(pll->base);
+	val &= ~BM_PLL_BYPASS;
+	writel_relaxed(val, pll->base);
+
+	return 0;
 }
 
 static void clk_pllv3_unprepare(struct clk_hw *hw)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-11-01  9:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-01  9:02 [PATCH 0/3] ARM: imx: pllv3 relock fixes Shawn Guo
2013-11-01  9:02 ` [PATCH 1/3] ARM: imx: add sleep for pllv3 relock Shawn Guo
2013-11-01  9:02 ` [PATCH 2/3] ARM: imx: pllv3 needs relock in .set_rate() call Shawn Guo
2013-11-01  9:02 ` [PATCH 3/3] ARM: imx: set up pllv3 POWER and BYPASS sequentially Shawn Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).