[linux-yocto] [PATCH 05/35] arch/powerpc: Update the Axxia NAND Driver for 3500

Daniel Dragomir daniel.dragomir at windriver.com
Thu Nov 13 09:19:32 PST 2014


From: John Jacques <john.jacques at lsi.com>

Signed-off-by: John Jacques <john.jacques at lsi.com>
---
 drivers/mtd/nand/lsi_acp_nand.c | 174 +++++++++++++++++++---------------------
 1 file changed, 84 insertions(+), 90 deletions(-)

diff --git a/drivers/mtd/nand/lsi_acp_nand.c b/drivers/mtd/nand/lsi_acp_nand.c
index dbb95b5..3f9e79d 100644
--- a/drivers/mtd/nand/lsi_acp_nand.c
+++ b/drivers/mtd/nand/lsi_acp_nand.c
@@ -342,16 +342,11 @@ _WRITEL(const char *file, int line, unsigned long value, unsigned long address)
 */
 
 static void *gpreg_base;
-
-#define LSI_NAND_PECC_BUSY_REGISTER (gpreg_base + 0x00c)
-
-#ifdef CONFIG_ACP_X1V1
-#define LSI_NAND_PECC_BUSY_MASK	    (1 << 25)
-#else
-#define LSI_NAND_PECC_BUSY_MASK	    (1 << 28)
-#endif
+static void *pecc_busy_register;
+static unsigned long pecc_busy_mask;
 
 #define MAX_READ_BUF	16
+
 /*
   ----------------------------------------------------------------------
   MTD structures
@@ -602,17 +597,6 @@ lsi_nand_command(struct mtd_info *mtd, unsigned int command,
 	unsigned int status = 0;
 	struct lsi_nand_private *priv = &lsi_nand_private;
 	struct device_node *np = NULL;
-	void *busy_reg;
-	unsigned long busy_mask;
-
-	np = of_find_compatible_node(NULL, NULL, "lsi,acp3500");
-	if (NULL != np) {
-		busy_reg = (gpreg_base + 0x80);
-		busy_mask = (1 << 20);
-	} else {
-		busy_reg = LSI_NAND_PECC_BUSY_REGISTER;
-		busy_mask = LSI_NAND_PECC_BUSY_MASK;
-	}
 
 	DEBUG_PRINT("command=0x%x\n", command);
 	command &= 0xff;
@@ -717,8 +701,8 @@ lsi_nand_command(struct mtd_info *mtd, unsigned int command,
 			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
 		do {
 			udelay(chip->chip_delay);
-			status = READL((void *)busy_reg);
-		} while (0 != (status & busy_mask));
+			status = READL((void *)pecc_busy_register);
+		} while (0 != (status & pecc_busy_mask));
 
 		/* wait until CHIP_BUSY goes low */
 		do {
@@ -815,17 +799,6 @@ static int lsi_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	unsigned long status = 0;
 	loff_t offset = 0;
 	struct device_node *np = NULL;
-	void *busy_reg;
-	unsigned long busy_mask;
-
-	np = of_find_compatible_node(NULL, NULL, "lsi,acp3500");
-	if (NULL != np) {
-		busy_reg = (gpreg_base + 0x80);
-		busy_mask = (1 << 20);
-	} else {
-		busy_reg = LSI_NAND_PECC_BUSY_REGISTER;
-		busy_mask = LSI_NAND_PECC_BUSY_MASK;
-	}
 
 	/*
 	  When reading or writing, wait for the
@@ -834,9 +807,9 @@ static int lsi_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 #ifdef NOT_USED
 	if (FL_READING == chip->state || FL_WRITING == chip->state) {
 		for (;;) {
-			status = READL((void *)busy_reg);
+			status = READL((void *)pecc_busy_register);
 
-			if (0 == (status & busy_mask))
+			if (0 == (status & pecc_busy_mask))
 				break;
 
 			udelay(chip->chip_delay);
@@ -844,9 +817,9 @@ static int lsi_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	}
 #else
 	for (;;) {
-		status = READL((void *)busy_reg);
+		status = READL((void *)pecc_busy_register);
 
-		if (0 == (status & busy_mask))
+		if (0 == (status & pecc_busy_mask))
 			break;
 
 		udelay(chip->chip_delay);
@@ -3455,7 +3428,16 @@ lsi_nand_init(void)
 	struct device_node *np = NULL;
 	struct mtd_part_parser_data ppdata;
 	static const char *part_probe_types[]
-	= { "cmdlinepart", "ofpart", NULL };
+		= { "cmdlinepart", "ofpart", NULL };
+	const u32 *reg;
+	int reglen;
+	u64 nand_address;
+	unsigned long nand_length;
+	u64 gpreg_address;
+	unsigned long gpreg_length;
+	const u32 *enabled;
+	unsigned long cr;
+	unsigned long cr_save;
 
 	memset(&ppdata, 0, sizeof(ppdata));
 
@@ -3464,45 +3446,62 @@ lsi_nand_init(void)
 	while (np && !of_device_is_compatible(np, "acp-nand"))
 		np = of_find_node_by_type(np, "nand");
 
-	if (np) {
-		const u32 *reg;
-		int reglen;
-		u64 nand_address;
-		unsigned long nand_length;
-		u64 gpreg_address;
-		unsigned long gpreg_length;
-		const u32 *enabled;
+	if (NULL == np) {
+		printk(KERN_ERR "No NAND Nodes in Device Tree\n");
 
-		enabled = of_get_property(np, "enabled", NULL);
+		return -1;
+	}
 
-		if (!enabled || (enabled && (0 == *enabled))) {
-			pr_err("ACP NAND Controller Isn't Enabled.\n");
-			return -ENODEV;
-		}
+	enabled = of_get_property(np, "enabled", NULL);
 
-		reg = of_get_property(np, "reg", &reglen);
-
-		if (reg && (16 == reglen)) {
-			nand_address = of_translate_address(np, reg);
-			nand_length = reg[1];
-			reg += 2;
-			gpreg_address = of_translate_address(np, reg);
-			gpreg_length = reg[1];
-			pr_info("nand_address=0x%08llx nand_length=0x%lx\n"
-				"gpreg_address=0x%08llx gpreg_length=0x%lx\n",
-				nand_address, nand_length,
-				gpreg_address, gpreg_length);
-			nand_base = ioremap(nand_address, nand_length);
-			gpreg_base = ioremap(gpreg_address, gpreg_length);
-		} else {
-			return -1;
-		}
+	if (!enabled || (enabled && (0 == *enabled))) {
+		pr_err("ACP NAND Controller Isn't Enabled.\n");
+		return -ENODEV;
+	}
 
-		ppdata.of_node = np;
+	reg = of_get_property(np, "reg", &reglen);
+
+	if (reg && (16 == reglen)) {
+		nand_address = of_translate_address(np, reg);
+		nand_length = reg[1];
+		reg += 2;
+		gpreg_address = of_translate_address(np, reg);
+		gpreg_length = reg[1];
+		pr_info("nand_address=0x%08llx nand_length=0x%lx\n"
+			"gpreg_address=0x%08llx gpreg_length=0x%lx\n",
+			nand_address, nand_length,
+			gpreg_address, gpreg_length);
+		nand_base = ioremap(nand_address, nand_length);
+		gpreg_base = ioremap(gpreg_address, gpreg_length);
 	} else {
-		pr_info("ACP NAND: Using Static Addresses.\n");
-		nand_base = ioremap(0x002000440000ULL, 0x20000);
-		gpreg_base = ioremap(0x00200040c000ULL, 0x1000);
+		return -1;
+	}
+
+	ppdata.of_node = np;
+
+	/*
+	  Determine the Axxia system type.
+
+	  The ECC status register and mask are different on 344x, 342x, 35xx...
+	*/
+
+	if (of_machine_is_compatible("lsi,acp3500")) {
+		pecc_busy_register = (gpreg_base + 0x8c);
+		pecc_busy_mask = (1 << 20);
+	} else {
+		if (of_machine_is_compatible("lsi,acp3420")) {
+			pecc_busy_register = (gpreg_base + 0xc);
+			pecc_busy_mask = (1 << 28);
+		} else {
+			if (of_machine_is_compatible("lsi,acp3440")) {
+				pecc_busy_register = (gpreg_base + 0xc);
+				pecc_busy_mask = (1 << 28);
+			} else {
+				printk(KERN_ERR "Unsupported NAND Target\n");
+
+				return -1;
+			}
+		}
 	}
 
 	/*
@@ -3513,25 +3512,20 @@ lsi_nand_init(void)
 	  case and aren't in the EP501G1 case.
 	*/
 
-	{
-		unsigned long cr;
-		unsigned long cr_save;
-
-		cr = cr_save = READL((void *)(nand_base + NAND_CONFIG_REG));
-		cr = 0x2038;
-		WRITEL(cr, (void *)(nand_base + EP501_NAND_CONFIG_REG));
-		cr = READL((void *)nand_base + EP501_NAND_CONFIG_REG);
-		WRITEL(cr_save, (void *)(nand_base + EP501_NAND_CONFIG_REG));
-
-		if (0 == (cr & 0x2038))
-			lsi_nand_type = LSI_NAND_EP501G1;
-		else if (0x38 == (cr & 0x2038))
-			lsi_nand_type = LSI_NAND_EP501;
-		else if (0x2000 == (cr & 0x2038))
-			lsi_nand_type = LSI_NAND_EP501G3;
-		else
-			lsi_nand_type = LSI_NAND_NONE;
-	}
+	cr = cr_save = READL((void *)(nand_base + NAND_CONFIG_REG));
+	cr = 0x2038;
+	WRITEL(cr, (void *)(nand_base + EP501_NAND_CONFIG_REG));
+	cr = READL((void *)nand_base + EP501_NAND_CONFIG_REG);
+	WRITEL(cr_save, (void *)(nand_base + EP501_NAND_CONFIG_REG));
+
+	if (0 == (cr & 0x2038))
+		lsi_nand_type = LSI_NAND_EP501G1;
+	else if (0x38 == (cr & 0x2038))
+		lsi_nand_type = LSI_NAND_EP501;
+	else if (0x2000 == (cr & 0x2038))
+		lsi_nand_type = LSI_NAND_EP501G3;
+	else
+		lsi_nand_type = LSI_NAND_NONE;
 
 	switch (lsi_nand_type) {
 	case LSI_NAND_EP501:
-- 
1.8.1.4



More information about the linux-yocto mailing list