[linux-yocto] [PATCH 31/57] arm/axxia: improved robustness for DDR retention

Bruce Ashfield bruce.ashfield at windriver.com
Tue Mar 18 14:38:05 PDT 2014


On 14-03-18 12:56 AM, Charlie Paul wrote:
> From: Gary McGee <gary.mcgee at lsi.com>

Again, we are missing the "what we changed" part of the commit log .. and
why it works!

Bruce

>
> Signed-off-by: Gary McGee <gary.mcgee at lsi.com>
> ---
>   arch/arm/mach-axxia/Makefile        |    2 +-
>   arch/arm/mach-axxia/ddr_retention.c |   96 ++++------
>   arch/arm/mach-axxia/ddr_shutdown.c  |  331 +++++++++++++++++++++++++++++++++++
>   3 files changed, 365 insertions(+), 64 deletions(-)
>   create mode 100644 arch/arm/mach-axxia/ddr_shutdown.c
>
> diff --git a/arch/arm/mach-axxia/Makefile b/arch/arm/mach-axxia/Makefile
> index 4d41b15..b4b8dd2 100644
> --- a/arch/arm/mach-axxia/Makefile
> +++ b/arch/arm/mach-axxia/Makefile
> @@ -7,7 +7,7 @@ obj-y                                   += io.o
>   obj-y					+= ncr.o
>   obj-y					+= timers.o
>   obj-y					+= pci.o
> -obj-y					+= ddr_retention.o
> +obj-y					+= ddr_retention.o ddr_shutdown.o
>   obj-$(CONFIG_I2C)			+= i2c.o
>   obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
>   obj-$(CONFIG_ARCH_AXXIA_GIC)		+= axxia-gic.o
> diff --git a/arch/arm/mach-axxia/ddr_retention.c b/arch/arm/mach-axxia/ddr_retention.c
> index bcedf33..35dbfcb 100644
> --- a/arch/arm/mach-axxia/ddr_retention.c
> +++ b/arch/arm/mach-axxia/ddr_retention.c
> @@ -36,7 +36,6 @@
>   static void __iomem *nca;
>   static void __iomem *apb;
>   static void __iomem *dickens;
> -static void __iomem *femac;
>   static int ddr_retention_enabled;
>
>   enum {
> @@ -229,60 +228,33 @@ static inline void cpu_disable_l2_prefetch(void)
>   }
>
>   static inline void
> -ncp_ddr_shutdown(unsigned long ctl_244)
> +reset_elm_trace(void)
>   {
> -	unsigned long value;
> -
> -	cpu_disable_l2_prefetch();
> -
> -	/*
> -	 * put SDRAM in self-refresh mode
> -	 */
> -	ncr_write(NCP_REGION_ID(34, 0), 0x3d0, 4, &ctl_244);
> -	ncr_write(NCP_REGION_ID(15, 0), 0x3d0, 4, &ctl_244);
> -
> -	/* check interrupt status for completion */
> -	/* CDR1 - word offset 0x104 (byte offset 0x410) */
> -	do {
> -		ncr_read(NCP_REGION_ID(34, 0), 0x410, 4, &value);
> -	} while ((value & 0x0200) == 0);
> +	/* reset and disable ELM trace */
> +	ncr_register_write(htonl(0x000fff04), (unsigned *) (apb + 0x68000));
> +	ncr_register_write(htonl(0x000fff04), (unsigned *) (apb + 0x78000));
>
> -	do {
> -		ncr_read(NCP_REGION_ID(15, 0), 0x410, 4, &value);
> -	} while ((value & 0x0200) == 0);
> -
> -	/*
> -	 Indicate DDR Retention Reset
> -	 */
> -
> -	/* set bit 0 of persist_scratch */
> -	writel_relaxed(0x00000001, apb + 0x300dc);
> +	/* reset ELM statistics */
> +	ncr_register_write(htonl(0x00001), (unsigned *) (apb + 0x60230));
> +	ncr_register_write(htonl(0x00001), (unsigned *) (apb + 0x70230));
>
> -	/*
> -	 * Issue Chip Reset
> -	 */
> +	/* enable ELM trace */
> +	ncr_register_write(htonl(0x000fff01), (unsigned *) (apb + 0x68000));
> +	ncr_register_write(htonl(0x000fff01), (unsigned *) (apb + 0x78000));
> +}
>
> -	/* Intrnl Boot, 0xffff0000 Target */
> -	writel_relaxed(0x00000040, apb + 0x31004);
> -	/* Set ResetReadDone */
> -	writel_relaxed(0x80000000, apb + 0x3180c);
> -	/* Chip Reset */
> -	writel_relaxed(0x00080802, apb + 0x31008);
>
> -	wfi();
> -	while (1)
> -		;
> -	__asm__ __volatile__("nop\n\t");
> +extern void ncp_ddr_shutdown(void *, void *,  unsigned long );
>
> -	return;
> -}
>
>   void
>   initiate_retention_reset(void)
>   {
>   	unsigned long ctl_244 = 0;
>   	unsigned long value;
> -	unsigned cpu_id;
> +	unsigned cpu_id ;
> +	volatile long tmp;
> +	volatile long *ptmp;
>
>   	if (0 == ddr_retention_enabled) {
>   		pr_info("DDR Retention Reset is Not Enabled\n");
> @@ -292,19 +264,17 @@ initiate_retention_reset(void)
>   	if (NULL == nca || NULL == apb || NULL == dickens)
>   		BUG();
>
> -	/* kill the femac */
> -	writel(0x80000000, (femac+0x2000));
> -	value = readl(femac + 0x2000);
> -
>   	preempt_disable();
>   	cpu_id = smp_processor_id();
> -	udelay(1000);
> +
>   	/* send stop message to other CPUs */
>   	local_irq_disable();
> +	local_fiq_disable();
>   	asm volatile ("dsb" : : : "memory");
>   	asm volatile ("dmb" : : : "memory");
>   	system_state = SYSTEM_RESTART;
>   	smp_send_stop();
> +	udelay(1000);
>
>   	flush_cache_all();
>   	flush_l3();
> @@ -314,11 +284,6 @@ initiate_retention_reset(void)
>   	quiesce_vp_engine(AXXIA_ENGINE_CNAL);
>
>
> -	/* disable sysmem interrupts */
> -	value = 0;
> -	ncr_write(NCP_REGION_ID(34, 0), 0x414, 4, &value);
> -	ncr_write(NCP_REGION_ID(15, 0), 0x414, 4, &value);
> -
>   	/* unlock reset register for later */
>   	writel(0x000000ab, apb + 0x31000); /* Access Key */
>
> @@ -327,21 +292,27 @@ initiate_retention_reset(void)
>   	ncr_read(NCP_REGION_ID(34, 0), 0x3d0, 4, &ctl_244);
>   	ctl_244 |= 0x000a0000;
>
> -
> -	/* put secondary CPUs into reset */
> +	/* belts & braces: put secondary CPUs into reset */
>   	value = ~(1 << cpu_id);
>   	value &= 0xffff;
>   	ncr_register_write(htonl(value), (unsigned *) (apb + 0x31030));
>
> -	/*
> -	 * issue instruction barrier
> -	 * this should cause the next few instructions to be fetched
> -	 * into cache
> -	 */
> -	asm volatile ("dsb" : : : "memory");
> +	/* load entire ddr_shutdown function into L2 cache */
> +	ptmp = (long *) ncp_ddr_shutdown;
> +	do {
> +		tmp += *ptmp++;
> +	} while (ptmp < (long*) (ncp_ddr_shutdown + 0x1000));
> +
>   	asm volatile ("isb" : : : "memory");
>
> -	ncp_ddr_shutdown(ctl_244);
> +	/* disable L2 prefetching */
> +	cpu_disable_l2_prefetch();
> +
> +	/* reset ELM DDR access trace buffer */
> +	reset_elm_trace();
> +
> +	/* call cache resident ddr shutdown function */
> +	ncp_ddr_shutdown(nca, apb, ctl_244);
>
>   	return;
>   }
> @@ -376,7 +347,6 @@ axxia_ddr_retention_init(void)
>   			apb = ioremap(0x2010000000, 0x80000);
>   			nca = ioremap(0x002020100000ULL, 0x20000);
>   			dickens = ioremap(0x2000000000, 0x1000000);
> -			femac = ioremap(0x2010120000, 0x10000);
>   			ddr_retention_enabled = 1;
>   			pr_info("DDR Retention Reset Initialized\n");
>   		}
> diff --git a/arch/arm/mach-axxia/ddr_shutdown.c b/arch/arm/mach-axxia/ddr_shutdown.c
> new file mode 100644
> index 0000000..6c6c3bb
> --- /dev/null
> +++ b/arch/arm/mach-axxia/ddr_shutdown.c
> @@ -0,0 +1,331 @@
> +
> +#include <asm/io.h>
> +
> +/*
> + * private copies of the ioread/write macros
> + * These are defined with a different barrier
> + * to avoid the outer_sync() call that's part
> + * of the normal barrier.
> + */
> +#define pvt_ioread32be(p)   ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); dsb(); __v; })
> +#define pvt_iowrite32be(v,p) ({ dsb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })
> +
> +#define pvt_ioread32(p)   ({ unsigned int __v = (__raw_readl(p)); dsb(); __v; })
> +#define pvt_iowrite32(v,p) ({ dsb(); __raw_writel((__force __u32)(v), p); })
> +
> +/* #define DDR_SHUTDOWN_DEBUG  */
> +#ifdef DDR_SHUTDOWN_DEBUG
> +#define dbg_write(v, p) pvt_iowrite32be(v,p)
> +#else
> +#define dbg_write(v, p)
> +#endif
> +
> +/*
> + * Wait For Completion timeout
> + * how many loops to wait for the config ring access to complete
> + */
> +#define WFC_TIMEOUT (400000)
> +
> +/*
> + * DDR status timeout
> + * how many times we read the DDR status waiting for self refresh complete
> + */
> +#define DDR_TIMEOUT (1000)
> +
> +void ncp_ddr_shutdown(void *nca, void *apb, unsigned long ctl_244)
> +{
> +	unsigned long value;
> +	int two_elms = 0;
> +	int wfc_loop = 0;
> +	int ddr_loop = 0;
> +
> +	/* determine if we are in one or two ELM/SMEM mode */
> +	value = pvt_ioread32(apb + 0x60004);
> +	two_elms = (value & 0x00000200);
> +
> +	/*
> +	 * Issue command to put SMEM0 into self-refresh mode
> +	 *
> +	 * ncpWrite 0x22.0.0x3d0
> +	 */
> +	dbg_write(0xaaaa0001, (unsigned *)(nca + 0x1200));
> +
> +	/* write register value into CDAR[0] */
> +	pvt_iowrite32be(ctl_244, (unsigned *)(nca + 0x1000));
> +	/* CDR2 - Node.target */
> +	pvt_iowrite32be(0x00002200, (unsigned *)(nca + 0xf8));
> +	/* CDR1 - word offset 0xf4 (byte offset 0x3d0) */
> +	pvt_iowrite32be(0x000000f4, (unsigned *)(nca + 0xf4));
> +	/* CDR0 - write command */
> +	pvt_iowrite32be(0x80050003, (unsigned *)(nca + 0xf0));
> +	wfc_loop = 0;
> +	do {
> +		if (wfc_loop++ > WFC_TIMEOUT) {
> +			dbg_write(value, (unsigned *)(nca + 0x11fc));
> +			dbg_write(0xffff0001, (unsigned *)(nca + 0x1200));
> +			goto do_reset;
> +		}
> +		dbg_write(wfc_loop, (unsigned *)(nca + 0x11f8));
> +		value = pvt_ioread32be((unsigned *)
> +				       (nca + 0xf0));
> +	} while ((0x80000000UL & value));
> +	dbg_write(0xaaaa0002, (unsigned *)(nca + 0x1200));
> +
> +	if (two_elms) {
> +		/*
> +		 * Issue command to put SMEM1 into self-refresh mode
> +		 *
> +		 * ncpWrite 0x0f.0.0x3d0
> +		 */
> +		/* CDR2 - Node.target */
> +		pvt_iowrite32be(0x00000f00, (unsigned *)(nca + 0xf8));
> +		/* CDR0 - write command */
> +		pvt_iowrite32be(0x80050003, (unsigned *)(nca + 0xf0));
> +		wfc_loop = 0;
> +		do {
> +			if (wfc_loop++ > WFC_TIMEOUT) {
> +				dbg_write(value, (unsigned *)(nca + 0x11fc));
> +				dbg_write(0xffff0002,
> +					  (unsigned *)(nca + 0x1200));
> +				goto do_reset;
> +			}
> +			value = pvt_ioread32be((unsigned *)
> +					       (nca + 0xf0));
> +		} while ((0x80000000UL & value));
> +	}
> +
> +	dbg_write(0xaaaa0003, (unsigned *)(nca + 0x1200));
> +
> +	/*
> +	 * Poll for SMEM0 refresh-mode command completion
> +	 */
> +	/* CDR1 - word offset 0x104 (byte offset 0x410) */
> +	pvt_iowrite32be(0x00000104, (unsigned *)(nca + 0xf4));
> +	/* CDR2 - Node.target */
> +	pvt_iowrite32be(0x00002200, (unsigned *)(nca + 0xf8));
> +	ddr_loop = 0;
> +	do {
> +		if (ddr_loop++ > DDR_TIMEOUT) {
> +			dbg_write(value, (unsigned *)(nca + 0x11fc));
> +			dbg_write(0xffff0003, (unsigned *)(nca + 0x1200));
> +			goto do_reset;
> +		}
> +		pvt_iowrite32be(wfc_loop, (unsigned *)
> +				(nca + 0x11f0));
> +
> +		/* issue config ring read */
> +		pvt_iowrite32be(0x80040003, (unsigned *)
> +				(nca + 0xf0));
> +		wfc_loop = 0;
> +		do {
> +			if (wfc_loop++ > WFC_TIMEOUT) {
> +				dbg_write(value, (unsigned *)(nca + 0x11fc));
> +				dbg_write(0xffff0004,
> +					  (unsigned *)(nca + 0x1200));
> +				goto do_reset;
> +			}
> +			value = pvt_ioread32be((unsigned *)
> +					       (nca + 0xf0));
> +		} while ((0x80000000UL & value));
> +
> +		value = pvt_ioread32be((unsigned *)
> +				       (nca + 0x1000));
> +
> +	} while ((value & 0x0200) == 0);
> +	dbg_write(0xaaaa0004, (unsigned *)(nca + 0x1200));
> +
> +	if (two_elms) {
> +		/*
> +		 * Poll for SMEM1 refresh-mode command completion
> +		 */
> +		/* CDR2 - Node.target */
> +		pvt_iowrite32be(0x00000f00, (unsigned *)(nca + 0xf8));
> +		ddr_loop = 0;
> +		do {
> +			if (ddr_loop++ > DDR_TIMEOUT) {
> +				dbg_write(value, (unsigned *)(nca + 0x11fc));
> +				dbg_write(0xffff0005,
> +					  (unsigned *)(nca + 0x1200));
> +				goto do_reset;
> +			}
> +
> +			/* issue config ring read */
> +			pvt_iowrite32be(0x80040003, (unsigned *)(nca + 0xf0));
> +			wfc_loop = 0;
> +			do {
> +				if (wfc_loop++ > WFC_TIMEOUT) {
> +					dbg_write(value,
> +						  (unsigned *)(nca + 0x11fc));
> +					dbg_write(0xffff0006,
> +						  (unsigned *)(nca + 0x1200));
> +					goto do_reset;
> +				}
> +				value =
> +				    pvt_ioread32be((unsigned *)(nca + 0xf0));
> +			} while ((0x80000000UL & value));
> +
> +			value = pvt_ioread32be((unsigned *)
> +					       (nca + 0x1000));
> +			wfc_loop++;
> +		} while ((value & 0x0200) == 0);
> +	}
> +
> +	dbg_write(0xaaaa0005, (unsigned *)(nca + 0x1200));
> +
> +	/*
> +	 * Tell U-Boot to do a DDR retention-reset
> +	 * (i.e. set bit 0 of persist_scratch register)
> +	 */
> +	pvt_iowrite32(0x00000001, apb + 0x300dc);
> +
> +	dbg_write(0xaaaa0006, (unsigned *)(nca + 0x1200));
> +      do_reset:
> +	/*
> +	 * Issue Chip reset
> +	 */
> +	/* Intrnl Boot, 0xffff0000 Target */
> +	pvt_iowrite32(0x00000040, apb + 0x31004);
> +	/* Set ResetReadDone */
> +	pvt_iowrite32(0x80000000, apb + 0x3180c);
> +	/* Chip Reset */
> +	pvt_iowrite32(0x00080802, apb + 0x31008);
> +
> +	while(1);
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +
> +	return;
> +}
> +
> +void ncp_ddr_shutdown_dummy(void)
> +{
> +	wfi();
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +	__asm__ __volatile__(" nop \n\t");
> +}
>



More information about the linux-yocto mailing list