From 8e5368a1e230a87220ef0d238584002e4a429ce3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 23 Mar 2007 10:40:04 +0000 Subject: [MTD] [NAND] Remember timing settings for CAFÉ NAND controller. We'll need them for suspend/resume. Signed-off-by: David Woodhouse --- drivers/mtd/nand/cafe.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c index fd6bb3ed40df..c328a7514510 100644 --- a/drivers/mtd/nand/cafe.c +++ b/drivers/mtd/nand/cafe.c @@ -530,7 +530,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, { struct mtd_info *mtd; struct cafe_priv *cafe; - uint32_t timing1, timing2, timing3; uint32_t ctrl; int err = 0; @@ -587,21 +586,19 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, } if (numtimings == 3) { - timing1 = timing[0]; - timing2 = timing[1]; - timing3 = timing[2]; cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n", - timing1, timing2, timing3); + timing[0], timing[1], timing[2]); } else { - timing1 = cafe_readl(cafe, NAND_TIMING1); - timing2 = cafe_readl(cafe, NAND_TIMING2); - timing3 = cafe_readl(cafe, NAND_TIMING3); + timing[0] = cafe_readl(cafe, NAND_TIMING1); + timing[1] = cafe_readl(cafe, NAND_TIMING2); + timing[2] = cafe_readl(cafe, NAND_TIMING3); - if (timing1 | timing2 | timing3) { - cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3); + if (timing[0] | timing[1] | timing[2]) { + cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", + timing[0], timing[1], timing[2]); } else { dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n"); - timing1 = timing2 = timing3 = 0xffffffff; + timing[0] = timing[1] = timing[2] = 0xffffffff; } } @@ -609,9 +606,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe_writel(cafe, 1, NAND_RESET); cafe_writel(cafe, 0, NAND_RESET); - cafe_writel(cafe, timing1, NAND_TIMING1); - cafe_writel(cafe, timing2, NAND_TIMING2); - cafe_writel(cafe, timing3, NAND_TIMING3); + cafe_writel(cafe, timing[0], NAND_TIMING1); + cafe_writel(cafe, timing[1], NAND_TIMING2); + cafe_writel(cafe, timing[2], NAND_TIMING3); cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, -- cgit v1.2.3-55-g7522 From 8c60e5475d8ca614d712cd3e2fe7330480709e02 Mon Sep 17 00:00:00 2001 From: sshahrom@micron.com Date: Wed, 21 Mar 2007 18:48:02 -0700 Subject: [MTD][NAND] Add Micron Manufacturer ID Add Micron Manufacturer ID. Signed-off-by: Shahrom Sharif Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2e2cdf2fc91d..900207769167 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -137,6 +137,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, + {NAND_MFR_MICRON, "Micron"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 97523887fe5d..cf197ad62da6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -431,6 +431,7 @@ struct nand_chip { #define NAND_MFR_RENESAS 0x07 #define NAND_MFR_STMICRO 0x20 #define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c /** * struct nand_flash_dev - NAND Flash Device ID Structure -- cgit v1.2.3-55-g7522 From 90424de8d0646eaf7cddbdb111edaf429dea6042 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 5 Apr 2007 11:44:05 +0200 Subject: [MTD] [NAND] Use ecc.read/write_page_raw consequently Use the functions in the ecc structure instead of the default ones, so the override by the board driver is effective also for software ecc code paths. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6af37b8cff65..5b96f1c5759f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; - nand_read_page_raw(mtd, chip, buf); + chip->ecc.read_page_raw(mtd, chip, buf); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - nand_write_page_raw(mtd, chip, buf); + chip->ecc.write_page_raw(mtd, chip, buf); } /** -- cgit v1.2.3-55-g7522 From 1cf9827b6852d5d81130efbf2e777e50b7126d23 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 17 Apr 2007 18:30:57 +0100 Subject: [MTD] [NAND] Move ancient NAND chip support into a config option The support for obsolete ancient NAND chips adds .data size and one of the old ids conflicts with a modern one. Make the support for such chips depending on a config option. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 9 +++++++++ drivers/mtd/nand/nand_ids.c | 3 +++ 2 files changed, 12 insertions(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 2d12dcdd740c..49cbf510cce1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -31,6 +31,15 @@ config MTD_NAND_ECC_SMC Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. +config MTD_NAND_MUSEUM_IDS + bool "Enable chip ids for obsolete ancient NAND devices" + depends on MTD_NAND + default n + help + Enable this option only when your board has first generation + NAND chips (page size 256 byte, erase size 4-8KiB). The IDs + of these chips were reused by later, larger chips. + config MTD_NAND_AUTCPU12 tristate "SmartMediaCard on autronix autcpu12 board" depends on MTD_NAND && ARCH_AUTCPU12 diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 900207769167..2fc674a190cf 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -24,6 +24,8 @@ * 512 512 Byte page size */ struct nand_flash_dev nand_flash_ids[] = { + +#ifdef CONFIG_MTD_NAND_MUSEUM_IDS {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, @@ -39,6 +41,7 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, +#endif {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, -- cgit v1.2.3-55-g7522 From 4226b510371efd9cdc628663527d36aee36054a9 Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Tue, 17 Apr 2007 13:50:59 -0400 Subject: [MTD] [NAND] Casting bug in nand_default_block_markbad There is a slight bug in nand_default_block_markbad, where the offset is cast to an integer, prior to being shifted. This means that on large offsets, it is incorrectly doing a signed shift & losing bits. Fixed this by doing the cast after the shift (as is done elsewhere in the code). Signed-off-by: Andre Renaud Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5b96f1c5759f..ab3b2d16cffe 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -350,7 +350,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) int block, ret; /* Get block number */ - block = ((int)ofs) >> chip->bbt_erase_shift; + block = (int)(ofs >> chip->bbt_erase_shift); if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); -- cgit v1.2.3-55-g7522 From 2b77a0ed54eeea61937e7f71b0487b815edfbcdf Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Mar 2007 12:46:43 +0200 Subject: [MTD] nandsim: add partition capability to nandsim Enhance nandsim to be able to create more than 1 partition. A new module parameter 'parts' may be used to specify partition sizes. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 97 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 24 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c3bca9590ad2..638e6c256d3e 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -37,6 +37,7 @@ #include #include #include +#include /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -90,6 +91,8 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; static uint log = CONFIG_NANDSIM_LOG; static uint dbg = CONFIG_NANDSIM_DBG; +static unsigned long parts[MAX_MTD_DEVICES]; +static unsigned int parts_num; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -104,6 +107,7 @@ module_param(bus_width, uint, 0400); module_param(do_delays, uint, 0400); module_param(log, uint, 0400); module_param(dbg, uint, 0400); +module_param_array(parts, ulong, &parts_num, 0400); MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -118,6 +122,7 @@ MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)"); MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); MODULE_PARM_DESC(log, "Perform logging if not zero"); MODULE_PARM_DESC(dbg, "Output debug information if not zero"); +MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -131,9 +136,9 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); #define NS_DBG(args...) \ do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) #define NS_WARN(args...) \ - do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0) + do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) #define NS_ERR(args...) \ - do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0) + do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) /* Busy-wait delay macros (microseconds, milliseconds) */ #define NS_UDELAY(us) \ @@ -238,7 +243,8 @@ union ns_mem { * The structure which describes all the internal simulator data. */ struct nandsim { - struct mtd_partition part; + struct mtd_partition partitions[MAX_MTD_DEVICES]; + unsigned int nbparts; uint busw; /* flash chip bus width (8 or 16) */ u_char ids[4]; /* chip's ID bytes */ @@ -381,6 +387,13 @@ static void free_device(struct nandsim *ns) } } +static char *get_partition_name(int i) +{ + char buf[64]; + sprintf(buf, "NAND simulator partition %d", i); + return kstrdup(buf, GFP_KERNEL); +} + /* * Initialize the nandsim structure. * @@ -390,7 +403,9 @@ static int init_nandsim(struct mtd_info *mtd) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); - int i; + int i, ret = 0; + u_int32_t remains; + u_int32_t next_offset; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -448,6 +463,40 @@ static int init_nandsim(struct mtd_info *mtd) } } + /* Fill the partition_info structure */ + if (parts_num > ARRAY_SIZE(ns->partitions)) { + NS_ERR("too many partitions.\n"); + ret = -EINVAL; + goto error; + } + remains = ns->geom.totsz; + next_offset = 0; + for (i = 0; i < parts_num; ++i) { + unsigned long part = parts[i]; + if (!part || part > remains / ns->geom.secsz) { + NS_ERR("bad partition size.\n"); + ret = -EINVAL; + goto error; + } + ns->partitions[i].name = get_partition_name(i); + ns->partitions[i].offset = next_offset; + ns->partitions[i].size = part * ns->geom.secsz; + next_offset += ns->partitions[i].size; + remains -= ns->partitions[i].size; + } + ns->nbparts = parts_num; + if (remains) { + if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { + NS_ERR("too many partitions.\n"); + ret = -EINVAL; + goto error; + } + ns->partitions[i].name = get_partition_name(i); + ns->partitions[i].offset = next_offset; + ns->partitions[i].size = remains; + ns->nbparts += 1; + } + /* Detect how many ID bytes the NAND chip outputs */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (second_id_byte != nand_flash_ids[i].id) @@ -474,7 +523,7 @@ static int init_nandsim(struct mtd_info *mtd) printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); - if (alloc_device(ns) != 0) + if ((ret = alloc_device(ns)) != 0) goto error; /* Allocate / initialize the internal buffer */ @@ -482,21 +531,17 @@ static int init_nandsim(struct mtd_info *mtd) if (!ns->buf.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", ns->geom.pgszoob); + ret = -ENOMEM; goto error; } memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); - /* Fill the partition_info structure */ - ns->part.name = "NAND simulator partition"; - ns->part.offset = 0; - ns->part.size = ns->geom.totsz; - return 0; error: free_device(ns); - return -ENOMEM; + return ret; } /* @@ -1503,7 +1548,7 @@ static int __init ns_init_module(void) { struct nand_chip *chip; struct nandsim *nand; - int retval = -ENOMEM; + int retval = -ENOMEM, i; if (bus_width != 8 && bus_width != 16) { NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); @@ -1564,21 +1609,23 @@ static int __init ns_init_module(void) goto error; } - if ((retval = init_nandsim(nsmtd)) != 0) { - NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); - goto error; - } + if ((retval = init_nandsim(nsmtd)) != 0) + goto err_exit; - if ((retval = nand_default_bbt(nsmtd)) != 0) { - free_nandsim(nand); - goto error; - } + if ((retval = nand_default_bbt(nsmtd)) != 0) + goto err_exit; - /* Register NAND as one big partition */ - add_mtd_partitions(nsmtd, &nand->part, 1); + /* Register NAND partitions */ + if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) + goto err_exit; return 0; +err_exit: + free_nandsim(nand); + nand_release(nsmtd); + for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) + kfree(nand->partitions[i].name); error: kfree(nsmtd); @@ -1593,9 +1640,12 @@ module_init(ns_init_module); static void __exit ns_cleanup_module(void) { struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); + int i; free_nandsim(ns); /* Free nandsim private resources */ - nand_release(nsmtd); /* Unregisterd drived */ + nand_release(nsmtd); /* Unregister driver */ + for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) + kfree(ns->partitions[i].name); kfree(nsmtd); /* Free other structures */ } @@ -1604,4 +1654,3 @@ module_exit(ns_cleanup_module); MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("Artem B. Bityuckiy"); MODULE_DESCRIPTION ("The NAND flash simulator"); - -- cgit v1.2.3-55-g7522 From 514087e74fb401a6621e8c836f4eaab87c269f24 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Mar 2007 12:47:45 +0200 Subject: [MTD] nandsim: enhance nandsim to simulate flash errors New module parameters have been added to nandsim to simulate: bitflips random bit flips badblocks blocks that are initially marked bad weakblocks blocks that fail to erase after a small number of erase cycles weakpages pages that fail to write after a small number of successful writes gravepages pages that fail to read after a small number of successful reads Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 301 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 300 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 638e6c256d3e..05b42077d22f 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -38,6 +38,7 @@ #include #include #include +#include /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -93,6 +94,11 @@ static uint log = CONFIG_NANDSIM_LOG; static uint dbg = CONFIG_NANDSIM_DBG; static unsigned long parts[MAX_MTD_DEVICES]; static unsigned int parts_num; +static char *badblocks = NULL; +static char *weakblocks = NULL; +static char *weakpages = NULL; +static unsigned int bitflips = 0; +static char *gravepages = NULL; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -108,6 +114,11 @@ module_param(do_delays, uint, 0400); module_param(log, uint, 0400); module_param(dbg, uint, 0400); module_param_array(parts, ulong, &parts_num, 0400); +module_param(badblocks, charp, 0400); +module_param(weakblocks, charp, 0400); +module_param(weakpages, charp, 0400); +module_param(bitflips, uint, 0400); +module_param(gravepages, charp, 0400); MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -123,6 +134,18 @@ MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not z MODULE_PARM_DESC(log, "Perform logging if not zero"); MODULE_PARM_DESC(dbg, "Output debug information if not zero"); MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); +/* Page and erase block positions for the following parameters are independent of any partitions */ +MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas"); +MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]" + " separated by commas e.g. 113:2 means eb 113" + " can be erased only twice before failing"); +MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]" + " separated by commas e.g. 1401:2 means page 1401" + " can be written only twice before failing"); +MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)"); +MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" + " separated by commas e.g. 1401:2 means page 1401" + " can be read only twice before failing"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -344,6 +367,33 @@ static struct nandsim_operations { STATE_DATAOUT, STATE_READY}} }; +struct weak_block { + struct list_head list; + unsigned int erase_block_no; + unsigned int max_erases; + unsigned int erases_done; +}; + +static LIST_HEAD(weak_blocks); + +struct weak_page { + struct list_head list; + unsigned int page_no; + unsigned int max_writes; + unsigned int writes_done; +}; + +static LIST_HEAD(weak_pages); + +struct grave_page { + struct list_head list; + unsigned int page_no; + unsigned int max_reads; + unsigned int reads_done; +}; + +static LIST_HEAD(grave_pages); + /* MTD structure for NAND controller */ static struct mtd_info *nsmtd; @@ -555,6 +605,204 @@ static void free_nandsim(struct nandsim *ns) return; } +static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) +{ + char *w; + int zero_ok; + unsigned int erase_block_no; + loff_t offset; + + if (!badblocks) + return 0; + w = badblocks; + do { + zero_ok = (*w == '0' ? 1 : 0); + erase_block_no = simple_strtoul(w, &w, 0); + if (!zero_ok && !erase_block_no) { + NS_ERR("invalid badblocks.\n"); + return -EINVAL; + } + offset = erase_block_no * ns->geom.secsz; + if (mtd->block_markbad(mtd, offset)) { + NS_ERR("invalid badblocks.\n"); + return -EINVAL; + } + if (*w == ',') + w += 1; + } while (*w); + return 0; +} + +static int parse_weakblocks(void) +{ + char *w; + int zero_ok; + unsigned int erase_block_no; + unsigned int max_erases; + struct weak_block *wb; + + if (!weakblocks) + return 0; + w = weakblocks; + do { + zero_ok = (*w == '0' ? 1 : 0); + erase_block_no = simple_strtoul(w, &w, 0); + if (!zero_ok && !erase_block_no) { + NS_ERR("invalid weakblocks.\n"); + return -EINVAL; + } + max_erases = 3; + if (*w == ':') { + w += 1; + max_erases = simple_strtoul(w, &w, 0); + } + if (*w == ',') + w += 1; + wb = kzalloc(sizeof(*wb), GFP_KERNEL); + if (!wb) { + NS_ERR("unable to allocate memory.\n"); + return -ENOMEM; + } + wb->erase_block_no = erase_block_no; + wb->max_erases = max_erases; + list_add(&wb->list, &weak_blocks); + } while (*w); + return 0; +} + +static int erase_error(unsigned int erase_block_no) +{ + struct weak_block *wb; + + list_for_each_entry(wb, &weak_blocks, list) + if (wb->erase_block_no == erase_block_no) { + if (wb->erases_done >= wb->max_erases) + return 1; + wb->erases_done += 1; + return 0; + } + return 0; +} + +static int parse_weakpages(void) +{ + char *w; + int zero_ok; + unsigned int page_no; + unsigned int max_writes; + struct weak_page *wp; + + if (!weakpages) + return 0; + w = weakpages; + do { + zero_ok = (*w == '0' ? 1 : 0); + page_no = simple_strtoul(w, &w, 0); + if (!zero_ok && !page_no) { + NS_ERR("invalid weakpagess.\n"); + return -EINVAL; + } + max_writes = 3; + if (*w == ':') { + w += 1; + max_writes = simple_strtoul(w, &w, 0); + } + if (*w == ',') + w += 1; + wp = kzalloc(sizeof(*wp), GFP_KERNEL); + if (!wp) { + NS_ERR("unable to allocate memory.\n"); + return -ENOMEM; + } + wp->page_no = page_no; + wp->max_writes = max_writes; + list_add(&wp->list, &weak_pages); + } while (*w); + return 0; +} + +static int write_error(unsigned int page_no) +{ + struct weak_page *wp; + + list_for_each_entry(wp, &weak_pages, list) + if (wp->page_no == page_no) { + if (wp->writes_done >= wp->max_writes) + return 1; + wp->writes_done += 1; + return 0; + } + return 0; +} + +static int parse_gravepages(void) +{ + char *g; + int zero_ok; + unsigned int page_no; + unsigned int max_reads; + struct grave_page *gp; + + if (!gravepages) + return 0; + g = gravepages; + do { + zero_ok = (*g == '0' ? 1 : 0); + page_no = simple_strtoul(g, &g, 0); + if (!zero_ok && !page_no) { + NS_ERR("invalid gravepagess.\n"); + return -EINVAL; + } + max_reads = 3; + if (*g == ':') { + g += 1; + max_reads = simple_strtoul(g, &g, 0); + } + if (*g == ',') + g += 1; + gp = kzalloc(sizeof(*gp), GFP_KERNEL); + if (!gp) { + NS_ERR("unable to allocate memory.\n"); + return -ENOMEM; + } + gp->page_no = page_no; + gp->max_reads = max_reads; + list_add(&gp->list, &grave_pages); + } while (*g); + return 0; +} + +static int read_error(unsigned int page_no) +{ + struct grave_page *gp; + + list_for_each_entry(gp, &grave_pages, list) + if (gp->page_no == page_no) { + if (gp->reads_done >= gp->max_reads) + return 1; + gp->reads_done += 1; + return 0; + } + return 0; +} + +static void free_lists(void) +{ + struct list_head *pos, *n; + list_for_each_safe(pos, n, &weak_blocks) { + list_del(pos); + kfree(list_entry(pos, struct weak_block, list)); + } + list_for_each_safe(pos, n, &weak_pages) { + list_del(pos); + kfree(list_entry(pos, struct weak_page, list)); + } + list_for_each_safe(pos, n, &grave_pages) { + list_del(pos); + kfree(list_entry(pos, struct grave_page, list)); + } +} + /* * Returns the string representation of 'state' state. */ @@ -867,9 +1115,31 @@ static void read_page(struct nandsim *ns, int num) NS_DBG("read_page: page %d not allocated\n", ns->regs.row); memset(ns->buf.byte, 0xFF, num); } else { + unsigned int page_no = ns->regs.row; NS_DBG("read_page: page %d allocated, reading from %d\n", ns->regs.row, ns->regs.column + ns->regs.off); + if (read_error(page_no)) { + int i; + memset(ns->buf.byte, 0xFF, num); + for (i = 0; i < num; ++i) + ns->buf.byte[i] = random32(); + NS_WARN("simulating read error in page %u\n", page_no); + return; + } memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); + if (bitflips && random32() < (1 << 22)) { + int flips = 1; + if (bitflips > 1) + flips = (random32() % (int) bitflips) + 1; + while (flips--) { + int pos = random32() % (num * 8); + ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); + NS_WARN("read_page: flipping bit %d in page %d " + "reading from %d ecc: corrected=%u failed=%u\n", + pos, ns->regs.row, ns->regs.column + ns->regs.off, + nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); + } + } } } @@ -928,6 +1198,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) { int num; int busdiv = ns->busw == 8 ? 1 : 2; + unsigned int erase_block_no, page_no; action &= ACTION_MASK; @@ -987,14 +1258,21 @@ static int do_state_action(struct nandsim *ns, uint32_t action) 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; ns->regs.column = 0; + erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift); + NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", ns->regs.row, NS_RAW_OFFSET(ns)); - NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); + NS_LOG("erase sector %u\n", erase_block_no); erase_sector(ns); NS_MDELAY(erase_delay); + if (erase_error(erase_block_no)) { + NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); + return -1; + } + break; case ACTION_PRGPAGE: @@ -1017,6 +1295,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action) if (prog_page(ns, num) == -1) return -1; + page_no = ns->regs.row; + NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); NS_LOG("programm page %d\n", ns->regs.row); @@ -1024,6 +1304,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action) NS_UDELAY(programm_delay); NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); + if (write_error(page_no)) { + NS_WARN("simulating write failure in page %u\n", page_no); + return -1; + } + break; case ACTION_ZEROOFF: @@ -1602,6 +1887,15 @@ static int __init ns_init_module(void) nsmtd->owner = THIS_MODULE; + if ((retval = parse_weakblocks()) != 0) + goto error; + + if ((retval = parse_weakpages()) != 0) + goto error; + + if ((retval = parse_gravepages()) != 0) + goto error; + if ((retval = nand_scan(nsmtd, 1)) != 0) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) @@ -1612,6 +1906,9 @@ static int __init ns_init_module(void) if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; + if ((retval = parse_badblocks(nand, nsmtd)) != 0) + goto err_exit; + if ((retval = nand_default_bbt(nsmtd)) != 0) goto err_exit; @@ -1628,6 +1925,7 @@ err_exit: kfree(nand->partitions[i].name); error: kfree(nsmtd); + free_lists(); return retval; } @@ -1647,6 +1945,7 @@ static void __exit ns_cleanup_module(void) for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) kfree(ns->partitions[i].name); kfree(nsmtd); /* Free other structures */ + free_lists(); } module_exit(ns_cleanup_module); -- cgit v1.2.3-55-g7522 From 57aa6b545f6f772dd317ccd29bdada999b16a13d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Mar 2007 12:40:41 +0200 Subject: [MTD] nandsim: Enhance nandsim optionally to report wear information A new module parameter 'rptwear' specifies how many erases between reporting wear information. Zero means never. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 05b42077d22f..1a44ef63c8d1 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -99,6 +99,7 @@ static char *weakblocks = NULL; static char *weakpages = NULL; static unsigned int bitflips = 0; static char *gravepages = NULL; +static unsigned int rptwear = 0; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -119,6 +120,7 @@ module_param(weakblocks, charp, 0400); module_param(weakpages, charp, 0400); module_param(bitflips, uint, 0400); module_param(gravepages, charp, 0400); +module_param(rptwear, uint, 0400); MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -146,6 +148,7 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" " separated by commas e.g. 1401:2 means page 1401" " can be read only twice before failing"); +MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -162,6 +165,8 @@ MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (default do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) #define NS_ERR(args...) \ do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) +#define NS_INFO(args...) \ + do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0) /* Busy-wait delay macros (microseconds, milliseconds) */ #define NS_UDELAY(us) \ @@ -394,6 +399,11 @@ struct grave_page { static LIST_HEAD(grave_pages); +static unsigned long *erase_block_wear = NULL; +static unsigned int wear_eb_count = 0; +static unsigned long total_wear = 0; +static unsigned int rptwear_cnt = 0; + /* MTD structure for NAND controller */ static struct mtd_info *nsmtd; @@ -801,6 +811,89 @@ static void free_lists(void) list_del(pos); kfree(list_entry(pos, struct grave_page, list)); } + kfree(erase_block_wear); +} + +static int setup_wear_reporting(struct mtd_info *mtd) +{ + size_t mem; + + if (!rptwear) + return 0; + wear_eb_count = mtd->size / mtd->erasesize; + mem = wear_eb_count * sizeof(unsigned long); + if (mem / sizeof(unsigned long) != wear_eb_count) { + NS_ERR("Too many erase blocks for wear reporting\n"); + return -ENOMEM; + } + erase_block_wear = kzalloc(mem, GFP_KERNEL); + if (!erase_block_wear) { + NS_ERR("Too many erase blocks for wear reporting\n"); + return -ENOMEM; + } + return 0; +} + +static void update_wear(unsigned int erase_block_no) +{ + unsigned long wmin = -1, wmax = 0, avg; + unsigned long deciles[10], decile_max[10], tot = 0; + unsigned int i; + + if (!erase_block_wear) + return; + total_wear += 1; + if (total_wear == 0) + NS_ERR("Erase counter total overflow\n"); + erase_block_wear[erase_block_no] += 1; + if (erase_block_wear[erase_block_no] == 0) + NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); + rptwear_cnt += 1; + if (rptwear_cnt < rptwear) + return; + rptwear_cnt = 0; + /* Calc wear stats */ + for (i = 0; i < wear_eb_count; ++i) { + unsigned long wear = erase_block_wear[i]; + if (wear < wmin) + wmin = wear; + if (wear > wmax) + wmax = wear; + tot += wear; + } + for (i = 0; i < 9; ++i) { + deciles[i] = 0; + decile_max[i] = (wmax * (i + 1) + 5) / 10; + } + deciles[9] = 0; + decile_max[9] = wmax; + for (i = 0; i < wear_eb_count; ++i) { + int d; + unsigned long wear = erase_block_wear[i]; + for (d = 0; d < 10; ++d) + if (wear <= decile_max[d]) { + deciles[d] += 1; + break; + } + } + avg = tot / wear_eb_count; + /* Output wear report */ + NS_INFO("*** Wear Report ***\n"); + NS_INFO("Total numbers of erases: %lu\n", tot); + NS_INFO("Number of erase blocks: %u\n", wear_eb_count); + NS_INFO("Average number of erases: %lu\n", avg); + NS_INFO("Maximum number of erases: %lu\n", wmax); + NS_INFO("Minimum number of erases: %lu\n", wmin); + for (i = 0; i < 10; ++i) { + unsigned long from = (i ? decile_max[i - 1] + 1 : 0); + if (from > decile_max[i]) + continue; + NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", + from, + decile_max[i], + deciles[i]); + } + NS_INFO("*** End of Wear Report ***\n"); } /* @@ -1268,6 +1361,9 @@ static int do_state_action(struct nandsim *ns, uint32_t action) NS_MDELAY(erase_delay); + if (erase_block_wear) + update_wear(erase_block_no); + if (erase_error(erase_block_no)) { NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); return -1; @@ -1903,6 +1999,9 @@ static int __init ns_init_module(void) goto error; } + if ((retval = setup_wear_reporting(nsmtd)) != 0) + goto err_exit; + if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; -- cgit v1.2.3-55-g7522 From a5ac8aeb29000fcab8d91848273a6616fcd039ee Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Mar 2007 12:49:11 +0200 Subject: [MTD] nandsim: enhance nandsim to allow arbitrary NAND size A new module parameter has been added called 'overridesize', which overrides the size that would be determined by the ID bytes. 'overridesize' is specified in erase blocks and as the exponent of a power of two e.g. 5 means a size of 32 erase blocks. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 1a44ef63c8d1..205df0f771fe 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -100,6 +100,7 @@ static char *weakpages = NULL; static unsigned int bitflips = 0; static char *gravepages = NULL; static unsigned int rptwear = 0; +static unsigned int overridesize = 0; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -121,8 +122,9 @@ module_param(weakpages, charp, 0400); module_param(bitflips, uint, 0400); module_param(gravepages, charp, 0400); module_param(rptwear, uint, 0400); +module_param(overridesize, uint, 0400); -MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); +MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); @@ -149,6 +151,9 @@ MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (default " separated by commas e.g. 1401:2 means page 1401" " can be read only twice before failing"); MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); +MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " + "The size is specified in erase blocks and as the exponent of a power of two" + " e.g. 5 means a size of 32 erase blocks"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -1959,6 +1964,8 @@ static int __init ns_init_module(void) chip->verify_buf = ns_nand_verify_buf; chip->read_word = ns_nand_read_word; chip->ecc.mode = NAND_ECC_SOFT; + /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ + /* and 'badblocks' parameters to work */ chip->options |= NAND_SKIP_BBTSCAN; /* @@ -1999,6 +2006,18 @@ static int __init ns_init_module(void) goto error; } + if (overridesize) { + u_int32_t new_size = nsmtd->erasesize << overridesize; + if (new_size >> overridesize != nsmtd->erasesize) { + NS_ERR("overridesize is too big\n"); + goto err_exit; + } + /* N.B. This relies on nand_scan not doing anything with the size before we change it */ + nsmtd->size = new_size; + chip->chipsize = new_size; + chip->chip_shift = ffs(new_size) - 1; + } + if ((retval = setup_wear_reporting(nsmtd)) != 0) goto err_exit; -- cgit v1.2.3-55-g7522 From ec98c681a5355469eee70227b7e0a88f0d688483 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 19 Apr 2007 16:21:41 -0500 Subject: Use menuconfig objects: MTD Use menuconfigs instead of menus, so the whole menu can be disabled at once instead of going through all options. Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/Kconfig | 30 +++++++++++---------------- drivers/mtd/chips/Kconfig | 12 +++-------- drivers/mtd/devices/Kconfig | 18 ++++++----------- drivers/mtd/maps/Kconfig | 8 +++----- drivers/mtd/nand/Kconfig | 49 +++++++++++++++++++++------------------------ drivers/mtd/onenand/Kconfig | 13 +++++------- 6 files changed, 52 insertions(+), 78 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 26f75c299440..fedf9b7eae5d 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -1,8 +1,6 @@ # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ -menu "Memory Technology Devices (MTD)" - -config MTD +menuconfig MTD tristate "Memory Technology Device (MTD) support" help Memory Technology Devices are flash, RAM and similar chips, often @@ -13,9 +11,10 @@ config MTD them. It will also allow you to select individual drivers for particular hardware and users of MTD devices. If unsure, say N. +if MTD + config MTD_DEBUG bool "Debugging" - depends on MTD help This turns on low-level debugging for the entire MTD sub-system. Normally, you should say 'N'. @@ -29,7 +28,6 @@ config MTD_DEBUG_VERBOSE config MTD_CONCAT tristate "MTD concatenating support" - depends on MTD help Support for concatenating several MTD devices into a single (virtual) one. This allows you to have -for example- a JFFS(2) @@ -38,7 +36,6 @@ config MTD_CONCAT config MTD_PARTITIONS bool "MTD partitioning support" - depends on MTD help If you have a device which needs to divide its flash chip(s) up into multiple 'partitions', each of which appears to the user as @@ -153,11 +150,9 @@ config MTD_AFS_PARTS 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. comment "User Modules And Translation Layers" - depends on MTD config MTD_CHAR tristate "Direct char device access to MTD devices" - depends on MTD help This provides a character device for each MTD device present in the system, allowing the user to read and write directly to the @@ -166,12 +161,12 @@ config MTD_CHAR config MTD_BLKDEVS tristate "Common interface to block layer for MTD 'translation layers'" - depends on MTD && BLOCK + depends on BLOCK default n config MTD_BLOCK tristate "Caching block device access to MTD devices" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS ---help--- Although most flash chips have an erase size too large to be useful @@ -194,7 +189,7 @@ config MTD_BLOCK config MTD_BLOCK_RO tristate "Readonly block device access to MTD devices" - depends on MTD_BLOCK!=y && MTD && BLOCK + depends on MTD_BLOCK!=y && BLOCK select MTD_BLKDEVS help This allows you to mount read-only file systems (such as cramfs) @@ -206,7 +201,7 @@ config MTD_BLOCK_RO config FTL tristate "FTL (Flash Translation Layer) support" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS ---help--- This provides support for the original Flash Translation Layer which @@ -223,7 +218,7 @@ config FTL config NFTL tristate "NFTL (NAND Flash Translation Layer) support" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS ---help--- This provides support for the NAND Flash Translation Layer which is @@ -247,7 +242,7 @@ config NFTL_RW config INFTL tristate "INFTL (Inverse NAND Flash Translation Layer) support" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS ---help--- This provides support for the Inverse NAND Flash Translation @@ -265,7 +260,7 @@ config INFTL config RFD_FTL tristate "Resident Flash Disk (Flash Translation Layer) support" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS ---help--- This provides support for the flash translation layer known @@ -276,7 +271,7 @@ config RFD_FTL config SSFDC tristate "NAND SSFDC (SmartMedia) read only translation layer" - depends on MTD && BLOCK + depends on BLOCK select MTD_BLKDEVS help This enables read only access to SmartMedia formatted NAND @@ -292,5 +287,4 @@ source "drivers/mtd/nand/Kconfig" source "drivers/mtd/onenand/Kconfig" -endmenu - +endif # MTD diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 72e6d73beb40..d28e0fc85e12 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers" config MTD_CFI tristate "Detect flash chips by Common Flash Interface (CFI) probe" - depends on MTD select MTD_GEN_PROBE help The Common Flash Interface specification was developed by Intel, @@ -18,7 +17,6 @@ config MTD_CFI config MTD_JEDECPROBE tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" - depends on MTD select MTD_GEN_PROBE help This option enables JEDEC-style probing of flash chips which are not @@ -213,21 +211,18 @@ config MTD_CFI_UTIL config MTD_RAM tristate "Support for RAM chips in bus mapping" - depends on MTD help This option enables basic support for RAM chips accessed through a bus mapping driver. config MTD_ROM tristate "Support for ROM chips in bus mapping" - depends on MTD help This option enables basic support for ROM chips accessed through a bus mapping driver. config MTD_ABSENT tristate "Support for absent chips in bus mapping" - depends on MTD help This option enables support for a dummy probing driver used to allocated placeholder MTD devices on systems that have socketed @@ -237,7 +232,6 @@ config MTD_ABSENT with this driver will return -ENODEV upon access. config MTD_OBSOLETE_CHIPS - depends on MTD bool "Older (theoretically obsoleted now) drivers for non-CFI chips" help This option does not enable any code directly, but will allow you to @@ -250,7 +244,7 @@ config MTD_OBSOLETE_CHIPS config MTD_AMDSTD tristate "AMD compatible flash chip support (non-CFI)" - depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN + depends on MTD_OBSOLETE_CHIPS && BROKEN help This option enables support for flash chips using AMD-compatible commands, including some which are not CFI-compatible and hence @@ -260,7 +254,7 @@ config MTD_AMDSTD config MTD_SHARP tristate "pre-CFI Sharp chip support" - depends on MTD && MTD_OBSOLETE_CHIPS + depends on MTD_OBSOLETE_CHIPS help This option enables support for flash chips using Sharp-compatible commands, including some which are not CFI-compatible and hence @@ -268,7 +262,7 @@ config MTD_SHARP config MTD_JEDEC tristate "JEDEC device support" - depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN + depends on MTD_OBSOLETE_CHIPS && BROKEN help Enable older JEDEC flash interface devices for self programming flash. It is commonly used in older AMD chips. It is diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index bef0f0d2c28e..690c94236d7f 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers" config MTD_PMC551 tristate "Ramix PMC551 PCI Mezzanine RAM card support" - depends on MTD && PCI + depends on PCI ---help--- This provides a MTD device driver for the Ramix PMC551 RAM PCI card from Ramix Inc. . @@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG config MTD_MS02NV tristate "DEC MS02-NV NVRAM module support" - depends on MTD && MACH_DECSTATION + depends on MACH_DECSTATION help This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery backed-up NVRAM module. The module was originally meant as an NFS @@ -54,7 +54,7 @@ config MTD_MS02NV config MTD_DATAFLASH tristate "Support for AT45xxx DataFlash" - depends on MTD && SPI_MASTER && EXPERIMENTAL + depends on SPI_MASTER && EXPERIMENTAL help This enables access to AT45xxx DataFlash chips, using SPI. Sometimes DataFlash chips are packaged inside MMC-format @@ -70,7 +70,7 @@ config MTD_DATAFLASH26 config MTD_M25P80 tristate "Support for M25 SPI Flash" - depends on MTD && SPI_MASTER && EXPERIMENTAL + depends on SPI_MASTER && EXPERIMENTAL help This enables access to ST M25P80 and similar SPI flash chips, used for program and data storage. Set up your spi devices @@ -78,7 +78,6 @@ config MTD_M25P80 config MTD_SLRAM tristate "Uncached system RAM" - depends on MTD help If your CPU cannot cache all of the physical memory in your machine, you can still use it for storage or swap by using this driver to @@ -86,7 +85,6 @@ config MTD_SLRAM config MTD_PHRAM tristate "Physical system RAM" - depends on MTD help This is a re-implementation of the slram driver above. @@ -96,7 +94,7 @@ config MTD_PHRAM config MTD_LART tristate "28F160xx flash driver for LART" - depends on SA1100_LART && MTD + depends on SA1100_LART help This enables the flash driver for LART. Please note that you do not need any mapping/chip driver for LART. This one does it all @@ -104,7 +102,6 @@ config MTD_LART config MTD_MTDRAM tristate "Test driver using RAM" - depends on MTD help This enables a test MTD device driver which uses vmalloc() to provide storage. You probably want to say 'N' unless you're @@ -144,7 +141,7 @@ config MTDRAM_ABS_POS config MTD_BLOCK2MTD tristate "MTD using block device" - depends on MTD && BLOCK + depends on BLOCK help This driver allows a block device to appear as an MTD. It would generally be used in the following cases: @@ -158,7 +155,6 @@ comment "Disk-On-Chip Device Drivers" config MTD_DOC2000 tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" - depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- @@ -181,7 +177,6 @@ config MTD_DOC2000 config MTD_DOC2001 tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" - depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- @@ -203,7 +198,6 @@ config MTD_DOC2001 config MTD_DOC2001PLUS tristate "M-Systems Disk-On-Chip Millennium Plus" - depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 87158797a66f..d990d8141ef5 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -6,7 +6,6 @@ menu "Mapping drivers for chip access" config MTD_COMPLEX_MAPPINGS bool "Support non-linear mappings of flash chips" - depends on MTD help This causes the chip drivers to allow for complicated paged mappings of flash chips. @@ -550,7 +549,7 @@ config MTD_OMAP_NOR # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" - depends on MTD && PCI && MTD_COMPLEX_MAPPINGS + depends on PCI && MTD_COMPLEX_MAPPINGS help Mapping for accessing flash devices on add-in cards like the Intel XScale IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode @@ -560,7 +559,7 @@ config MTD_PCI config MTD_PCMCIA tristate "PCMCIA MTD driver" - depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN + depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN help Map driver for accessing PCMCIA linear flash memory cards. These cards are usually around 4-16MiB in size. This does not include @@ -624,13 +623,12 @@ config MTD_BAST_MAXSIZE config MTD_SHARP_SL bool "ROM mapped on Sharp SL Series" - depends on MTD && ARCH_PXA + depends on ARCH_PXA help This enables access to the flash chip on the Sharp SL Series of PDAs. config MTD_PLATRAM tristate "Map driver for platform device RAM (mtd-ram)" - depends on MTD select MTD_RAM help Map driver for RAM areas described via the platform device diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 49cbf510cce1..4e62afe0c0f3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,10 +1,7 @@ # drivers/mtd/nand/Kconfig # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ -menu "NAND Flash Device Drivers" - depends on MTD!=n - -config MTD_NAND +menuconfig MTD_NAND tristate "NAND Device Support" depends on MTD select MTD_NAND_IDS @@ -13,9 +10,10 @@ config MTD_NAND devices. For further information see . +if MTD_NAND + config MTD_NAND_VERIFY_WRITE bool "Verify NAND page writes" - depends on MTD_NAND help This adds an extra check when data is written to the flash. The NAND flash device internally checks only bits transitioning @@ -25,7 +23,6 @@ config MTD_NAND_VERIFY_WRITE config MTD_NAND_ECC_SMC bool "NAND ECC Smart Media byte order" - depends on MTD_NAND default n help Software ECC according to the Smart Media Specification. @@ -42,45 +39,45 @@ config MTD_NAND_MUSEUM_IDS config MTD_NAND_AUTCPU12 tristate "SmartMediaCard on autronix autcpu12 board" - depends on MTD_NAND && ARCH_AUTCPU12 + depends on ARCH_AUTCPU12 help This enables the driver for the autronix autcpu12 board to access the SmartMediaCard. config MTD_NAND_EDB7312 tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on MTD_NAND && ARCH_EDB7312 + depends on ARCH_EDB7312 help This enables the driver for the Cirrus Logic EBD7312 evaluation board to access the onboard NAND Flash. config MTD_NAND_H1900 tristate "iPAQ H1900 flash" - depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS + depends on ARCH_PXA && MTD_PARTITIONS help This enables the driver for the iPAQ h1900 flash. config MTD_NAND_SPIA tristate "NAND Flash device on SPIA board" - depends on ARCH_P720T && MTD_NAND + depends on ARCH_P720T help If you had to ask, you don't have one. Say 'N'. config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" - depends on MACH_AMS_DELTA && MTD_NAND + depends on MACH_AMS_DELTA help Support for NAND flash on Amstrad E3 (Delta). config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" - depends on ARCH_OMAP && MTD_NAND && BROKEN + depends on ARCH_OMAP && BROKEN help Support for NAND flash on Texas Instruments Toto platform. config MTD_NAND_TS7250 tristate "NAND Flash device on TS-7250 board" - depends on MACH_TS72XX && MTD_NAND + depends on MACH_TS72XX help Support for NAND flash on Technologic Systems TS-7250 platform. @@ -89,14 +86,14 @@ config MTD_NAND_IDS config MTD_NAND_AU1550 tristate "Au1550/1200 NAND support" - depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND + depends on SOC_AU1200 || SOC_AU1550 help This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" - depends on MTD_NAND && SH_SOLUTION_ENGINE + depends on SH_SOLUTION_ENGINE select REED_SOLOMON select REED_SOLOMON_DEC8 select BITREVERSE @@ -106,13 +103,13 @@ config MTD_NAND_RTC_FROM4 config MTD_NAND_PPCHAMELEONEVB tristate "NAND Flash device on PPChameleonEVB board" - depends on PPCHAMELEONEVB && MTD_NAND && BROKEN + depends on PPCHAMELEONEVB && BROKEN help This enables the NAND flash driver on the PPChameleon EVB Board. config MTD_NAND_S3C2410 tristate "NAND Flash support for S3C2410/S3C2440 SoC" - depends on ARCH_S3C2410 && MTD_NAND + depends on ARCH_S3C2410 help This enables the NAND flash controller on the S3C2410 and S3C2440 SoCs @@ -137,7 +134,7 @@ config MTD_NAND_S3C2410_HWECC config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" - depends on MTD_NAND && 44x + depends on 44x select MTD_NAND_ECC_SMC help NDFC Nand Flash Controllers are integrated in EP44x SoCs @@ -154,7 +151,7 @@ config MTD_NAND_S3C2410_CLKSTOP config MTD_NAND_DISKONCHIP tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" - depends on MTD_NAND && EXPERIMENTAL + depends on EXPERIMENTAL select REED_SOLOMON select REED_SOLOMON_DEC16 help @@ -224,11 +221,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE config MTD_NAND_SHARPSL tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on MTD_NAND && ARCH_PXA + depends on ARCH_PXA config MTD_NAND_BASLER_EXCITE tristate "Support for NAND Flash on Basler eXcite" - depends on MTD_NAND && BASLER_EXCITE + depends on BASLER_EXCITE help This enables the driver for the NAND flash device found on the Basler eXcite Smart Camera. If built as a module, the driver @@ -236,14 +233,14 @@ config MTD_NAND_BASLER_EXCITE config MTD_NAND_CAFE tristate "NAND support for OLPC CAFÉ chip" - depends on MTD_NAND && PCI + depends on PCI help Use NAND flash attached to the CAFÉ chip designed for the $100 laptop. config MTD_NAND_CS553X tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" - depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH) + depends on X86_32 && (X86_PC || X86_GENERICARCH) help The CS553x companion chips for the AMD Geode processor include NAND flash controllers with built-in hardware ECC @@ -256,16 +253,16 @@ config MTD_NAND_CS553X config MTD_NAND_AT91 bool "Support for NAND Flash / SmartMedia on AT91" - depends on MTD_NAND && ARCH_AT91 + depends on ARCH_AT91 help Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 processors. config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" - depends on MTD_NAND && MTD_PARTITIONS + depends on MTD_PARTITIONS help The simulator may simulate various NAND flash chips for the MTD nand layer. -endmenu +endif # MTD_NAND diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 373bddce8f1c..e1503912f69e 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig @@ -2,10 +2,7 @@ # linux/drivers/mtd/onenand/Kconfig # -menu "OneNAND Flash Device Drivers" - depends on MTD != n - -config MTD_ONENAND +menuconfig MTD_ONENAND tristate "OneNAND Device Support" depends on MTD help @@ -13,9 +10,10 @@ config MTD_ONENAND devices. For further information see . +if MTD_ONENAND + config MTD_ONENAND_VERIFY_WRITE bool "Verify OneNAND page writes" - depends on MTD_ONENAND help This adds an extra check when data is written to the flash. The OneNAND flash device internally checks only bits transitioning @@ -25,13 +23,12 @@ config MTD_ONENAND_VERIFY_WRITE config MTD_ONENAND_GENERIC tristate "OneNAND Flash device via platform device driver" - depends on MTD_ONENAND && ARM + depends on ARM help Support for OneNAND flash via platform device driver. config MTD_ONENAND_OTP bool "OneNAND OTP Support" - depends on MTD_ONENAND help One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. @@ -43,4 +40,4 @@ config MTD_ONENAND_OTP OTP block is fully-guaranteed to be a valid block. -endmenu +endif # MTD_ONENAND -- cgit v1.2.3-55-g7522 From 78ab67da1002d954ea4c3e2b441e2483c41f94e8 Mon Sep 17 00:00:00 2001 From: Knobloch, Thomas Date: Fri, 27 Apr 2007 13:19:36 +0200 Subject: [MTD] [NAND] Wrong calculation of page number in nand_block_bad() In case that there is no memory based bad block table available the function nand_block_checkbad() in drivers/mtd/nand/nand_base.c will call nand_block_bad() directly. When parameter 'getchip' is set to zero, nand_block_bad() will not right shift the offset to calculate the correct page number. Signed-off-by: Thomas Knobloch Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ab3b2d16cffe..04de315e4937 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -312,7 +312,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ chip->select_chip(mtd, chipnr); } else - page = (int)ofs; + page = (int)(ofs >> chip->page_shift); if (chip->options & NAND_BUSWIDTH_16) { chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, -- cgit v1.2.3-55-g7522 From 54d33c4c715b80cc022b8e4974a4de693c96fc99 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 22 Apr 2007 08:53:21 +0300 Subject: [MTD] [NAND] CM-x270 MTD driver This patch provides MTD support for NAND flash devices on CM-x270 modules. Signed-off-by: Mike Rapoport Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 5 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/cmx270_nand.c | 267 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 drivers/mtd/nand/cmx270_nand.c (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 4e62afe0c0f3..d05873b8c155 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -258,6 +258,11 @@ config MTD_NAND_AT91 Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 processors. +config MTD_NAND_CM_X270 + tristate "Support for NAND Flash on CM-X270 modules" + depends on MTD_NAND && MACH_ARMCORE + + config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" depends on MTD_PARTITIONS diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 80f1dfc77949..6872031a3fb2 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o +obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c new file mode 100644 index 000000000000..cb663ef245d5 --- /dev/null +++ b/drivers/mtd/nand/cmx270_nand.c @@ -0,0 +1,267 @@ +/* + * linux/drivers/mtd/nand/cmx270-nand.c + * + * Copyright (C) 2006 Compulab, Ltd. + * Mike Rapoport + * + * Derived from drivers/mtd/nand/h1910.c + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * CM-X270 board. + */ + +#include +#include + +#include +#include + +#include +#include + +#define GPIO_NAND_CS (11) +#define GPIO_NAND_RB (89) + +/* This macro needed to ensure in-order operation of GPIO and local + * bus. Without both asm command and dummy uncached read there're + * states when NAND access is broken. I've looked for such macro(s) in + * include/asm-arm but found nothing approptiate. + * dmac_clean_range is close, but is makes cache invalidation + * unnecessary here and it cannot be used in module + */ +#define DRAIN_WB() \ + do { \ + unsigned char dummy; \ + asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \ + dummy=*((unsigned char*)UNCACHED_ADDR); \ + } while(0) + +/* MTD structure for CM-X270 board */ +static struct mtd_info *cmx270_nand_mtd; + +/* remaped IO address of the device */ +static void __iomem *cmx270_nand_io; + +/* + * Define static partitions for flash device + */ +static struct mtd_partition partition_info[] = { + [0] = { + .name = "cmx270-0", + .offset = 0, + .size = MTDPART_SIZ_FULL + } +}; +#define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) + +const char *part_probes[] = { "cmdlinepart", NULL }; + +static u_char cmx270_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + return (readl(this->IO_ADDR_R) >> 16); +} + +static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_W); +} + +static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_R) >> 16; +} + +static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_R) >> 16)) + return -EFAULT; + + return 0; +} + +static inline void nand_cs_on(void) +{ + GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); +} + +static void nand_cs_off(void) +{ + DRAIN_WB(); + + GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); +} + +/* + * hardware specific access to control-lines + */ +static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, + unsigned int ctrl) +{ + struct nand_chip* this = mtd->priv; + unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; + + DRAIN_WB(); + + if (ctrl & NAND_CTRL_CHANGE) { + if ( ctrl & NAND_ALE ) + nandaddr |= (1 << 3); + else + nandaddr &= ~(1 << 3); + if ( ctrl & NAND_CLE ) + nandaddr |= (1 << 2); + else + nandaddr &= ~(1 << 2); + if ( ctrl & NAND_NCE ) + nand_cs_on(); + else + nand_cs_off(); + } + + DRAIN_WB(); + this->IO_ADDR_W = (void __iomem*)nandaddr; + if (dat != NAND_CMD_NONE) + writel((dat << 16), this->IO_ADDR_W); + + DRAIN_WB(); +} + +/* + * read device ready pin + */ +static int cmx270_device_ready(struct mtd_info *mtd) +{ + DRAIN_WB(); + + return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB)); +} + +/* + * Main initialization routine + */ +static int cmx270_init(void) +{ + struct nand_chip *this; + const char *part_type; + struct mtd_partition *mtd_parts; + int mtd_parts_nb = 0; + int ret; + + /* Allocate memory for MTD device structure and private data */ + cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) + + sizeof(struct nand_chip), + GFP_KERNEL); + if (!cmx270_nand_mtd) { + printk("Unable to allocate CM-X270 NAND MTD device structure.\n"); + return -ENOMEM; + } + + cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12); + if (!cmx270_nand_io) { + printk("Unable to ioremap NAND device\n"); + ret = -EINVAL; + goto err1; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&cmx270_nand_mtd[1]); + + /* Link the private data with the MTD structure */ + cmx270_nand_mtd->owner = THIS_MODULE; + cmx270_nand_mtd->priv = this; + + /* insert callbacks */ + this->IO_ADDR_R = cmx270_nand_io; + this->IO_ADDR_W = cmx270_nand_io; + this->cmd_ctrl = cmx270_hwcontrol; + this->dev_ready = cmx270_device_ready; + + /* 15 us command delay time */ + this->chip_delay = 20; + this->ecc.mode = NAND_ECC_SOFT; + + /* read/write functions */ + this->read_byte = cmx270_read_byte; + this->read_buf = cmx270_read_buf; + this->write_buf = cmx270_write_buf; + this->verify_buf = cmx270_verify_buf; + + /* Scan to find existence of the device */ + if (nand_scan (cmx270_nand_mtd, 1)) { + printk(KERN_NOTICE "No NAND device\n"); + ret = -ENXIO; + goto err2; + } + +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, + &mtd_parts, 0); + if (mtd_parts_nb > 0) + part_type = "command line"; + else + mtd_parts_nb = 0; +#endif + if (!mtd_parts_nb) { + mtd_parts = partition_info; + mtd_parts_nb = NUM_PARTITIONS; + part_type = "static"; + } + + /* Register the partitions */ + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); + if (ret) + goto err2; + + /* Return happy */ + return 0; + +err2: + iounmap(cmx270_nand_io); +err1: + kfree(cmx270_nand_mtd); + + return ret; + +} +module_init(cmx270_init); + +/* + * Clean up routine + */ +static void cmx270_cleanup(void) +{ + /* Release resources, unregister device */ + nand_release(cmx270_nand_mtd); + + iounmap(cmx270_nand_io); + + /* Free the MTD device structure */ + kfree (cmx270_nand_mtd); +} +module_exit(cmx270_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mike Rapoport "); +MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module"); -- cgit v1.2.3-55-g7522