summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2009-10-26 12:18:35 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2009-10-26 13:06:02 +0100
commit422fbc0a2821c30e6f826f92b7d128f566373a62 (patch)
tree0f56fa22df43d183a013b7d76766d11abaa775b9
parentca479dcadd5c7b6178e83feaffc638a92951fecd (diff)
downloadbarebox-422fbc0a2821c30e6f826f92b7d128f566373a62.tar.gz
barebox-422fbc0a2821c30e6f826f92b7d128f566373a62.tar.xz
mxc_nand: Add NFC V2 support
The v2 version of this controller is used on i.MX35/25 SoCs. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--drivers/nand/nand_imx.c103
1 files changed, 78 insertions, 25 deletions
diff --git a/drivers/nand/nand_imx.c b/drivers/nand/nand_imx.c
index 51387149db..8ad56dd292 100644
--- a/drivers/nand/nand_imx.c
+++ b/drivers/nand/nand_imx.c
@@ -26,11 +26,15 @@
#include <linux/mtd/nand.h>
#include <asm/arch/imx-nand.h>
#include <asm/arch/imx-regs.h>
+#include <asm/arch/generic.h>
#include <asm/io.h>
#include <errno.h>
#define DVR_VER "2.0"
+#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
+#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27())
+
/*
* Addresses for NFC registers
*/
@@ -43,8 +47,10 @@
#define NFC_RSLTMAIN_AREA 0xE0E
#define NFC_RSLTSPARE_AREA 0xE10
#define NFC_WRPROT 0xE12
-#define NFC_UNLOCKSTART_BLKADDR 0xE14
-#define NFC_UNLOCKEND_BLKADDR 0xE16
+#define NFC_V1_UNLOCKSTART_BLKADDR 0xe14
+#define NFC_V1_UNLOCKEND_BLKADDR 0xe16
+#define NFC_V21_UNLOCKSTART_BLKADDR 0xe20
+#define NFC_V21_UNLOCKEND_BLKADDR 0xe22
#define NFC_NF_WRPRST 0xE18
#define NFC_CONFIG1 0xE1A
#define NFC_CONFIG2 0xE1C
@@ -146,19 +152,47 @@ struct imx_nand_host {
/*
* OOB placement block for use with hardware ecc generation
*/
-static struct nand_ecclayout nand_hw_eccoob_smallpage = {
+static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
.eccbytes = 5,
.eccpos = {6, 7, 8, 9, 10},
.oobfree = {{0, 5}, {12, 4}}
};
-static struct nand_ecclayout nand_hw_eccoob_largepage = {
+static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
.eccbytes = 20,
.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
.oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
};
+/* OOB description for 512 byte pages with 16 byte OOB */
+static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
+ .eccbytes = 1 * 9,
+ .eccpos = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 15
+ },
+ .oobfree = {
+ {.offset = 0, .length = 5}
+ }
+};
+
+/* OOB description for 2048 byte pages with 64 byte OOB */
+static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
+ .eccbytes = 4 * 9,
+ .eccpos = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63
+ },
+ .oobfree = {
+ {.offset = 2, .length = 4},
+ {.offset = 16, .length = 7},
+ {.offset = 32, .length = 7},
+ {.offset = 48, .length = 7}
+ }
+};
+
static void __nand_boot_init memcpy32(void *trg, const void *src, int size)
{
int i;
@@ -243,7 +277,7 @@ static void __nand_boot_init send_page(struct imx_nand_host *host,
{
int bufs, i;
- if (host->pagesize_2k)
+ if (nfc_is_v1() && host->pagesize_2k)
bufs = 4;
else
bufs = 1;
@@ -753,6 +787,7 @@ static int __init imxnd_probe(struct device_d *dev)
struct mtd_info *mtd;
struct imx_nand_platform_data *pdata = dev->platform_data;
struct imx_nand_host *host;
+ struct nand_ecclayout *oob_smallpage, *oob_largepage;
u16 tmp;
int err = 0;
#ifdef CONFIG_ARCH_IMX27
@@ -765,12 +800,24 @@ static int __init imxnd_probe(struct device_d *dev)
return -ENOMEM;
host->data_buf = (uint8_t *)(host + 1);
- host->spare_len = 16;
+ host->base = (void __iomem *)dev->map_base;
- host->regs = host->base;
host->main_area0 = host->base;
host->main_area1 = host->base + 0x200;
- host->spare0 = host->base + 0x800;
+
+ if (nfc_is_v21()) {
+ host->regs = host->base + 0x1000;
+ host->spare0 = host->base + 0x1000;
+ host->spare_len = 64;
+ oob_smallpage = &nandv2_hw_eccoob_smallpage;
+ oob_largepage = &nandv2_hw_eccoob_largepage;
+ } else if (nfc_is_v1()) {
+ host->regs = host->base;
+ host->spare0 = host->base + 0x800;
+ host->spare_len = 16;
+ oob_smallpage = &nandv1_hw_eccoob_smallpage;
+ oob_largepage = &nandv1_hw_eccoob_largepage;
+ }
host->dev = dev;
/* structures must be linked */
@@ -798,8 +845,6 @@ static int __init imxnd_probe(struct device_d *dev)
clk_enable(host->clk);
#endif
- host->regs = (void __iomem *)dev->map_base;
-
tmp = readw(host->regs + NFC_CONFIG1);
tmp |= NFC_INT_MSK;
tmp &= ~NFC_SP_EN;
@@ -811,15 +856,11 @@ static int __init imxnd_probe(struct device_d *dev)
this->ecc.correct = imx_nand_correct_data;
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 512;
- this->ecc.bytes = 3;
- this->ecc.layout = &nand_hw_eccoob_smallpage;
tmp = readw(host->regs + NFC_CONFIG1);
tmp |= NFC_ECC_EN;
writew(tmp, host->regs + NFC_CONFIG1);
} else {
this->ecc.size = 512;
- this->ecc.bytes = 3;
- this->ecc.layout = &nand_hw_eccoob_smallpage;
this->ecc.mode = NAND_ECC_SOFT;
tmp = readw(host->regs + NFC_CONFIG1);
tmp &= ~NFC_ECC_EN;
@@ -834,16 +875,25 @@ static int __init imxnd_probe(struct device_d *dev)
writew(0x2, host->regs + NFC_CONFIG);
/* Blocks to be unlocked */
- writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);
- writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);
+ if (nfc_is_v21()) {
+ writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
+ writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR);
+ this->ecc.bytes = 9;
+ } else if (nfc_is_v1()) {
+ writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR);
+ writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR);
+ this->ecc.bytes = 3;
+ }
/* Unlock Block Command for given address range */
writew(0x4, host->regs + NFC_WRPROT);
+ this->ecc.layout = oob_smallpage;
+
/* NAND bus width determines access funtions used by upper layer */
if (pdata->width == 2) {
this->options |= NAND_BUSWIDTH_16;
- this->ecc.layout = &nand_hw_eccoob_smallpage;
+ this->ecc.layout = &nandv1_hw_eccoob_smallpage;
}
this->options |= NAND_SKIP_BBTSCAN;
@@ -855,7 +905,7 @@ static int __init imxnd_probe(struct device_d *dev)
}
if (mtd->writesize == 2048) {
- this->ecc.layout = &nand_hw_eccoob_largepage;
+ this->ecc.layout = oob_largepage;
host->pagesize_2k = 1;
}
@@ -910,6 +960,7 @@ void __nand_boot_init imx_nand_load_image(void *dest, int size)
{
struct imx_nand_host host;
u32 tmp, page, block, blocksize, pagesize;
+ void __iomem *base = (void __iomem *)IMX_NFC_BASE;
#ifdef CONFIG_ARCH_IMX27
tmp = readl(IMX_SYSTEM_CTL_BASE + 0x14);
@@ -934,9 +985,15 @@ void __nand_boot_init imx_nand_load_image(void *dest, int size)
blocksize = 16 * 1024;
}
- host.base = (void __iomem *)IMX_NFC_BASE;
- host.regs = host.base;
- host.spare0 = host.base + 0x800;
+ if (nfc_is_v21()) {
+ host.regs = base + 0x1000;
+ host.spare0 = base + 0x1000;
+ host.spare_len = 64;
+ } else if (nfc_is_v1()) {
+ host.regs = base;
+ host.spare0 = base + 0x800;
+ host.spare_len = 16;
+ }
send_cmd(&host, NAND_CMD_RESET);
@@ -944,10 +1001,6 @@ void __nand_boot_init imx_nand_load_image(void *dest, int size)
/* Unlock the internal RAM Buffer */
writew(0x2, host.regs + NFC_CONFIG);
- /* Blocks to be unlocked */
- writew(0x0, host.regs + NFC_UNLOCKSTART_BLKADDR);
- writew(0x4000, host.regs + NFC_UNLOCKEND_BLKADDR);
-
/* Unlock Block Command for given address range */
writew(0x4, host.regs + NFC_WRPROT);