[PATCH]: at91 slowclock: fix two bugs when disabling the PLLs

From: Julien Langer
Date: Tue Dec 01 2009 - 02:22:57 EST


Hi,

attached are two patches which fix two problems with the at91 slowclock code:

the first one fixes a problem during suspend: When turning off the
PLLs, wait for the LOCKA/LOCKB flags to be unset instead of being set
(which will never happen).

The second patch fixes a problem of trying to turn on/off a PLL which
was already disabled: ohci-at91 disables PLLB when going to suspend.
The slowclock code however tries to do the same. In that case the
slowclock code just stores and restores a 0 to the PLLB register which
results in the wait_pllblock loop to hang until it reaches the
timeout. This patches fixes the problem by only restoring the
PLLA/PLLB registers when they were != 0.


PS: please CC me, I'm not on the list.
at91: when turning off the plls during suspend, don't wait for the lock

flag to be set, instead wait for it to be unset. Previously the code would
always run into the loop limitation of 1000 iterations because the flag is
never set when turning the plls off.

Signed-off-by: Julien Langer <julien.langer@xxxxxxxxx>
---

arch/arm/mach-at91/pm_slowclock.S | 35 ++++++++++++++++++++++++++++++++---
1 files changed, 32 insertions(+), 3 deletions(-)


diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index 987fab3..dc6d730 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -45,7 +45,9 @@
#define MCKRDY_TIMEOUT 1000
#define MOSCRDY_TIMEOUT 1000
#define PLLALOCK_TIMEOUT 1000
+#define PLLAUNLOCK_TIMEOUT 1000
#define PLLBLOCK_TIMEOUT 1000
+#define PLLBUNLOCK_TIMEOUT 1000


/*
@@ -91,6 +93,20 @@
.endm

/*
+ * Wait until PLLA has unlocked.
+ */
+ .macro wait_pllaunlock
+ mov r4, #PLLAUNLOCK_TIMEOUT
+1: sub r4, r4, #1
+ cmp r4, #0
+ beq 2f
+ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+ tst r3, #AT91_PMC_LOCKA
+ bne 1b
+2:
+ .endm
+
+/*
* Wait until PLLB has locked.
*/
.macro wait_pllblock
@@ -104,6 +120,20 @@
2:
.endm

+/*
+ * Wait until PLLB has unlocked.
+ */
+ .macro wait_pllbunlock
+ mov r4, #PLLBUNLOCK_TIMEOUT
+1: sub r4, r4, #1
+ cmp r4, #0
+ beq 2f
+ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
+ tst r3, #AT91_PMC_LOCKB
+ bne 1b
+2:
+ .endm
+
.text

ENTRY(at91_slow_clock)
@@ -175,7 +205,7 @@ ENTRY(at91_slow_clock)
orr r3, r3, #(1 << 29) /* bit 29 always set */
str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]

- wait_pllalock
+ wait_pllaunlock

/* Save PLLB setting and disable it */
ldr r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
@@ -183,8 +213,7 @@ ENTRY(at91_slow_clock)

mov r3, #AT91_PMC_PLLCOUNT
str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
-
- wait_pllblock
+ wait_pllbunlock

/* Turn off the main oscillator */
ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
at91: Don't try to restore the PLL settings when the PLLs were turned off

previously.

We run into this problem with the PLLB on the at91: ohci-at91 disables the PLLB
when going to suspend. The slowclock code however tries to do the same: It
saves the PLLB register value and when restoring the value during resume, it
wait's for the PLLB to lock again. However the PLL will never lock and the loop
would run into it's timeout because the slowclock code just stored and restored
an empty register.
This fixes the problem by only restoring PLLA/PLLB when the registers were != 0.

Signed-off-by: Julien Langer <julien.langer@xxxxxxxxx>
---

arch/arm/mach-at91/pm_slowclock.S | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)


diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index dc6d730..dbc8f0a 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -201,20 +201,28 @@ ENTRY(at91_slow_clock)
ldr r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
str r3, .saved_pllar

+ cmp r3, #0
+ beq 3f
+
mov r3, #AT91_PMC_PLLCOUNT
orr r3, r3, #(1 << 29) /* bit 29 always set */
str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]

wait_pllaunlock

+3:
/* Save PLLB setting and disable it */
ldr r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
str r3, .saved_pllbr

+ cmp r3, #0
+ beq 4f
+
mov r3, #AT91_PMC_PLLCOUNT
str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
wait_pllbunlock

+4:
/* Turn off the main oscillator */
ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
bic r3, r3, #AT91_PMC_MOSCEN
@@ -232,16 +240,22 @@ ENTRY(at91_slow_clock)

/* Restore PLLB setting */
ldr r3, .saved_pllbr
+ cmp r3, #0
+ beq 5f
str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]

wait_pllblock

+5:
/* Restore PLLA setting */
ldr r3, .saved_pllar
+ cmp r3, #0
+ beq 6f
str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]

wait_pllalock

+6:
#ifdef SLOWDOWN_MASTER_CLOCK
/*
* First set PRES if it was not 0,