[linux-yocto] [PATCH 09/39] LSI AXXIA: fixes for VP engine quiesce and DDR shutdown
Charlie Paul
cpaul.windriver at gmail.com
Tue Apr 22 13:59:21 PDT 2014
From: Gary McGee <gary.mcgee at lsi.com>
---
arch/arm/mach-axxia/ddr_retention.c | 187 ++++++++++++++++++++---------------
arch/arm/mach-axxia/ncr.c | 18 +++-
2 files changed, 121 insertions(+), 84 deletions(-)
diff --git a/arch/arm/mach-axxia/ddr_retention.c b/arch/arm/mach-axxia/ddr_retention.c
index 933ff6d..bcedf33 100644
--- a/arch/arm/mach-axxia/ddr_retention.c
+++ b/arch/arm/mach-axxia/ddr_retention.c
@@ -36,9 +36,15 @@
static void __iomem *nca;
static void __iomem *apb;
static void __iomem *dickens;
+static void __iomem *femac;
static int ddr_retention_enabled;
-static unsigned long
+enum {
+ AXXIA_ENGINE_CAAL,
+ AXXIA_ENGINE_CNAL
+};
+
+unsigned long
ncp_caal_regions_acp55xx[] = {
NCP_REGION_ID(0x0b, 0x05), /* SPPV2 */
NCP_REGION_ID(0x0c, 0x05), /* SED */
@@ -57,6 +63,11 @@ ncp_caal_regions_acp55xx[] = {
NCP_REGION_ID(0x1c, 0x05), /* PAB */
NCP_REGION_ID(0x1f, 0x05), /* EIOAM0 */
NCP_REGION_ID(0x31, 0x05), /* ISB */
+ NCP_REGION_ID(0xff, 0xff)
+};
+
+unsigned long
+ncp_cnal_regions_acp55xx[] = {
NCP_REGION_ID(0x28, 0x05), /* EIOASM0 */
NCP_REGION_ID(0x29, 0x05), /* EIOASM1 */
NCP_REGION_ID(0x2a, 0x05), /* EIOAS2 */
@@ -67,6 +78,7 @@ ncp_caal_regions_acp55xx[] = {
NCP_REGION_ID(0xff, 0xff)
};
+
/*
------------------------------------------------------------------------------
flush_l3
@@ -128,17 +140,36 @@ flush_l3(void)
}
static void
-quiesce_vp_engine(void)
+quiesce_vp_engine(int engineType)
{
- unsigned long *pCnalRegions = ncp_caal_regions_acp55xx;
- unsigned long *pRegion;
+ unsigned long *pEngineRegions;
+ unsigned long ortOff, owtOff;
+ unsigned long *pRegion;
unsigned ort, owt;
- unsigned long buf = 0;
- unsigned short node, target;
- int loop;
+ unsigned long buf = 0;
+ unsigned short node, target;
+ int loop;
pr_info("quiescing VP engines...\n");
- pRegion = pCnalRegions;
+
+ switch (engineType) {
+ case AXXIA_ENGINE_CNAL:
+ pEngineRegions = ncp_cnal_regions_acp55xx;
+ ortOff = 0x1c0;
+ owtOff = 0x1c4;
+ break;
+
+ case AXXIA_ENGINE_CAAL:
+ pEngineRegions = ncp_caal_regions_acp55xx;
+ ortOff = 0xf8;
+ owtOff = 0xfc;
+ break;
+
+ default:
+ return;
+ }
+
+ pRegion = pEngineRegions;
while (*pRegion != NCP_REGION_ID(0xff, 0xff)) {
/* set read/write transaction limits to zero */
@@ -147,15 +178,15 @@ quiesce_vp_engine(void)
pRegion++;
}
- pRegion = pCnalRegions;
+ pRegion = pEngineRegions;
loop = 0;
while (*pRegion != NCP_REGION_ID(0xff, 0xff)) {
node = (*pRegion & 0xffff0000) >> 16;
target = *pRegion & 0x0000ffff;
/* read the number of outstanding read/write transactions */
- ncr_read(*pRegion, 0xf8, 4, &ort);
- ncr_read(*pRegion, 0xfc, 4, &owt);
+ ncr_read(*pRegion, ortOff, 4, &ort);
+ ncr_read(*pRegion, owtOff, 4, &owt);
if ((ort == 0) && (owt == 0)) {
/* this engine has been quiesced, move on to the next */
@@ -164,8 +195,9 @@ quiesce_vp_engine(void)
pRegion++;
} else {
if (loop++ > 10000) {
- pr_info("Unable to quiesce region 0x%02x.0x%02x ort=0x%x, owt=0x%x\n",
- node, target, ort, owt);
+ pr_info(
+ "Unable to quiesce region 0x%02x.0x%02x ort=0x%x, owt=0x%x\n",
+ node, target, ort, owt);
pRegion++;
loop = 0;
continue;
@@ -176,76 +208,71 @@ quiesce_vp_engine(void)
return;
}
+static inline void cpu_disable_l2_prefetch(void)
+{
+ unsigned int v;
+
+ /*
+ * MRC p15, 1, <Rt>, c15, c0, 3; Read L2 Prefetch Control Register
+ * MCR p15, 1, <Rt>, c15, c0, 3; Write L2 Prefetch Control Register
+ *
+ */
+ asm volatile(
+ " mrc p15, 1, %0, c15, c0, 3\n"
+ " and %0, %0, #0x0000\n"
+ " mcr p15, 1, %0, c15, c0, 3\n"
+ : "=&r" (v)
+ :
+ : "cc");
+
+ isb();
+}
+
static inline void
-ncp_ddr_shutdown(void)
+ncp_ddr_shutdown(unsigned long ctl_244)
{
unsigned long value;
- int loop = 1;
- unsigned long cdr2[2] = {0x00002200, 0x00000f00};
- int smId;
+ cpu_disable_l2_prefetch();
/*
- * Most of the PIO command has already been set up.
- * issue config ring write - enter DDR self-refresh mode
+ * put SDRAM in self-refresh mode
*/
-
- for (smId = 0; smId < 2; smId++) {
- /* CDR2 - Node.target */
- ncr_register_write(cdr2[smId], (unsigned *) (nca + 0xf8));
- /* CDR0 - */
- ncr_register_write(0x80050003, (unsigned *) (nca + 0xf0));
- do {
- value = ncr_register_read((unsigned *)
- (nca + 0xf0));
- } while ((0x80000000UL & value));
- }
+ 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) */
- ncr_register_write(0x00000104, (unsigned *) (nca + 0xf4));
+ do {
+ ncr_read(NCP_REGION_ID(34, 0), 0x410, 4, &value);
+ } while ((value & 0x0200) == 0);
- for (smId = 0; smId < 2; smId++) {
- /* CDR2 - Node.target */
- ncr_register_write(cdr2[smId], (unsigned *) (nca + 0xf8));
- do {
- ncr_register_write(loop, (unsigned *)
- (nca + 0x11f0));
-
- /* issue config ring read */
- ncr_register_write(0x80040003, (unsigned *)
- (nca + 0xf0));
- do {
- value = ncr_register_read((unsigned *)
- (nca + 0xf0));
- } while ((0x80000000UL & value));
-
- value = ncr_register_read((unsigned *)
- (nca + 0x1000));
- ncr_register_write(value, (unsigned *)
- (nca + 0x1200));
-
- loop++;
- } while ((value & 0x0200) == 0);
- }
+ do {
+ ncr_read(NCP_REGION_ID(15, 0), 0x410, 4, &value);
+ } while ((value & 0x0200) == 0);
/*
- Indicate DDR Retention Reset
- */
+ Indicate DDR Retention Reset
+ */
/* set bit 0 of persist_scratch */
- writel(0x00000001, apb + 0x300dc);
+ writel_relaxed(0x00000001, apb + 0x300dc);
/*
- Issue Chip Reset
- */
+ * Issue Chip Reset
+ */
/* Intrnl Boot, 0xffff0000 Target */
- writel(0x00000040, apb + 0x31004);
+ writel_relaxed(0x00000040, apb + 0x31004);
/* Set ResetReadDone */
- writel(0x80000000, apb + 0x3180c);
+ writel_relaxed(0x80000000, apb + 0x3180c);
/* Chip Reset */
- writel(0x00080802, apb + 0x31008);
+ writel_relaxed(0x00080802, apb + 0x31008);
+
+ wfi();
+ while (1)
+ ;
+ __asm__ __volatile__("nop\n\t");
return;
}
@@ -255,6 +282,7 @@ initiate_retention_reset(void)
{
unsigned long ctl_244 = 0;
unsigned long value;
+ unsigned cpu_id;
if (0 == ddr_retention_enabled) {
pr_info("DDR Retention Reset is Not Enabled\n");
@@ -264,6 +292,13 @@ 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();
asm volatile ("dsb" : : : "memory");
@@ -275,10 +310,11 @@ initiate_retention_reset(void)
flush_l3();
/* TODO - quiesce VP engines */
- quiesce_vp_engine();
+ quiesce_vp_engine(AXXIA_ENGINE_CAAL);
+ quiesce_vp_engine(AXXIA_ENGINE_CNAL);
+
/* disable sysmem interrupts */
- pr_info("disabling sysmem interrupts\n");
value = 0;
ncr_write(NCP_REGION_ID(34, 0), 0x414, 4, &value);
ncr_write(NCP_REGION_ID(15, 0), 0x414, 4, &value);
@@ -292,18 +328,10 @@ initiate_retention_reset(void)
ctl_244 |= 0x000a0000;
- /*
- * set up for CRBW operation
- */
-
- /* write register value into CDAR[0] */
- ncr_register_write(ctl_244, (unsigned *) (nca + 0x1000));
-
- /* CDR2 - Node.target = 34.0 */
- ncr_register_write(0x00002200, (unsigned *) (nca + 0xf8));
-
- /* CDR1 - word offset 0xf4 (byte offset 0x3d0) */
- ncr_register_write(0x000000f4, (unsigned *) (nca + 0xf4));
+ /* put secondary CPUs into reset */
+ value = ~(1 << cpu_id);
+ value &= 0xffff;
+ ncr_register_write(htonl(value), (unsigned *) (apb + 0x31030));
/*
* issue instruction barrier
@@ -311,9 +339,9 @@ initiate_retention_reset(void)
* into cache
*/
asm volatile ("dsb" : : : "memory");
- prefetch_range(ncp_ddr_shutdown, 0x1000);
+ asm volatile ("isb" : : : "memory");
- ncp_ddr_shutdown();
+ ncp_ddr_shutdown(ctl_244);
return;
}
@@ -345,9 +373,10 @@ axxia_ddr_retention_init(void)
S_IWUSR, NULL, &axxia_ddr_retention_proc_ops)) {
pr_info("Failed to register DDR retention proc entry\n");
} else {
- apb = ioremap(0x2010000000, 0x40000);
+ 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/ncr.c b/arch/arm/mach-axxia/ncr.c
index 4112038..51fcf66 100644
--- a/arch/arm/mach-axxia/ncr.c
+++ b/arch/arm/mach-axxia/ncr.c
@@ -92,11 +92,18 @@ typedef union {
#ifdef CONFIG_ARM
/*
+ * like iowrite32be but without the barrier.
+ * The iowmb barrier in the standard macro includes a outer_cache_sync
+ * which we don't want for Axxia register IO.
+ */
+#define axxia_write32be(v,p) ({ __raw_writel((__force __u32)cpu_to_be32(v), p); })
+
+/*
----------------------------------------------------------------------
ncr_register_read
*/
-unsigned long
+inline unsigned long
ncr_register_read(unsigned *address)
{
unsigned long value;
@@ -112,9 +119,10 @@ ncr_register_read(unsigned *address)
*/
void
-ncr_register_write(const unsigned value, unsigned *address)
+inline ncr_register_write(const unsigned value, unsigned *address)
{
- iowrite32be(value, address);
+ axxia_write32be(value, address);
+ asm volatile ("mcr p15,0,%0,c7,c5,4" : : "r" (0)); /* isb */
return;
}
@@ -126,7 +134,7 @@ ncr_register_write(const unsigned value, unsigned *address)
ncr_register_read
*/
-unsigned long
+inline unsigned long
ncr_register_read(unsigned *address)
{
unsigned long value;
@@ -141,7 +149,7 @@ ncr_register_read(unsigned *address)
ncr_register_write
*/
-void
+inline void
ncr_register_write(const unsigned value, unsigned *address)
{
out_be32(address, value);
--
1.7.9.5
More information about the linux-yocto
mailing list