[linux-yocto] [PATCH 09/39] LSI AXXIA: fixes for VP engine quiesce and DDR shutdown

Charlie Paul cpaul.windriver at gmail.com
Fri Apr 11 14:13:10 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