From: Gary McGee <gary.mc...@lsi.com> Signed-off-by: Gary McGee <gary.mc...@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"); +} -- 1.7.9.5 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto