[linux-yocto] [PATCH 05/52] arch/powerpc: Update the Axxia NAND Driver for 3500
Daniel Dragomir
daniel.dragomir at windriver.com
Wed Jan 28 09:18:19 PST 2015
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", ®len);
-
- 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", ®len);
+
+ 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