diff mbox

[3/3] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.

Message ID 1423116129-6026-1-git-send-email-wenyou.yang@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wenyou Yang Feb. 5, 2015, 6:02 a.m. UTC
From: Peter Rosin <peda@axentia.se>

The DDRSDR controller fails miserably to put LPDDR1 memories in
self-refresh. Force the controller to think it has DDR2 memories
during the self-refresh period, as the DDR2 self-refresh spec is
equivalent to LPDDR1, and is correctly implemented in the
controller.

Assume that the second controller has the same fault, but that is
untested.

Signed-off-by: Peter Rosin <peda@axentia.se>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/pm_slowclock.S  |   43 +++++++++++++++++++++++++++++++-----
 include/soc/at91/at91sam9_ddrsdr.h |    2 +-
 2 files changed, 39 insertions(+), 6 deletions(-)

Comments

Nicolas Ferre March 3, 2015, 6:41 p.m. UTC | #1
Le 05/02/2015 07:02, Wenyou Yang a écrit :
> From: Peter Rosin <peda@axentia.se>
> 
> The DDRSDR controller fails miserably to put LPDDR1 memories in
> self-refresh. Force the controller to think it has DDR2 memories
> during the self-refresh period, as the DDR2 self-refresh spec is
> equivalent to LPDDR1, and is correctly implemented in the
> controller.
> 
> Assume that the second controller has the same fault, but that is
> untested.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Stacked in at91-4.0-fixes.

Bye,


> ---
>  arch/arm/mach-at91/pm_slowclock.S  |   43 +++++++++++++++++++++++++++++++-----
>  include/soc/at91/at91sam9_ddrsdr.h |    2 +-
>  2 files changed, 39 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
> index 75d8b19..487ae1e 100644
> --- a/arch/arm/mach-at91/pm_slowclock.S
> +++ b/arch/arm/mach-at91/pm_slowclock.S
> @@ -109,6 +109,16 @@ ddr_sr_enable:
>  	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
>  	bne	sdr_sr_enable
>  
> +	/* LPDDR1 --> force DDR2 mode during self-refresh */
> +	ldr	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
> +	str	tmp1, .saved_sam9_mdr
> +	bic	tmp1, tmp1, #~AT91_DDRSDRC_MD
> +	cmp	tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
> +	ldreq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
> +	biceq	tmp1, tmp1, #AT91_DDRSDRC_MD
> +	orreq	tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
> +	streq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
> +
>  	/* prepare for DDRAM self-refresh mode */
>  	ldr	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
>  	str	tmp1, .saved_sam9_lpr
> @@ -117,14 +127,26 @@ ddr_sr_enable:
>  
>  	/* figure out if we use the second ram controller */
>  	cmp	ramc1, #0
> -	ldrne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
> -	strne	tmp2, .saved_sam9_lpr1
> -	bicne	tmp2, #AT91_DDRSDRC_LPCB
> -	orrne	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
> +	beq	ddr_no_2nd_ctrl
> +
> +	ldr	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
> +	str	tmp2, .saved_sam9_mdr1
> +	bic	tmp2, tmp2, #~AT91_DDRSDRC_MD
> +	cmp	tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
> +	ldreq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
> +	biceq	tmp2, tmp2, #AT91_DDRSDRC_MD
> +	orreq	tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
> +	streq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
> +
> +	ldr	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
> +	str	tmp2, .saved_sam9_lpr1
> +	bic	tmp2, #AT91_DDRSDRC_LPCB
> +	orr	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
>  
>  	/* Enable DDRAM self-refresh mode */
> +	str	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
> +ddr_no_2nd_ctrl:
>  	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
> -	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
>  
>  	b	sdr_sr_done
>  
> @@ -236,12 +258,17 @@ sdr_sr_done:
>  	 */
>  	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
>  	bne	sdr_en_restore
> +	/* Restore MDR in case of LPDDR1 */
> +	ldr	tmp1, .saved_sam9_mdr
> +	str	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
>  	/* Restore LPR on AT91 with DDRAM */
>  	ldr	tmp1, .saved_sam9_lpr
>  	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
>  
>  	/* if we use the second ram controller */
>  	cmp	ramc1, #0
> +	ldrne	tmp2, .saved_sam9_mdr1
> +	strne	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
>  	ldrne	tmp2, .saved_sam9_lpr1
>  	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
>  
> @@ -272,5 +299,11 @@ ram_restored:
>  .saved_sam9_lpr1:
>  	.word 0
>  
> +.saved_sam9_mdr:
> +	.word 0
> +
> +.saved_sam9_mdr1:
> +	.word 0
> +
>  ENTRY(at91_slow_clock_sz)
>  	.word .-at91_slow_clock
> diff --git a/include/soc/at91/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h
> index 0210797..dc10c52 100644
> --- a/include/soc/at91/at91sam9_ddrsdr.h
> +++ b/include/soc/at91/at91sam9_ddrsdr.h
> @@ -92,7 +92,7 @@
>  #define		AT91_DDRSDRC_UPD_MR	(3 << 20)	 /* Update load mode register and extended mode register */
>  
>  #define AT91_DDRSDRC_MDR	0x20	/* Memory Device Register */
> -#define		AT91_DDRSDRC_MD		(3 << 0)		/* Memory Device Type */
> +#define		AT91_DDRSDRC_MD		(7 << 0)	/* Memory Device Type */
>  #define			AT91_DDRSDRC_MD_SDR		0
>  #define			AT91_DDRSDRC_MD_LOW_POWER_SDR	1
>  #define			AT91_DDRSDRC_MD_LOW_POWER_DDR	3
>
diff mbox

Patch

diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index 75d8b19..487ae1e 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -109,6 +109,16 @@  ddr_sr_enable:
 	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
 	bne	sdr_sr_enable
 
+	/* LPDDR1 --> force DDR2 mode during self-refresh */
+	ldr	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+	str	tmp1, .saved_sam9_mdr
+	bic	tmp1, tmp1, #~AT91_DDRSDRC_MD
+	cmp	tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+	ldreq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+	biceq	tmp1, tmp1, #AT91_DDRSDRC_MD
+	orreq	tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+	streq	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
 	/* prepare for DDRAM self-refresh mode */
 	ldr	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 	str	tmp1, .saved_sam9_lpr
@@ -117,14 +127,26 @@  ddr_sr_enable:
 
 	/* figure out if we use the second ram controller */
 	cmp	ramc1, #0
-	ldrne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-	strne	tmp2, .saved_sam9_lpr1
-	bicne	tmp2, #AT91_DDRSDRC_LPCB
-	orrne	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+	beq	ddr_no_2nd_ctrl
+
+	ldr	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+	str	tmp2, .saved_sam9_mdr1
+	bic	tmp2, tmp2, #~AT91_DDRSDRC_MD
+	cmp	tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+	ldreq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+	biceq	tmp2, tmp2, #AT91_DDRSDRC_MD
+	orreq	tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+	streq	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+	ldr	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+	str	tmp2, .saved_sam9_lpr1
+	bic	tmp2, #AT91_DDRSDRC_LPCB
+	orr	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
 	/* Enable DDRAM self-refresh mode */
+	str	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
 	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
 	b	sdr_sr_done
 
@@ -236,12 +258,17 @@  sdr_sr_done:
 	 */
 	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
 	bne	sdr_en_restore
+	/* Restore MDR in case of LPDDR1 */
+	ldr	tmp1, .saved_sam9_mdr
+	str	tmp1, [sdramc, #AT91_DDRSDRC_MDR]
 	/* Restore LPR on AT91 with DDRAM */
 	ldr	tmp1, .saved_sam9_lpr
 	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
 	/* if we use the second ram controller */
 	cmp	ramc1, #0
+	ldrne	tmp2, .saved_sam9_mdr1
+	strne	tmp2, [ramc1, #AT91_DDRSDRC_MDR]
 	ldrne	tmp2, .saved_sam9_lpr1
 	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -272,5 +299,11 @@  ram_restored:
 .saved_sam9_lpr1:
 	.word 0
 
+.saved_sam9_mdr:
+	.word 0
+
+.saved_sam9_mdr1:
+	.word 0
+
 ENTRY(at91_slow_clock_sz)
 	.word .-at91_slow_clock
diff --git a/include/soc/at91/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h
index 0210797..dc10c52 100644
--- a/include/soc/at91/at91sam9_ddrsdr.h
+++ b/include/soc/at91/at91sam9_ddrsdr.h
@@ -92,7 +92,7 @@ 
 #define		AT91_DDRSDRC_UPD_MR	(3 << 20)	 /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR	0x20	/* Memory Device Register */
-#define		AT91_DDRSDRC_MD		(3 << 0)		/* Memory Device Type */
+#define		AT91_DDRSDRC_MD		(7 << 0)	/* Memory Device Type */
 #define			AT91_DDRSDRC_MD_SDR		0
 #define			AT91_DDRSDRC_MD_LOW_POWER_SDR	1
 #define			AT91_DDRSDRC_MD_LOW_POWER_DDR	3