diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-10-26 12:18:35 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-10-26 13:06:02 +0100 |
commit | 422fbc0a2821c30e6f826f92b7d128f566373a62 (patch) | |
tree | 0f56fa22df43d183a013b7d76766d11abaa775b9 | |
parent | ca479dcadd5c7b6178e83feaffc638a92951fecd (diff) | |
download | barebox-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.c | 103 |
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); |