From 437d0d299f0e08954c3cb680221d7e888e1a857f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toralf=20F=C3=B6rster?= Date: Mon, 26 May 2008 20:35:46 +0200 Subject: [MTD] [NAND] fix 2 "unused variable" warnings in cafe_nand.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toralf Förster Signed-off-by: David Woodhouse --- drivers/mtd/nand/cafe_nand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index da6ceaa..95345d0 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -626,10 +626,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, { struct mtd_info *mtd; struct cafe_priv *cafe; - struct mtd_partition *parts; uint32_t ctrl; - int nr_parts; int err = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; + int nr_parts; +#endif /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ -- cgit v1.1 From ff0de61c3612410dc84a8de28761ef840d5d35ac Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sun, 25 May 2008 07:35:17 -0400 Subject: [MTD] [NAND] excite_nandflash: simplify code using ARRAY_SIZE() macro. Signed-off-by: Robert P. J. Day Signed-off-by: David Woodhouse --- drivers/mtd/nand/excite_nandflash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index bed8729..ced14b5 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c @@ -209,7 +209,7 @@ static int __init excite_nand_probe(struct device *dev) if (likely(!scan_res)) { DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); add_mtd_partitions(&drvdata->board_mtd, partition_info, - sizeof partition_info / sizeof partition_info[0]); + ARRAY_SIZE(partition_info)); } else { iounmap(drvdata->regs); kfree(drvdata); -- cgit v1.1 From af3deccfa67341a9df39b6f734afcc85998ad4b7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 30 May 2008 15:56:18 +0300 Subject: [MTD] [NAND] nandsim: fix size bug Signed-off-by: Adrian Hunter Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index bb885d1..b28d760 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -511,7 +511,7 @@ static int init_nandsim(struct mtd_info *mtd) } if (ns->options & OPT_SMALLPAGE) { - if (ns->geom.totsz < (32 << 20)) { + if (ns->geom.totsz <= (32 << 20)) { ns->geom.pgaddrbytes = 3; ns->geom.secaddrbytes = 2; } else { -- cgit v1.1 From 07293b20083cb66df35bf2041f0c554eaac43e8c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 30 May 2008 15:56:23 +0300 Subject: [MTD] [NAND] nandsim: fix overridesize Signed-off-by: Adrian Hunter Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index b28d760..b480516 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2022,6 +2022,7 @@ static int __init ns_init_module(void) nsmtd->size = new_size; chip->chipsize = new_size; chip->chip_shift = ffs(new_size) - 1; + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; } if ((retval = setup_wear_reporting(nsmtd)) != 0) -- cgit v1.1 From 6eda7a55f786b75e7d3d636a9431e6c850b20d72 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 30 May 2008 15:56:26 +0300 Subject: [MTD] [NAND] nandsim: allow for 64-bit size Amend nandsim so that it does not assume 32-bit flash size. Signed-off-by: Adrian Hunter Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index b480516..68c150c 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -298,11 +298,11 @@ struct nandsim { /* NAND flash "geometry" */ struct nandsin_geometry { - uint32_t totsz; /* total flash size, bytes */ + uint64_t totsz; /* total flash size, bytes */ uint32_t secsz; /* flash sector (erase block) size, bytes */ uint pgsz; /* NAND flash page size, bytes */ uint oobsz; /* page OOB area size, bytes */ - uint32_t totszoob; /* total flash size including OOB, bytes */ + uint64_t totszoob; /* total flash size including OOB, bytes */ uint pgszoob; /* page size including OOB , bytes*/ uint secszoob; /* sector size including OOB, bytes */ uint pgnum; /* total number of pages */ @@ -459,6 +459,12 @@ static char *get_partition_name(int i) return kstrdup(buf, GFP_KERNEL); } +static u_int64_t divide(u_int64_t n, u_int32_t d) +{ + do_div(n, d); + return n; +} + /* * Initialize the nandsim structure. * @@ -469,8 +475,8 @@ 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, ret = 0; - u_int32_t remains; - u_int32_t next_offset; + u_int64_t remains; + u_int64_t next_offset; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -487,8 +493,8 @@ static int init_nandsim(struct mtd_info *mtd) ns->geom.oobsz = mtd->oobsize; ns->geom.secsz = mtd->erasesize; ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; - ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; - ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; + ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); + ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; ns->geom.secshift = ffs(ns->geom.secsz) - 1; ns->geom.pgshift = chip->page_shift; ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; @@ -537,15 +543,16 @@ static int init_nandsim(struct mtd_info *mtd) 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) { + u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; + + if (!part_sz || part_sz > remains) { 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; + ns->partitions[i].size = part_sz; next_offset += ns->partitions[i].size; remains -= ns->partitions[i].size; } @@ -573,7 +580,7 @@ static int init_nandsim(struct mtd_info *mtd) if (ns->busw == 16) NS_WARN("16-bit flashes support wasn't tested\n"); - printk("flash size: %u MiB\n", ns->geom.totsz >> 20); + printk("flash size: %llu MiB\n", ns->geom.totsz >> 20); printk("page size: %u bytes\n", ns->geom.pgsz); printk("OOB area size: %u bytes\n", ns->geom.oobsz); printk("sector size: %u KiB\n", ns->geom.secsz >> 10); @@ -583,7 +590,7 @@ static int init_nandsim(struct mtd_info *mtd) printk("bits in sector size: %u\n", ns->geom.secshift); printk("bits in page size: %u\n", ns->geom.pgshift); printk("bits in OOB size: %u\n", ns->geom.oobshift); - printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); + printk("flash size with OOB: %llu KiB\n", ns->geom.totszoob >> 10); printk("page address bytes: %u\n", ns->geom.pgaddrbytes); printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); @@ -825,7 +832,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) if (!rptwear) return 0; - wear_eb_count = mtd->size / mtd->erasesize; + wear_eb_count = divide(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"); @@ -2013,7 +2020,7 @@ static int __init ns_init_module(void) } if (overridesize) { - u_int32_t new_size = nsmtd->erasesize << overridesize; + u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); goto err_exit; @@ -2021,7 +2028,7 @@ static int __init ns_init_module(void) /* 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; + chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; } -- cgit v1.1 From 59018b6d2acabb114ab58637e6ab95ba424a89d0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 20 May 2008 01:03:52 +0300 Subject: MTD/JFFS2: remove CVS keywords Once upon a time, the MTD repository was using CVS. This patch therefore removes all usages of the no longer updated CVS keywords from the MTD code. This also includes code that printed them to the user. Signed-off-by: Adrian Bunk Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 1 - drivers/mtd/nand/Makefile | 1 - drivers/mtd/nand/au1550nd.c | 2 -- drivers/mtd/nand/autcpu12.c | 2 -- drivers/mtd/nand/diskonchip.c | 2 -- drivers/mtd/nand/edb7312.c | 2 -- drivers/mtd/nand/h1910.c | 2 -- drivers/mtd/nand/nand_bbt.c | 2 -- drivers/mtd/nand/nand_ecc.c | 2 -- drivers/mtd/nand/nand_ids.c | 2 -- drivers/mtd/nand/nandsim.c | 2 -- drivers/mtd/nand/ppchameleonevb.c | 2 -- drivers/mtd/nand/rtc_from4.c | 2 -- drivers/mtd/nand/s3c2410.c | 2 -- drivers/mtd/nand/sharpsl.c | 2 -- drivers/mtd/nand/spia.c | 2 -- drivers/mtd/nand/toto.c | 2 -- drivers/mtd/nand/ts7250.c | 2 -- 18 files changed, 34 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5076faf..7dea6c3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,4 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ menuconfig MTD_NAND tristate "NAND Device Support" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a6e74a4..d95a10c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,6 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 09e421a..22ad9f3 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -3,8 +3,6 @@ * * Copyright (C) 2004 Embedded Edge, LLC * - * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dd38011..553dd7e 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0e72153..cd4393c 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -15,8 +15,6 @@ * converted to the generic Reed-Solomon library by Thomas Gleixner * * Interface to generic NAND code for M-Systems DiskOnChip devices - * - * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ */ #include diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index ba67bbe..387e435 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 2d585d2..9e59de5 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -7,8 +7,6 @@ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5e121ce..0b1c485 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,8 +6,6 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 9003a13..918a806 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -9,8 +9,6 @@ * * Copyright (C) 2006 Thomas Gleixner * - * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ - * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 or (at your option) any diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a3e3ab0..69ee2c9 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -3,8 +3,6 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 68c150c..add975a 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -21,8 +21,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - * - * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ */ #include diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 082073a..cc86584 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/edb7312.c * * - * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 26f8821..a033c4c 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b34a460..91f42e4 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -20,8 +20,6 @@ * 20-Oct-2005 BJD Fix timing calculation bug * 14-Jan-2006 BJD Allow clock to be stopped when idle * - * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 033f880..6dba2fb 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -3,8 +3,6 @@ * * Copyright (C) 2004 Richard Purdie * - * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ - * * Based on Sharp's NAND driver sharp_sl.c * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 1f6d429..0cc6d0a 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -8,8 +8,6 @@ * to controllines (due to change in nand.c) * page_cache added * - * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ - * * 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. diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index f9e2d4a..bbf492e 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -14,8 +14,6 @@ * Overview: * This is a device driver for the NAND flash device found on the * TI fido board. It supports 32MiB and 64MiB cards - * - * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ */ #include diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index f400810..807a727 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -9,8 +9,6 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: ts7250.c,v 1.4 2004/12/30 22:02:07 joff Exp $ - * * 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. -- cgit v1.1 From 451d33993b13174d27474ad2ce7a2f10ce2e31ad Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 20 May 2008 17:32:14 +0100 Subject: [MTD] [NAND] S3C2410: Change printk() into dev_dbg() Fix a minor problem with what should have been debug output by changing printk() to dev_dbg() inside s3c2410_nand_update_chip(). Thanks to David Woodhouse for pointing this out. Signed-off-by: Ben Dooks Signed-off-by: David Woodhouse --- drivers/mtd/nand/s3c2410.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 91f42e4..c9726bd 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -689,7 +689,8 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, { struct nand_chip *chip = &nmtd->chip; - printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); + dev_dbg(info->device, "chip %p => page shift %d\n", + chip, chip->page_shift); if (hardware_ecc) { /* change the behaviour depending on wether we are using -- cgit v1.1 From 7e74a5076edb3555dc6c96dc91b155706515bb4c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 20 May 2008 17:32:27 +0100 Subject: [MTD] [NAND] S3C2410: Remove changelog and tidy header The changelog on the driver is superflous given this is being kept under revision control. Remove the other cruft in the header and update the copyright and the supported device list. Signed-off-by: Ben Dooks Signed-off-by: David Woodhouse --- drivers/mtd/nand/s3c2410.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index c9726bd..35c6db5 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,24 +1,10 @@ /* linux/drivers/mtd/nand/s3c2410.c * - * Copyright (c) 2004,2005 Simtec Electronics - * http://www.simtec.co.uk/products/SWLINUX/ + * Copyright © 2004-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ * Ben Dooks * - * Samsung S3C2410/S3C240 NAND driver - * - * Changelog: - * 21-Sep-2004 BJD Initial version - * 23-Sep-2004 BJD Multiple device support - * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode - * 12-Oct-2004 BJD Fixed errors in use of platform data - * 18-Feb-2005 BJD Fix sparse errors - * 14-Mar-2005 BJD Applied tglx's code reduction patch - * 02-May-2005 BJD Fixed s3c2440 support - * 02-May-2005 BJD Reduced hwcontrol decode - * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug - * 08-Jul-2005 BJD Fix OOPS when no platform data supplied - * 20-Oct-2005 BJD Fix timing calculation bug - * 14-Jan-2006 BJD Allow clock to be stopped when idle + * Samsung S3C2410/S3C2440/S3C2412 NAND driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.1 From 4474573a90bae41351fad576fa80c424d62be567 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 5 Jun 2008 09:43:03 -0700 Subject: [MTD] [NAND] nandsim: missing header for do_div Fix nandsim build error, missing #include: linux-next-20080605/drivers/mtd/nand/nandsim.c: In function 'divide': linux-next-20080605/drivers/mtd/nand/nandsim.c:462: error: implicit declaration of function 'do_div' Signed-off-by: Randy Dunlap Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index add975a..ecd70e2 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) || \ -- cgit v1.1 From aa83570e23e626fe8dd1253f17e6d175507025f1 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 6 Jun 2008 18:59:40 +0400 Subject: [MTD] [NAND] fsl_elbc_nand: fix section mismatch between probe and remove WARNING: drivers/mtd/nand/built-in.o(.devinit.text+0x114): Section mismatch in reference from the function fsl_elbc_ctrl_probe() to the function .devexit.text:fsl_elbc_ctrl_remove() __devinit functions should not call functions with __devexit. Since probe function calls remove in case of errors, we want to remove __devexit attribute from it. Signed-off-by: Anton Vorontsov Acked-by: Scott Wood Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4b69aac..1b06d29 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -917,7 +917,7 @@ static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) return 0; } -static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev) +static int fsl_elbc_ctrl_remove(struct of_device *ofdev) { struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); int i; @@ -1041,7 +1041,7 @@ static struct of_platform_driver fsl_elbc_ctrl_driver = { }, .match_table = fsl_elbc_match, .probe = fsl_elbc_ctrl_probe, - .remove = __devexit_p(fsl_elbc_ctrl_remove), + .remove = fsl_elbc_ctrl_remove, }; static int __init fsl_elbc_init(void) -- cgit v1.1 From 62fd71fe710886ba449e932ad7877f4a8340c2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Skinnemoen?= Date: Fri, 6 Jun 2008 18:04:51 +0200 Subject: [MTD] [NAND] at91_nand: Convert to generic GPIO API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point in using an AT91-specific GPIO API when the generic API works just as well. Signed-off-by: Håvard Skinnemoen Signed-off-by: David Woodhouse --- drivers/mtd/nand/at91_nand.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c index 0adb287..2dcaeea 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/at91_nand.c @@ -31,12 +31,10 @@ #include #include +#include #include -#include -#include #include -#include #ifdef CONFIG_MTD_NAND_AT91_ECC_HW #define hard_ecc 1 @@ -99,7 +97,7 @@ struct at91_nand_host { static void at91_nand_enable(struct at91_nand_host *host) { if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 0); + gpio_set_value(host->board->enable_pin, 0); } /* @@ -108,7 +106,7 @@ static void at91_nand_enable(struct at91_nand_host *host) static void at91_nand_disable(struct at91_nand_host *host) { if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 1); + gpio_set_value(host->board->enable_pin, 1); } /* @@ -142,7 +140,7 @@ static int at91_nand_device_ready(struct mtd_info *mtd) struct nand_chip *nand_chip = mtd->priv; struct at91_nand_host *host = nand_chip->priv; - return at91_get_gpio_value(host->board->rdy_pin); + return gpio_get_value(host->board->rdy_pin); } /* @@ -447,7 +445,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) at91_nand_enable(host); if (host->board->det_pin) { - if (at91_get_gpio_value(host->board->det_pin)) { + if (gpio_get_value(host->board->det_pin)) { printk ("No SmartMedia card inserted.\n"); res = ENXIO; goto out; -- cgit v1.1 From d4f4c0aa8e36f69e46360b3d3569dc15d6099894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Skinnemoen?= Date: Fri, 6 Jun 2008 18:04:52 +0200 Subject: [MTD] [NAND] rename at91_nand -> atmel_nand: file names and Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AT91 NAND driver needs just a few tiny modifications to work on AVR32 as well. Rename it atmel_nand to reflect this. Also move the ECC register definitions into drivers/mtd/nand since they are only useful to the atmel_nand driver, and get rid of the useless filename at the top of each file. Signed-off-by: Håvard Skinnemoen Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 17 +- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/at91_nand.c | 592 -------------------------------------- drivers/mtd/nand/atmel_nand.c | 590 +++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/atmel_nand_ecc.h | 36 +++ 5 files changed, 636 insertions(+), 601 deletions(-) delete mode 100644 drivers/mtd/nand/at91_nand.c create mode 100644 drivers/mtd/nand/atmel_nand.c create mode 100644 drivers/mtd/nand/atmel_nand_ecc.h (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 7dea6c3..cdd2952 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -271,7 +271,7 @@ config MTD_NAND_CS553X If you say "m", the module will be called "cs553x_nand.ko". -config MTD_NAND_AT91 +config MTD_NAND_ATMEL bool "Support for NAND Flash / SmartMedia on AT91" depends on ARCH_AT91 help @@ -279,14 +279,15 @@ config MTD_NAND_AT91 on Atmel AT91 processors. choice prompt "ECC management for NAND Flash / SmartMedia on AT91" - depends on MTD_NAND_AT91 + depends on MTD_NAND_ATMEL -config MTD_NAND_AT91_ECC_HW +config MTD_NAND_ATMEL_ECC_HW bool "Hardware ECC" depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 help - Uses hardware ECC provided by the at91sam9260/at91sam9263 chip - instead of software ECC. + Use hardware ECC instead of software ECC when the chip + supports it. + The hardware ECC controller is capable of single bit error correction and 2-bit random detection per page. @@ -296,16 +297,16 @@ config MTD_NAND_AT91_ECC_HW If unsure, say Y -config MTD_NAND_AT91_ECC_SOFT +config MTD_NAND_ATMEL_ECC_SOFT bool "Software ECC" help - Uses software ECC. + Use software ECC. NB : hardware and software ECC schemes are incompatible. If you switch from one to another, you'll have to erase your mtd partition. -config MTD_NAND_AT91_ECC_NONE +config MTD_NAND_ATMEL_ECC_NONE bool "No ECC (testing only, DANGEROUS)" depends on DEBUG_KERNEL help diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d95a10c..d772581 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o 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_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c deleted file mode 100644 index 2dcaeea..0000000 --- a/drivers/mtd/nand/at91_nand.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * drivers/mtd/nand/at91_nand.c - * - * Copyright (C) 2003 Rick Bronson - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) - * - * - * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 - * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 - * - * Derived from Das U-Boot source code - * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) - * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas - * - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#ifdef CONFIG_MTD_NAND_AT91_ECC_HW -#define hard_ecc 1 -#else -#define hard_ecc 0 -#endif - -#ifdef CONFIG_MTD_NAND_AT91_ECC_NONE -#define no_ecc 1 -#else -#define no_ecc 0 -#endif - -/* Register access macros */ -#define ecc_readl(add, reg) \ - __raw_readl(add + AT91_ECC_##reg) -#define ecc_writel(add, reg, value) \ - __raw_writel((value), add + AT91_ECC_##reg) - -#include /* AT91SAM9260/3 ECC registers */ - -/* oob layout for large page size - * bad block info is on bytes 0 and 1 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout at91_oobinfo_large = { - .eccbytes = 4, - .eccpos = {60, 61, 62, 63}, - .oobfree = { - {2, 58} - }, -}; - -/* oob layout for small page size - * bad block info is on bytes 4 and 5 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout at91_oobinfo_small = { - .eccbytes = 4, - .eccpos = {0, 1, 2, 3}, - .oobfree = { - {6, 10} - }, -}; - -struct at91_nand_host { - struct nand_chip nand_chip; - struct mtd_info mtd; - void __iomem *io_base; - struct at91_nand_data *board; - struct device *dev; - void __iomem *ecc; -}; - -/* - * Enable NAND. - */ -static void at91_nand_enable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - gpio_set_value(host->board->enable_pin, 0); -} - -/* - * Disable NAND. - */ -static void at91_nand_disable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - gpio_set_value(host->board->enable_pin, 1); -} - -/* - * Hardware specific access to control-lines - */ -static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_NCE) - at91_nand_enable(host); - else - at91_nand_disable(host); - } - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, host->io_base + (1 << host->board->cle)); - else - writeb(cmd, host->io_base + (1 << host->board->ale)); -} - -/* - * Read the Device Ready pin. - */ -static int at91_nand_device_ready(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - - return gpio_get_value(host->board->rdy_pin); -} - -/* - * write oob for small pages - */ -static int at91_nand_write_oob_512(struct mtd_info *mtd, - struct nand_chip *chip, int page) -{ - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsize = chip->ecc.size, length = mtd->oobsize; - int len, pos, status = 0; - const uint8_t *bufpoi = chip->oob_poi; - - pos = eccsize + chunk; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); - len = min_t(int, length, chunk); - chip->write_buf(mtd, bufpoi, len); - bufpoi += len; - length -= len; - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; - -} - -/* - * read oob for small pages - */ -static int at91_nand_read_oob_512(struct mtd_info *mtd, - struct nand_chip *chip, int page, int sndcmd) -{ - if (sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - sndcmd = 0; - } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return sndcmd; -} - -/* - * Calculate HW ECC - * - * function called after a write - * - * mtd: MTD block structure - * dat: raw data (unused) - * ecc_code: buffer for ECC - */ -static int at91_nand_calculate(struct mtd_info *mtd, - const u_char *dat, unsigned char *ecc_code) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - uint32_t *eccpos = nand_chip->ecc.layout->eccpos; - unsigned int ecc_value; - - /* get the first 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, PR); - - ecc_code[eccpos[0]] = ecc_value & 0xFF; - ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; - - /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; - - ecc_code[eccpos[2]] = ecc_value & 0xFF; - ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; - - return 0; -} - -/* - * HW ECC read page function - * - * mtd: mtd info structure - * chip: nand chip info structure - * buf: buffer to store read data - */ -static int at91_nand_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - uint8_t *ecc_pos; - int stat; - - /* read the page */ - chip->read_buf(mtd, p, eccsize); - - /* move to ECC position if needed */ - if (eccpos[0] != 0) { - /* This only works on large pages - * because the ECC controller waits for - * NAND_CMD_RNDOUTSTART after the - * NAND_CMD_RNDOUT. - * anyway, for small pages, the eccpos[0] == 0 - */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + eccpos[0], -1); - } - - /* the ECC controller needs to read the ECC just after the data */ - ecc_pos = oob + eccpos[0]; - chip->read_buf(mtd, ecc_pos, eccbytes); - - /* check if there's an error */ - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - - /* get back to oob start (end of page) */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - - /* read the oob */ - chip->read_buf(mtd, oob, mtd->oobsize); - - return 0; -} - -/* - * HW ECC Correction - * - * function called after a read - * - * mtd: MTD block structure - * dat: raw data read from the chip - * read_ecc: ECC from the chip (unused) - * isnull: unused - * - * Detect and correct a 1 bit error for a page - */ -static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *isnull) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - unsigned int ecc_status; - unsigned int ecc_word, ecc_bit; - - /* get the status from the Status Register */ - ecc_status = ecc_readl(host->ecc, SR); - - /* if there's no error */ - if (likely(!(ecc_status & AT91_ECC_RECERR))) - return 0; - - /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; - /* get word address (12 bits) */ - ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; - ecc_word >>= 4; - - /* if there are multiple errors */ - if (ecc_status & AT91_ECC_MULERR) { - /* check if it is a freshly erased block - * (filled with 0xff) */ - if ((ecc_bit == AT91_ECC_BITADDR) - && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { - /* the block has just been erased, return OK */ - return 0; - } - /* it doesn't seems to be a freshly - * erased block. - * We can't correct so many errors */ - dev_dbg(host->dev, "at91_nand : multiple errors detected." - " Unable to correct.\n"); - return -EIO; - } - - /* if there's a single bit error : we can correct it */ - if (ecc_status & AT91_ECC_ECCERR) { - /* there's nothing much to do here. - * the bit error is on the ECC itself. - */ - dev_dbg(host->dev, "at91_nand : one bit error on ECC code." - " Nothing to correct\n"); - return 0; - } - - dev_dbg(host->dev, "at91_nand : one bit error on data." - " (word offset in the page :" - " 0x%x bit offset : 0x%x)\n", - ecc_word, ecc_bit); - /* correct the error */ - if (nand_chip->options & NAND_BUSWIDTH_16) { - /* 16 bits words */ - ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); - } else { - /* 8 bits words */ - dat[ecc_word] ^= (1 << ecc_bit); - } - dev_dbg(host->dev, "at91_nand : error corrected\n"); - return 1; -} - -/* - * Enable HW ECC : unsused - */ -static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } - -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - -/* - * Probe for the NAND device. - */ -static int __init at91_nand_probe(struct platform_device *pdev) -{ - struct at91_nand_host *host; - struct mtd_info *mtd; - struct nand_chip *nand_chip; - struct resource *regs; - struct resource *mem; - int res; - -#ifdef CONFIG_MTD_PARTITIONS - struct mtd_partition *partitions = NULL; - int num_partitions = 0; -#endif - - /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); - return -ENOMEM; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); - return -ENXIO; - } - - host->io_base = ioremap(mem->start, mem->end - mem->start + 1); - if (host->io_base == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); - kfree(host); - return -EIO; - } - - mtd = &host->mtd; - nand_chip = &host->nand_chip; - host->board = pdev->dev.platform_data; - host->dev = &pdev->dev; - - nand_chip->priv = host; /* link the private data structures */ - mtd->priv = nand_chip; - mtd->owner = THIS_MODULE; - - /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = host->io_base; - nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; - - if (host->board->rdy_pin) - nand_chip->dev_ready = at91_nand_device_ready; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!regs && hard_ecc) { - printk(KERN_ERR "at91_nand: can't get I/O resource " - "regs\nFalling back on software ECC\n"); - } - - nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ - if (no_ecc) - nand_chip->ecc.mode = NAND_ECC_NONE; - if (hard_ecc && regs) { - host->ecc = ioremap(regs->start, regs->end - regs->start + 1); - if (host->ecc == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); - res = -EIO; - goto err_ecc_ioremap; - } - nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; - nand_chip->ecc.calculate = at91_nand_calculate; - nand_chip->ecc.correct = at91_nand_correct; - nand_chip->ecc.hwctl = at91_nand_hwctl; - nand_chip->ecc.read_page = at91_nand_read_page; - nand_chip->ecc.bytes = 4; - nand_chip->ecc.prepad = 0; - nand_chip->ecc.postpad = 0; - } - - nand_chip->chip_delay = 20; /* 20us command delay time */ - - if (host->board->bus_width_16) /* 16-bit bus width */ - nand_chip->options |= NAND_BUSWIDTH_16; - - platform_set_drvdata(pdev, host); - at91_nand_enable(host); - - if (host->board->det_pin) { - if (gpio_get_value(host->board->det_pin)) { - printk ("No SmartMedia card inserted.\n"); - res = ENXIO; - goto out; - } - } - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1)) { - res = -ENXIO; - goto out; - } - - if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { - /* ECC is calculated for the whole page (1 step) */ - nand_chip->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 512: - nand_chip->ecc.layout = &at91_oobinfo_small; - nand_chip->ecc.read_oob = at91_nand_read_oob_512; - nand_chip->ecc.write_oob = at91_nand_write_oob_512; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); - break; - case 1024: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); - break; - case 2048: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); - break; - case 4096: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); - break; - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand_chip->ecc.mode = NAND_ECC_SOFT; - nand_chip->ecc.calculate = NULL; - nand_chip->ecc.correct = NULL; - nand_chip->ecc.hwctl = NULL; - nand_chip->ecc.read_page = NULL; - nand_chip->ecc.postpad = 0; - nand_chip->ecc.prepad = 0; - nand_chip->ecc.bytes = 0; - break; - } - } - - /* second phase scan */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; - goto out; - } - -#ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd->name = "at91_nand"; - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); -#endif - if (num_partitions <= 0 && host->board->partition_info) - partitions = host->board->partition_info(mtd->size, - &num_partitions); - - if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); - res = ENXIO; - goto release; - } - - res = add_mtd_partitions(mtd, partitions, num_partitions); -#else - res = add_mtd_device(mtd); -#endif - - if (!res) - return res; - -#ifdef CONFIG_MTD_PARTITIONS -release: -#endif - nand_release(mtd); - -out: - iounmap(host->ecc); - -err_ecc_ioremap: - at91_nand_disable(host); - platform_set_drvdata(pdev, NULL); - iounmap(host->io_base); - kfree(host); - return res; -} - -/* - * Remove a NAND device. - */ -static int __devexit at91_nand_remove(struct platform_device *pdev) -{ - struct at91_nand_host *host = platform_get_drvdata(pdev); - struct mtd_info *mtd = &host->mtd; - - nand_release(mtd); - - at91_nand_disable(host); - - iounmap(host->io_base); - iounmap(host->ecc); - kfree(host); - - return 0; -} - -static struct platform_driver at91_nand_driver = { - .probe = at91_nand_probe, - .remove = at91_nand_remove, - .driver = { - .name = "at91_nand", - .owner = THIS_MODULE, - }, -}; - -static int __init at91_nand_init(void) -{ - return platform_driver_register(&at91_nand_driver); -} - - -static void __exit at91_nand_exit(void) -{ - platform_driver_unregister(&at91_nand_driver); -} - - -module_init(at91_nand_init); -module_exit(at91_nand_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); -MODULE_ALIAS("platform:at91_nand"); diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c new file mode 100644 index 0000000..51b7031 --- /dev/null +++ b/drivers/mtd/nand/atmel_nand.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2003 Rick Bronson + * + * Derived from drivers/mtd/nand/autcpu12.c + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * + * + * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 + * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 + * + * Derived from Das U-Boot source code + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW +#define hard_ecc 1 +#else +#define hard_ecc 0 +#endif + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE +#define no_ecc 1 +#else +#define no_ecc 0 +#endif + +/* Register access macros */ +#define ecc_readl(add, reg) \ + __raw_readl(add + AT91_ECC_##reg) +#define ecc_writel(add, reg, value) \ + __raw_writel((value), add + AT91_ECC_##reg) + +#include "atmel_nand_ecc.h" /* Hardware ECC registers */ + +/* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout at91_oobinfo_large = { + .eccbytes = 4, + .eccpos = {60, 61, 62, 63}, + .oobfree = { + {2, 58} + }, +}; + +/* oob layout for small page size + * bad block info is on bytes 4 and 5 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout at91_oobinfo_small = { + .eccbytes = 4, + .eccpos = {0, 1, 2, 3}, + .oobfree = { + {6, 10} + }, +}; + +struct at91_nand_host { + struct nand_chip nand_chip; + struct mtd_info mtd; + void __iomem *io_base; + struct at91_nand_data *board; + struct device *dev; + void __iomem *ecc; +}; + +/* + * Enable NAND. + */ +static void at91_nand_enable(struct at91_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 0); +} + +/* + * Disable NAND. + */ +static void at91_nand_disable(struct at91_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 1); +} + +/* + * Hardware specific access to control-lines + */ +static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_NCE) + at91_nand_enable(host); + else + at91_nand_disable(host); + } + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, host->io_base + (1 << host->board->cle)); + else + writeb(cmd, host->io_base + (1 << host->board->ale)); +} + +/* + * Read the Device Ready pin. + */ +static int at91_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + + return gpio_get_value(host->board->rdy_pin); +} + +/* + * write oob for small pages + */ +static int at91_nand_write_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsize = chip->ecc.size, length = mtd->oobsize; + int len, pos, status = 0; + const uint8_t *bufpoi = chip->oob_poi; + + pos = eccsize + chunk; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + len = min_t(int, length, chunk); + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; + +} + +/* + * read oob for small pages + */ +static int at91_nand_read_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + +/* + * Calculate HW ECC + * + * function called after a write + * + * mtd: MTD block structure + * dat: raw data (unused) + * ecc_code: buffer for ECC + */ +static int at91_nand_calculate(struct mtd_info *mtd, + const u_char *dat, unsigned char *ecc_code) +{ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + uint32_t *eccpos = nand_chip->ecc.layout->eccpos; + unsigned int ecc_value; + + /* get the first 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, PR); + + ecc_code[eccpos[0]] = ecc_value & 0xFF; + ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; + + /* get the last 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; + + ecc_code[eccpos[2]] = ecc_value & 0xFF; + ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; + + return 0; +} + +/* + * HW ECC read page function + * + * mtd: mtd info structure + * chip: nand chip info structure + * buf: buffer to store read data + */ +static int at91_nand_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + uint8_t *ecc_pos; + int stat; + + /* read the page */ + chip->read_buf(mtd, p, eccsize); + + /* move to ECC position if needed */ + if (eccpos[0] != 0) { + /* This only works on large pages + * because the ECC controller waits for + * NAND_CMD_RNDOUTSTART after the + * NAND_CMD_RNDOUT. + * anyway, for small pages, the eccpos[0] == 0 + */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + eccpos[0], -1); + } + + /* the ECC controller needs to read the ECC just after the data */ + ecc_pos = oob + eccpos[0]; + chip->read_buf(mtd, ecc_pos, eccbytes); + + /* check if there's an error */ + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + /* get back to oob start (end of page) */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + + /* read the oob */ + chip->read_buf(mtd, oob, mtd->oobsize); + + return 0; +} + +/* + * HW ECC Correction + * + * function called after a read + * + * mtd: MTD block structure + * dat: raw data read from the chip + * read_ecc: ECC from the chip (unused) + * isnull: unused + * + * Detect and correct a 1 bit error for a page + */ +static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *isnull) +{ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + unsigned int ecc_status; + unsigned int ecc_word, ecc_bit; + + /* get the status from the Status Register */ + ecc_status = ecc_readl(host->ecc, SR); + + /* if there's no error */ + if (likely(!(ecc_status & AT91_ECC_RECERR))) + return 0; + + /* get error bit offset (4 bits) */ + ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; + /* get word address (12 bits) */ + ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; + ecc_word >>= 4; + + /* if there are multiple errors */ + if (ecc_status & AT91_ECC_MULERR) { + /* check if it is a freshly erased block + * (filled with 0xff) */ + if ((ecc_bit == AT91_ECC_BITADDR) + && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { + /* the block has just been erased, return OK */ + return 0; + } + /* it doesn't seems to be a freshly + * erased block. + * We can't correct so many errors */ + dev_dbg(host->dev, "at91_nand : multiple errors detected." + " Unable to correct.\n"); + return -EIO; + } + + /* if there's a single bit error : we can correct it */ + if (ecc_status & AT91_ECC_ECCERR) { + /* there's nothing much to do here. + * the bit error is on the ECC itself. + */ + dev_dbg(host->dev, "at91_nand : one bit error on ECC code." + " Nothing to correct\n"); + return 0; + } + + dev_dbg(host->dev, "at91_nand : one bit error on data." + " (word offset in the page :" + " 0x%x bit offset : 0x%x)\n", + ecc_word, ecc_bit); + /* correct the error */ + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* 16 bits words */ + ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); + } else { + /* 8 bits words */ + dat[ecc_word] ^= (1 << ecc_bit); + } + dev_dbg(host->dev, "at91_nand : error corrected\n"); + return 1; +} + +/* + * Enable HW ECC : unsused + */ +static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/* + * Probe for the NAND device. + */ +static int __init at91_nand_probe(struct platform_device *pdev) +{ + struct at91_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *regs; + struct resource *mem; + int res; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; + int num_partitions = 0; +#endif + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); + return -ENOMEM; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); + return -ENXIO; + } + + host->io_base = ioremap(mem->start, mem->end - mem->start + 1); + if (host->io_base == NULL) { + printk(KERN_ERR "at91_nand: ioremap failed\n"); + kfree(host); + return -EIO; + } + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->board = pdev->dev.platform_data; + host->dev = &pdev->dev; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = host->io_base; + nand_chip->IO_ADDR_W = host->io_base; + nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; + + if (host->board->rdy_pin) + nand_chip->dev_ready = at91_nand_device_ready; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!regs && hard_ecc) { + printk(KERN_ERR "at91_nand: can't get I/O resource " + "regs\nFalling back on software ECC\n"); + } + + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + if (no_ecc) + nand_chip->ecc.mode = NAND_ECC_NONE; + if (hard_ecc && regs) { + host->ecc = ioremap(regs->start, regs->end - regs->start + 1); + if (host->ecc == NULL) { + printk(KERN_ERR "at91_nand: ioremap failed\n"); + res = -EIO; + goto err_ecc_ioremap; + } + nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; + nand_chip->ecc.calculate = at91_nand_calculate; + nand_chip->ecc.correct = at91_nand_correct; + nand_chip->ecc.hwctl = at91_nand_hwctl; + nand_chip->ecc.read_page = at91_nand_read_page; + nand_chip->ecc.bytes = 4; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.postpad = 0; + } + + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) /* 16-bit bus width */ + nand_chip->options |= NAND_BUSWIDTH_16; + + platform_set_drvdata(pdev, host); + at91_nand_enable(host); + + if (host->board->det_pin) { + if (gpio_get_value(host->board->det_pin)) { + printk ("No SmartMedia card inserted.\n"); + res = ENXIO; + goto out; + } + } + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1)) { + res = -ENXIO; + goto out; + } + + if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { + /* ECC is calculated for the whole page (1 step) */ + nand_chip->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 512: + nand_chip->ecc.layout = &at91_oobinfo_small; + nand_chip->ecc.read_oob = at91_nand_read_oob_512; + nand_chip->ecc.write_oob = at91_nand_write_oob_512; + ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); + break; + case 1024: + nand_chip->ecc.layout = &at91_oobinfo_large; + ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); + break; + case 2048: + nand_chip->ecc.layout = &at91_oobinfo_large; + ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); + break; + case 4096: + nand_chip->ecc.layout = &at91_oobinfo_large; + ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand_chip->ecc.mode = NAND_ECC_SOFT; + nand_chip->ecc.calculate = NULL; + nand_chip->ecc.correct = NULL; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = NULL; + nand_chip->ecc.postpad = 0; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.bytes = 0; + break; + } + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto out; + } + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd->name = "at91_nand"; + num_partitions = parse_mtd_partitions(mtd, part_probes, + &partitions, 0); +#endif + if (num_partitions <= 0 && host->board->partition_info) + partitions = host->board->partition_info(mtd->size, + &num_partitions); + + if ((!partitions) || (num_partitions == 0)) { + printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); + res = ENXIO; + goto release; + } + + res = add_mtd_partitions(mtd, partitions, num_partitions); +#else + res = add_mtd_device(mtd); +#endif + + if (!res) + return res; + +#ifdef CONFIG_MTD_PARTITIONS +release: +#endif + nand_release(mtd); + +out: + iounmap(host->ecc); + +err_ecc_ioremap: + at91_nand_disable(host); + platform_set_drvdata(pdev, NULL); + iounmap(host->io_base); + kfree(host); + return res; +} + +/* + * Remove a NAND device. + */ +static int __devexit at91_nand_remove(struct platform_device *pdev) +{ + struct at91_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + + at91_nand_disable(host); + + iounmap(host->io_base); + iounmap(host->ecc); + kfree(host); + + return 0; +} + +static struct platform_driver at91_nand_driver = { + .probe = at91_nand_probe, + .remove = at91_nand_remove, + .driver = { + .name = "at91_nand", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_nand_init(void) +{ + return platform_driver_register(&at91_nand_driver); +} + + +static void __exit at91_nand_exit(void) +{ + platform_driver_unregister(&at91_nand_driver); +} + + +module_init(at91_nand_init); +module_exit(at91_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); +MODULE_ALIAS("platform:at91_nand"); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h new file mode 100644 index 0000000..170db86 --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -0,0 +1,36 @@ +/* + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef ATMEL_NAND_ECC_H +#define ATMEL_NAND_ECC_H + +#define AT91_ECC_CR 0x00 /* Control register */ +#define AT91_ECC_RST (1 << 0) /* Reset parity */ + +#define AT91_ECC_MR 0x04 /* Mode register */ +#define AT91_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define AT91_ECC_PAGESIZE_528 (0) +#define AT91_ECC_PAGESIZE_1056 (1) +#define AT91_ECC_PAGESIZE_2112 (2) +#define AT91_ECC_PAGESIZE_4224 (3) + +#define AT91_ECC_SR 0x08 /* Status register */ +#define AT91_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define AT91_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define AT91_ECC_MULERR (1 << 2) /* Multiple Errors */ + +#define AT91_ECC_PR 0x0c /* Parity register */ +#define AT91_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define AT91_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +#define AT91_ECC_NPR 0x10 /* NParity register */ +#define AT91_ECC_NPARITY (0xffff << 0) /* NParity */ + +#endif -- cgit v1.1 From 3c3796cc32b6e53653a5eb868dc959b8c2779db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Skinnemoen?= Date: Fri, 6 Jun 2008 18:04:53 +0200 Subject: [MTD] [NAND] rename at91_nand -> atmel_nand: internal symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is basically s/at91_nand/atmel_nand/g with some manual inspection. Signed-off-by: Håvard Skinnemoen Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 152 +++++++++++++++++++------------------- drivers/mtd/nand/atmel_nand_ecc.h | 34 ++++----- 2 files changed, 93 insertions(+), 93 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 51b7031..675a82c 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -48,9 +48,9 @@ /* Register access macros */ #define ecc_readl(add, reg) \ - __raw_readl(add + AT91_ECC_##reg) + __raw_readl(add + ATMEL_ECC_##reg) #define ecc_writel(add, reg, value) \ - __raw_writel((value), add + AT91_ECC_##reg) + __raw_writel((value), add + ATMEL_ECC_##reg) #include "atmel_nand_ecc.h" /* Hardware ECC registers */ @@ -59,7 +59,7 @@ * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ -static struct nand_ecclayout at91_oobinfo_large = { +static struct nand_ecclayout atmel_oobinfo_large = { .eccbytes = 4, .eccpos = {60, 61, 62, 63}, .oobfree = { @@ -72,7 +72,7 @@ static struct nand_ecclayout at91_oobinfo_large = { * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ -static struct nand_ecclayout at91_oobinfo_small = { +static struct nand_ecclayout atmel_oobinfo_small = { .eccbytes = 4, .eccpos = {0, 1, 2, 3}, .oobfree = { @@ -80,11 +80,11 @@ static struct nand_ecclayout at91_oobinfo_small = { }, }; -struct at91_nand_host { +struct atmel_nand_host { struct nand_chip nand_chip; struct mtd_info mtd; void __iomem *io_base; - struct at91_nand_data *board; + struct atmel_nand_data *board; struct device *dev; void __iomem *ecc; }; @@ -92,7 +92,7 @@ struct at91_nand_host { /* * Enable NAND. */ -static void at91_nand_enable(struct at91_nand_host *host) +static void atmel_nand_enable(struct atmel_nand_host *host) { if (host->board->enable_pin) gpio_set_value(host->board->enable_pin, 0); @@ -101,7 +101,7 @@ static void at91_nand_enable(struct at91_nand_host *host) /* * Disable NAND. */ -static void at91_nand_disable(struct at91_nand_host *host) +static void atmel_nand_disable(struct atmel_nand_host *host) { if (host->board->enable_pin) gpio_set_value(host->board->enable_pin, 1); @@ -110,16 +110,16 @@ static void at91_nand_disable(struct at91_nand_host *host) /* * Hardware specific access to control-lines */ -static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_NCE) - at91_nand_enable(host); + atmel_nand_enable(host); else - at91_nand_disable(host); + atmel_nand_disable(host); } if (cmd == NAND_CMD_NONE) return; @@ -133,10 +133,10 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) /* * Read the Device Ready pin. */ -static int at91_nand_device_ready(struct mtd_info *mtd) +static int atmel_nand_device_ready(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; return gpio_get_value(host->board->rdy_pin); } @@ -144,7 +144,7 @@ static int at91_nand_device_ready(struct mtd_info *mtd) /* * write oob for small pages */ -static int at91_nand_write_oob_512(struct mtd_info *mtd, +static int atmel_nand_write_oob_512(struct mtd_info *mtd, struct nand_chip *chip, int page) { int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; @@ -172,7 +172,7 @@ static int at91_nand_write_oob_512(struct mtd_info *mtd, /* * read oob for small pages */ -static int at91_nand_read_oob_512(struct mtd_info *mtd, +static int atmel_nand_read_oob_512(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) { if (sndcmd) { @@ -192,11 +192,11 @@ static int at91_nand_read_oob_512(struct mtd_info *mtd, * dat: raw data (unused) * ecc_code: buffer for ECC */ -static int at91_nand_calculate(struct mtd_info *mtd, +static int atmel_nand_calculate(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; uint32_t *eccpos = nand_chip->ecc.layout->eccpos; unsigned int ecc_value; @@ -207,7 +207,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; + ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; ecc_code[eccpos[2]] = ecc_value & 0xFF; ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; @@ -222,7 +222,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, * chip: nand chip info structure * buf: buffer to store read data */ -static int at91_nand_read_page(struct mtd_info *mtd, +static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf) { int eccsize = chip->ecc.size; @@ -281,11 +281,11 @@ static int at91_nand_read_page(struct mtd_info *mtd, * * Detect and correct a 1 bit error for a page */ -static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, +static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *isnull) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_status; unsigned int ecc_word, ecc_bit; @@ -293,43 +293,43 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, ecc_status = ecc_readl(host->ecc, SR); /* if there's no error */ - if (likely(!(ecc_status & AT91_ECC_RECERR))) + if (likely(!(ecc_status & ATMEL_ECC_RECERR))) return 0; /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; + ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; /* get word address (12 bits) */ - ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; + ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; ecc_word >>= 4; /* if there are multiple errors */ - if (ecc_status & AT91_ECC_MULERR) { + if (ecc_status & ATMEL_ECC_MULERR) { /* check if it is a freshly erased block * (filled with 0xff) */ - if ((ecc_bit == AT91_ECC_BITADDR) - && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { + if ((ecc_bit == ATMEL_ECC_BITADDR) + && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { /* the block has just been erased, return OK */ return 0; } /* it doesn't seems to be a freshly * erased block. * We can't correct so many errors */ - dev_dbg(host->dev, "at91_nand : multiple errors detected." + dev_dbg(host->dev, "atmel_nand : multiple errors detected." " Unable to correct.\n"); return -EIO; } /* if there's a single bit error : we can correct it */ - if (ecc_status & AT91_ECC_ECCERR) { + if (ecc_status & ATMEL_ECC_ECCERR) { /* there's nothing much to do here. * the bit error is on the ECC itself. */ - dev_dbg(host->dev, "at91_nand : one bit error on ECC code." + dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." " Nothing to correct\n"); return 0; } - dev_dbg(host->dev, "at91_nand : one bit error on data." + dev_dbg(host->dev, "atmel_nand : one bit error on data." " (word offset in the page :" " 0x%x bit offset : 0x%x)\n", ecc_word, ecc_bit); @@ -341,14 +341,14 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, /* 8 bits words */ dat[ecc_word] ^= (1 << ecc_bit); } - dev_dbg(host->dev, "at91_nand : error corrected\n"); + dev_dbg(host->dev, "atmel_nand : error corrected\n"); return 1; } /* * Enable HW ECC : unsused */ -static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) { ; } #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { "cmdlinepart", NULL }; @@ -357,9 +357,9 @@ static const char *part_probes[] = { "cmdlinepart", NULL }; /* * Probe for the NAND device. */ -static int __init at91_nand_probe(struct platform_device *pdev) +static int __init atmel_nand_probe(struct platform_device *pdev) { - struct at91_nand_host *host; + struct atmel_nand_host *host; struct mtd_info *mtd; struct nand_chip *nand_chip; struct resource *regs; @@ -372,21 +372,21 @@ static int __init at91_nand_probe(struct platform_device *pdev) #endif /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); + host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); if (!host) { - printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); + printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); return -ENOMEM; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { - printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); + printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); return -ENXIO; } host->io_base = ioremap(mem->start, mem->end - mem->start + 1); if (host->io_base == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); + printk(KERN_ERR "atmel_nand: ioremap failed\n"); kfree(host); return -EIO; } @@ -403,14 +403,14 @@ static int __init at91_nand_probe(struct platform_device *pdev) /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; + nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; if (host->board->rdy_pin) - nand_chip->dev_ready = at91_nand_device_ready; + nand_chip->dev_ready = atmel_nand_device_ready; regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!regs && hard_ecc) { - printk(KERN_ERR "at91_nand: can't get I/O resource " + printk(KERN_ERR "atmel_nand: can't get I/O resource " "regs\nFalling back on software ECC\n"); } @@ -420,15 +420,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) if (hard_ecc && regs) { host->ecc = ioremap(regs->start, regs->end - regs->start + 1); if (host->ecc == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); + printk(KERN_ERR "atmel_nand: ioremap failed\n"); res = -EIO; goto err_ecc_ioremap; } nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; - nand_chip->ecc.calculate = at91_nand_calculate; - nand_chip->ecc.correct = at91_nand_correct; - nand_chip->ecc.hwctl = at91_nand_hwctl; - nand_chip->ecc.read_page = at91_nand_read_page; + nand_chip->ecc.calculate = atmel_nand_calculate; + nand_chip->ecc.correct = atmel_nand_correct; + nand_chip->ecc.hwctl = atmel_nand_hwctl; + nand_chip->ecc.read_page = atmel_nand_read_page; nand_chip->ecc.bytes = 4; nand_chip->ecc.prepad = 0; nand_chip->ecc.postpad = 0; @@ -440,7 +440,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) nand_chip->options |= NAND_BUSWIDTH_16; platform_set_drvdata(pdev, host); - at91_nand_enable(host); + atmel_nand_enable(host); if (host->board->det_pin) { if (gpio_get_value(host->board->det_pin)) { @@ -463,22 +463,22 @@ static int __init at91_nand_probe(struct platform_device *pdev) /* set ECC page size and oob layout */ switch (mtd->writesize) { case 512: - nand_chip->ecc.layout = &at91_oobinfo_small; - nand_chip->ecc.read_oob = at91_nand_read_oob_512; - nand_chip->ecc.write_oob = at91_nand_write_oob_512; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); + nand_chip->ecc.layout = &atmel_oobinfo_small; + nand_chip->ecc.read_oob = atmel_nand_read_oob_512; + nand_chip->ecc.write_oob = atmel_nand_write_oob_512; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); break; case 1024: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); break; case 2048: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); break; case 4096: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); break; default: /* page size not handled by HW ECC */ @@ -503,7 +503,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) #ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_CMDLINE_PARTS - mtd->name = "at91_nand"; + mtd->name = "atmel_nand"; num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); #endif @@ -512,7 +512,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) &num_partitions); if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); + printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); res = ENXIO; goto release; } @@ -534,7 +534,7 @@ out: iounmap(host->ecc); err_ecc_ioremap: - at91_nand_disable(host); + atmel_nand_disable(host); platform_set_drvdata(pdev, NULL); iounmap(host->io_base); kfree(host); @@ -544,14 +544,14 @@ err_ecc_ioremap: /* * Remove a NAND device. */ -static int __devexit at91_nand_remove(struct platform_device *pdev) +static int __devexit atmel_nand_remove(struct platform_device *pdev) { - struct at91_nand_host *host = platform_get_drvdata(pdev); + struct atmel_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; nand_release(mtd); - at91_nand_disable(host); + atmel_nand_disable(host); iounmap(host->io_base); iounmap(host->ecc); @@ -560,31 +560,31 @@ static int __devexit at91_nand_remove(struct platform_device *pdev) return 0; } -static struct platform_driver at91_nand_driver = { - .probe = at91_nand_probe, - .remove = at91_nand_remove, +static struct platform_driver atmel_nand_driver = { + .probe = atmel_nand_probe, + .remove = atmel_nand_remove, .driver = { - .name = "at91_nand", + .name = "atmel_nand", .owner = THIS_MODULE, }, }; -static int __init at91_nand_init(void) +static int __init atmel_nand_init(void) { - return platform_driver_register(&at91_nand_driver); + return platform_driver_register(&atmel_nand_driver); } -static void __exit at91_nand_exit(void) +static void __exit atmel_nand_exit(void) { - platform_driver_unregister(&at91_nand_driver); + platform_driver_unregister(&atmel_nand_driver); } -module_init(at91_nand_init); -module_exit(at91_nand_exit); +module_init(atmel_nand_init); +module_exit(atmel_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rick Bronson"); MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); -MODULE_ALIAS("platform:at91_nand"); +MODULE_ALIAS("platform:atmel_nand"); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index 170db86..1ee7f99 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -11,26 +11,26 @@ #ifndef ATMEL_NAND_ECC_H #define ATMEL_NAND_ECC_H -#define AT91_ECC_CR 0x00 /* Control register */ -#define AT91_ECC_RST (1 << 0) /* Reset parity */ +#define ATMEL_ECC_CR 0x00 /* Control register */ +#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ -#define AT91_ECC_MR 0x04 /* Mode register */ -#define AT91_ECC_PAGESIZE (3 << 0) /* Page Size */ -#define AT91_ECC_PAGESIZE_528 (0) -#define AT91_ECC_PAGESIZE_1056 (1) -#define AT91_ECC_PAGESIZE_2112 (2) -#define AT91_ECC_PAGESIZE_4224 (3) +#define ATMEL_ECC_MR 0x04 /* Mode register */ +#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define ATMEL_ECC_PAGESIZE_528 (0) +#define ATMEL_ECC_PAGESIZE_1056 (1) +#define ATMEL_ECC_PAGESIZE_2112 (2) +#define ATMEL_ECC_PAGESIZE_4224 (3) -#define AT91_ECC_SR 0x08 /* Status register */ -#define AT91_ECC_RECERR (1 << 0) /* Recoverable Error */ -#define AT91_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ -#define AT91_ECC_MULERR (1 << 2) /* Multiple Errors */ +#define ATMEL_ECC_SR 0x08 /* Status register */ +#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ -#define AT91_ECC_PR 0x0c /* Parity register */ -#define AT91_ECC_BITADDR (0xf << 0) /* Bit Error Address */ -#define AT91_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ +#define ATMEL_ECC_PR 0x0c /* Parity register */ +#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ -#define AT91_ECC_NPR 0x10 /* NParity register */ -#define AT91_ECC_NPARITY (0xffff << 0) /* NParity */ +#define ATMEL_ECC_NPR 0x10 /* NParity register */ +#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ #endif -- cgit v1.1 From cc0c72e173db70a3a864994b05ebbe59b79b888f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Skinnemoen?= Date: Fri, 6 Jun 2008 18:04:54 +0200 Subject: [MTD] [NAND] atmel_nand: Clean up and fix probe() error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes several bugs in the atmel_nand_probe() error path, including at least one memory leak. Signed-off-by: Håvard Skinnemoen Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 675a82c..325ce29 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -371,6 +371,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev) int num_partitions = 0; #endif + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); + return -ENXIO; + } + /* Allocate memory for the device structure (and zero it) */ host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); if (!host) { @@ -378,17 +384,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) return -ENOMEM; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); - return -ENXIO; - } - host->io_base = ioremap(mem->start, mem->end - mem->start + 1); if (host->io_base == NULL) { printk(KERN_ERR "atmel_nand: ioremap failed\n"); - kfree(host); - return -EIO; + res = -EIO; + goto err_nand_ioremap; } mtd = &host->mtd; @@ -446,14 +446,14 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (gpio_get_value(host->board->det_pin)) { printk ("No SmartMedia card inserted.\n"); res = ENXIO; - goto out; + goto err_no_card; } } /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, 1)) { res = -ENXIO; - goto out; + goto err_scan_ident; } if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { @@ -498,7 +498,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) /* second phase scan */ if (nand_scan_tail(mtd)) { res = -ENXIO; - goto out; + goto err_scan_tail; } #ifdef CONFIG_MTD_PARTITIONS @@ -514,7 +514,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if ((!partitions) || (num_partitions == 0)) { printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); res = ENXIO; - goto release; + goto err_no_partitions; } res = add_mtd_partitions(mtd, partitions, num_partitions); @@ -526,17 +526,19 @@ static int __init atmel_nand_probe(struct platform_device *pdev) return res; #ifdef CONFIG_MTD_PARTITIONS -release: +err_no_partitions: #endif nand_release(mtd); - -out: - iounmap(host->ecc); - -err_ecc_ioremap: +err_scan_tail: +err_scan_ident: +err_no_card: atmel_nand_disable(host); platform_set_drvdata(pdev, NULL); + if (host->ecc) + iounmap(host->ecc); +err_ecc_ioremap: iounmap(host->io_base); +err_nand_ioremap: kfree(host); return res; } @@ -553,8 +555,9 @@ static int __devexit atmel_nand_remove(struct platform_device *pdev) atmel_nand_disable(host); + if (host->ecc) + iounmap(host->ecc); iounmap(host->io_base); - iounmap(host->ecc); kfree(host); return 0; -- cgit v1.1 From 984290ded4ee3834ca913fe361afe3bf625cd9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Skinnemoen?= Date: Fri, 6 Jun 2008 18:04:57 +0200 Subject: [MTD] [NAND] atmel_nand: make available on AVR32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the atmel_nand driver selectable on AVR32, and update the Kconfig help text to reflect this. Signed-off-by: Håvard Skinnemoen Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index cdd2952..d8c0d86 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -272,18 +272,18 @@ config MTD_NAND_CS553X If you say "m", the module will be called "cs553x_nand.ko". config MTD_NAND_ATMEL - bool "Support for NAND Flash / SmartMedia on AT91" - depends on ARCH_AT91 + bool "Support for NAND Flash / SmartMedia on AT91 and AVR32" + depends on ARCH_AT91 || AVR32 help Enables support for NAND Flash / Smart Media Card interface - on Atmel AT91 processors. + on Atmel AT91 and AVR32 processors. choice - prompt "ECC management for NAND Flash / SmartMedia on AT91" + prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" depends on MTD_NAND_ATMEL config MTD_NAND_ATMEL_ECC_HW bool "Hardware ECC" - depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 + depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 help Use hardware ECC instead of software ECC when the chip supports it. -- cgit v1.1 From 90574d0a4d4b73308ae54a2a57a4f3f1fa98e984 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 7 Jun 2008 08:49:00 +0100 Subject: [MTD] [NAND] Fix checkpatch warnings which showed up when atmel_nand.c moved Some of them, at least. Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 325ce29..50700ab 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -29,8 +29,8 @@ #include #include -#include -#include +#include +#include #include @@ -444,7 +444,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (host->board->det_pin) { if (gpio_get_value(host->board->det_pin)) { - printk ("No SmartMedia card inserted.\n"); + printk("No SmartMedia card inserted.\n"); res = ENXIO; goto err_no_card; } -- cgit v1.1 From 23a346ca4a5a6f50f81062456af955155f68e313 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 3 Jul 2008 23:40:16 -0700 Subject: [MTD] [NAND] atmel_nand speedup via {read,write}s{b,w}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses __raw_{read,write}s{b,w}() primitives to access data on NAND chips for more efficient I/O. On an arm926 with memory clocked at 100 MHz, this reduced the elapsed time for a 64 MiB read by 16%. ("dd" /dev/mtd0 to /dev/null, with an 8-bit NAND using hardware ECC and 128KiB blocksize.) Also some minor section tweaks: - Use platform_driver_probe() so no pointer to probe() lingers after that code has been removed at run-time. - Use __exit and __exit_p so the remove() code will normally be removed by the linker. Since these buffer read/write calls are new, this increases the runtime code footprint (by 88 bytes on my build, after the section tweaks). [haavard.skinnemoen@atmel.com: rebase onto atmel_nand rename] Signed-off-by: David Brownell Signed-off-by: Håvard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 46 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 50700ab..4814fc9 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -142,6 +142,37 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) } /* + * Minimal-overhead PIO for data access. + */ +static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsb(nand_chip->IO_ADDR_R, buf, len); +} + +static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); +} + +static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesb(nand_chip->IO_ADDR_W, buf, len); +} + +static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); +} + +/* * write oob for small pages */ static int atmel_nand_write_oob_512(struct mtd_info *mtd, @@ -436,8 +467,14 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 20; /* 20us command delay time */ - if (host->board->bus_width_16) /* 16-bit bus width */ + if (host->board->bus_width_16) { /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; + nand_chip->read_buf = atmel_read_buf16; + nand_chip->write_buf = atmel_write_buf16; + } else { + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; + } platform_set_drvdata(pdev, host); atmel_nand_enable(host); @@ -546,7 +583,7 @@ err_nand_ioremap: /* * Remove a NAND device. */ -static int __devexit atmel_nand_remove(struct platform_device *pdev) +static int __exit atmel_nand_remove(struct platform_device *pdev) { struct atmel_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; @@ -564,8 +601,7 @@ static int __devexit atmel_nand_remove(struct platform_device *pdev) } static struct platform_driver atmel_nand_driver = { - .probe = atmel_nand_probe, - .remove = atmel_nand_remove, + .remove = __exit_p(atmel_nand_remove), .driver = { .name = "atmel_nand", .owner = THIS_MODULE, @@ -574,7 +610,7 @@ static struct platform_driver atmel_nand_driver = { static int __init atmel_nand_init(void) { - return platform_driver_register(&atmel_nand_driver); + return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); } -- cgit v1.1 From d6248fddf717041f25781050e6392cc76525272d Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 3 Jul 2008 23:40:18 -0700 Subject: [MTD] [NAND] atmel_nand: Work around AT32AP7000 ECC erratum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ALE signal isn't correctly wired up to the ECC controller on the AP7000, so it starts calculating ECC during the address cycles. Work around this by resetting the ECC controller between the address and data cycles. Signed-off-by: Håvard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 4814fc9..99aec46 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -33,6 +33,7 @@ #include #include +#include #ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW #define hard_ecc 1 @@ -264,6 +265,19 @@ static int atmel_nand_read_page(struct mtd_info *mtd, uint8_t *ecc_pos; int stat; + /* + * Errata: ALE is incorrectly wired up to the ECC controller + * on the AP7000, so it will include the address cycles in the + * ECC calculation. + * + * Workaround: Reset the parity registers before reading the + * actual data. + */ + if (cpu_is_at32ap7000()) { + struct atmel_nand_host *host = chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } + /* read the page */ chip->read_buf(mtd, p, eccsize); @@ -377,9 +391,16 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, } /* - * Enable HW ECC : unsused + * Enable HW ECC : unused on most chips */ -static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) { ; } +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +{ + if (cpu_is_at32ap7000()) { + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } +} #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { "cmdlinepart", NULL }; -- cgit v1.1 From bd5a43822b438f297f4088f1cfd3514e32e56328 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 3 Jul 2008 23:40:19 -0700 Subject: [MTD] [NAND] atmel_nand can be modular MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no reason to prevent the Atmel NAND driver from building as a module. Signed-off-by: David Brownell Signed-off-by: Håvard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index d8c0d86..71406e5 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -272,7 +272,7 @@ config MTD_NAND_CS553X If you say "m", the module will be called "cs553x_nand.ko". config MTD_NAND_ATMEL - bool "Support for NAND Flash / SmartMedia on AT91 and AVR32" + tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" depends on ARCH_AT91 || AVR32 help Enables support for NAND Flash / Smart Media Card interface -- cgit v1.1 From 452db2724351ff3d9416a183a7955e00ab4e6ab4 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 27 Jun 2008 23:04:04 +0400 Subject: [MTD] [NAND] fsl_elbc_nand: fix OOB workability for large page NAND chips For large page chips, nand_bbt is looking into OOB area, and checking for "0xff 0xff" pattern at OOB offset 0. That is, two bytes should be reserved for bbt means. But ELBC driver is specifying ecclayout so that oobfree area starts at offset 1, so only one byte left for the bbt purposes. This causes problems with any OOB users, namely JFFS2: after first mount JFFS2 will fill all OOBs with "erased marker", so OOBs will contain: OOB Data: ff 19 85 20 03 00 ff ff ff 00 00 08 ff ff ff ff OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff And on the next boot, NAND core will rescan for bad blocks, then will see "0xff 0x19" pattern, and will mark all blocks as bad ones. To fix the issue we should implement our own bad block pattern: just one byte at OOB start. Though, this will work only for x8 chips. For x16 chips two bytes must be checked. Since ELBC driver does not support x16 NANDs (yet), we're safe for now. Signed-off-by: Anton Vorontsov Acked-by: Scott Wood Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 1b06d29..99dc2be 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -116,6 +116,20 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { .oobavail = 48, }; +/* + * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset + * 1, so we have to adjust bad block pattern. This pattern should be used for + * x8 chips only. So far hardware does not support x16 chips anyway. + */ +static u8 scan_ff_pattern[] = { 0xff, }; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern, +}; + /*=================================*/ /* @@ -687,6 +701,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->ecc.layout = (priv->fmr & FMR_ECCM) ? &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; + chip->badblock_pattern = &largepage_memorybased; mtd->ecclayout = chip->ecc.layout; mtd->oobavail = chip->ecc.layout->oobavail; } -- cgit v1.1 From ec6e0ea3bdf82ee9761d324c011c3627821f7410 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 27 Jun 2008 23:04:13 +0400 Subject: [MTD] [NAND] fsl_elbc_nand: implement support for flash-based BBT This patch implements support for flash-based BBT for chips working through ELBC NAND controller, so that NAND core will not have to re-scan for bad blocks on every boot. Because ELBC controller may provide HW-generated ECCs we should adjust bbt pattern and bbt version positions in the OOB free area. Signed-off-by: Anton Vorontsov Acked-by: Scott Wood Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 99dc2be..5f1bc5e 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -130,6 +130,34 @@ static struct nand_bbt_descr largepage_memorybased = { .pattern = scan_ff_pattern, }; +/* + * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, + * interfere with ECC positions, that's why we implement our own descriptors. + * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. + */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + /*=================================*/ /* @@ -767,8 +795,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->cmdfunc = fsl_elbc_cmdfunc; chip->waitfunc = fsl_elbc_wait; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | + NAND_USE_FLASH_BBT; chip->controller = &ctrl->controller; chip->priv = priv; -- cgit v1.1 From 0acf944c6853813ed19cdf46d4042a77dd878ab5 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 27 Jun 2008 23:04:20 +0400 Subject: [MTD] [NAND] fsl_elbc_nand: ecclayout cleanups This patch deletes oobavail assignments, they're calculated by the nand core code in nand_scan_tail, plus current oobavail values are wrong for the LP NANDs. Also remove mtd->ecclayout and mtd->oobavail assignments, mtd core handles this all by itself. Signed-off-by: Anton Vorontsov Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 5f1bc5e..d6d1ff5 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -89,7 +89,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { .eccbytes = 3, .eccpos = {6, 7, 8}, .oobfree = { {0, 5}, {9, 7} }, - .oobavail = 12, }; /* Small Page FLASH with FMR[ECCM] = 1 */ @@ -97,7 +96,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { .eccbytes = 3, .eccpos = {8, 9, 10}, .oobfree = { {0, 5}, {6, 2}, {11, 5} }, - .oobavail = 12, }; /* Large Page FLASH with FMR[ECCM] = 0 */ @@ -105,7 +103,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { .eccbytes = 12, .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, - .oobavail = 48, }; /* Large Page FLASH with FMR[ECCM] = 1 */ @@ -113,7 +110,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { .eccbytes = 12, .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, - .oobavail = 48, }; /* @@ -730,8 +726,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; chip->badblock_pattern = &largepage_memorybased; - mtd->ecclayout = chip->ecc.layout; - mtd->oobavail = chip->ecc.layout->oobavail; } } else { dev_err(ctrl->dev, -- cgit v1.1 From f63af11ddb508ce7b2a270515244d145248cad7f Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 10 Jul 2008 16:14:18 -0500 Subject: [MTD] [NAND] remove __PPC__ hardcoded address from DiskOnChip drivers Such a hardcoded address can cause a checkstop or machine check if the driver is in the kernel but the address is not acknowledged. Both drivers allow an address to be specified as either a module parameter or config option. Any future powerpc board should either use one of these methods or find the address in the device tree. Signed-off-by: Milton Miller Signed-off-by: David Woodhouse --- drivers/mtd/nand/diskonchip.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index cd4393c..765d4f0 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -52,8 +52,6 @@ static unsigned long __initdata doc_locations[] = { 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#elif defined(__PPC__) - 0xe4000000, #else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif -- cgit v1.1 From 55679df30dfa37886cd9e22d8dea0e6974a552df Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 14 Jul 2008 19:20:37 +0400 Subject: [MTD] [NAND] fsl_elbc_nand: fix section mismatch with CONFIG_MTD_OF_PARTS=y With CONFIG_MTD_OF_PARTS=y I'm getting this new section mismatch in reference from the function fsl_elbc_chip_probe() to the function .devinit.text:of_mtd_parse_partitions() This patch fixes the mismatch by providing __devinit annotation to the fsl_elbc_chip_probe() function. Signed-off-by: Anton Vorontsov Acked-By: Scott Wood Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index d6d1ff5..9dff513 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -836,8 +836,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) return 0; } -static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, - struct device_node *node) +static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, + struct device_node *node) { struct fsl_lbc_regs __iomem *lbc = ctrl->regs; struct fsl_elbc_mtd *priv; -- cgit v1.1 From ee39a0e61b8a307576b5e26057f8257444b5c9c1 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 15 Jul 2008 23:04:35 +0900 Subject: [MTD][NAND] au1550nd: remove unused variable Remove unused variable from au1550 NAND driver. Signed-off-by: Yoichi Yuasa Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 22ad9f3..761946e 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -602,8 +602,6 @@ module_init(au1xxx_nand_init); */ static void __exit au1550_cleanup(void) { - struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; - /* Release resources, unregister device */ nand_release(au1550_mtd); -- cgit v1.1 From 30821fee4f0cb3e6d241d9f7ddc37742212e3eb7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 15 Jul 2008 11:58:31 +0100 Subject: CPUFREQ: S3C24XX NAND driver frequency scaling support. Add support for CPU frequency scalling to the S3C24XX NAND driver. Signed-off-by: Ben Dooks Signed-off-by: David Woodhouse --- drivers/mtd/nand/s3c2410.c | 143 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 21 deletions(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 35c6db5..556139e 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -104,8 +105,13 @@ struct s3c2410_nand_info { int sel_bit; int mtd_count; unsigned long save_sel; + unsigned long clk_rate; enum s3c_cpu_type cpu_type; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif }; /* conversion functions */ @@ -163,17 +169,18 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) /* controller setup */ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, - struct platform_device *pdev) +static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) { - struct s3c2410_platform_nand *plat = to_nand_plat(pdev); - unsigned long clkrate = clk_get_rate(info->clk); + struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; - unsigned long cfg = 0; + unsigned long clkrate = clk_get_rate(info->clk); + unsigned long set, cfg, mask; + unsigned long flags; /* calculate the timing information for the controller */ + info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { @@ -195,28 +202,69 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); + switch (info->cpu_type) { + case TYPE_S3C2410: + mask = (S3C2410_NFCONF_TACLS(3) | + S3C2410_NFCONF_TWRPH0(7) | + S3C2410_NFCONF_TWRPH1(7)); + set = S3C2410_NFCONF_EN; + set |= S3C2410_NFCONF_TACLS(tacls - 1); + set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); + set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + break; + + case TYPE_S3C2440: + case TYPE_S3C2412: + mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | + S3C2410_NFCONF_TWRPH0(7) | + S3C2410_NFCONF_TWRPH1(7)); + + set = S3C2440_NFCONF_TACLS(tacls - 1); + set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); + set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); + break; + + default: + /* keep compiler happy */ + mask = 0; + set = 0; + BUG(); + } + + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); + + local_irq_save(flags); + + cfg = readl(info->regs + S3C2410_NFCONF); + cfg &= ~mask; + cfg |= set; + writel(cfg, info->regs + S3C2410_NFCONF); + + local_irq_restore(flags); + + return 0; +} + +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) +{ + int ret; + + ret = s3c2410_nand_setrate(info); + if (ret < 0) + return ret; + switch (info->cpu_type) { case TYPE_S3C2410: - cfg = S3C2410_NFCONF_EN; - cfg |= S3C2410_NFCONF_TACLS(tacls - 1); - cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); - cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + default: break; case TYPE_S3C2440: case TYPE_S3C2412: - cfg = S3C2440_NFCONF_TACLS(tacls - 1); - cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); - cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); - /* enable the controller and de-assert nFCE */ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); } - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); - - writel(cfg, info->regs + S3C2410_NFCONF); return 0; } @@ -497,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int writesl(info->regs + S3C2440_NFDATA, buf, len / 4); } +/* cpufreq driver support */ + +#ifdef CONFIG_CPU_FREQ + +static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct s3c2410_nand_info *info; + unsigned long newclk; + + info = container_of(nb, struct s3c2410_nand_info, freq_transition); + newclk = clk_get_rate(info->clk); + + if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || + (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { + s3c2410_nand_setrate(info); + } + + return 0; +} + +static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) +{ + info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; + + return cpufreq_register_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) +{ + cpufreq_unregister_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) +{ + return 0; +} + +static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) +{ +} +#endif + /* device management functions */ static int s3c2410_nand_remove(struct platform_device *pdev) @@ -508,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; - /* first thing we need to do is release all our mtds - * and their partitions, then go through freeing the - * resources used + s3c2410_nand_cpufreq_deregister(info); + + /* Release all our mtds and their partitions, then go through + * freeing the resources used */ if (info->mtds != NULL) { @@ -769,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, /* initialise the hardware */ - err = s3c2410_nand_inithw(info, pdev); + err = s3c2410_nand_inithw(info); if (err != 0) goto exit_error; @@ -812,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, sets++; } + err = s3c2410_nand_cpufreq_register(info); + if (err < 0) { + dev_err(&pdev->dev, "failed to init cpufreq support\n"); + goto exit_error; + } + if (allow_clk_stop(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); clk_disable(info->clk); @@ -859,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) if (info) { clk_enable(info->clk); - s3c2410_nand_inithw(info, dev); + s3c2410_nand_inithw(info); /* Restore the state of the nFCE line. */ -- cgit v1.1 From 3d45955962496879dead8d4dd70bb9a23b07154b Mon Sep 17 00:00:00 2001 From: Alexey Korolev Date: Thu, 15 May 2008 17:23:18 +0100 Subject: [MTD] [NAND] subpage read feature as a way to increase performance. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables NAND subpage read functionality. If upper layer drivers are requesting to read non page aligned data NAND subpage-read functionality reads the only whose ECC regions which include requested data when original code reads whole page. This significantly improves performance in many cases. Here are some digits : UBI volume mount time No subpage reads: 5.75 seconds Subpage read patch: 2.42 seconds Open/stat time for files on JFFS2 volume: No subpage read 0m 5.36s Subpage read 0m 2.88s Signed-off-by Alexey Korolev Acked-by: Artem Bityutskiy Acked-by: Jörn Engel Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 87 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba1bdf7..d1129ba 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -798,6 +798,87 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** + * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @dataofs offset of requested data within the page + * @readlen data length + * @buf: buffer to store read data + */ +static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) +{ + int start_step, end_step, num_steps; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p; + int data_col_addr, i, gaps = 0; + int datafrag_len, eccfrag_len, aligned_len, aligned_pos; + int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + + /* Column address wihin the page aligned to ECC size (256bytes). */ + start_step = data_offs / chip->ecc.size; + end_step = (data_offs + readlen - 1) / chip->ecc.size; + num_steps = end_step - start_step + 1; + + /* Data size aligned to ECC ecc.size*/ + datafrag_len = num_steps * chip->ecc.size; + eccfrag_len = num_steps * chip->ecc.bytes; + + data_col_addr = start_step * chip->ecc.size; + /* If we read not a page aligned data */ + if (data_col_addr != 0) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); + + p = bufpoi + data_col_addr; + chip->read_buf(mtd, p, datafrag_len); + + /* Calculate ECC */ + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) + chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); + + /* The performance is faster if to position offsets + according to ecc.pos. Let make sure here that + there are no gaps in ecc positions */ + for (i = 0; i < eccfrag_len - 1; i++) { + if (eccpos[i + start_step * chip->ecc.bytes] + 1 != + eccpos[i + start_step * chip->ecc.bytes + 1]) { + gaps = 1; + break; + } + } + if (gaps) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + } else { + /* send the command to read the particular ecc bytes */ + /* take care about buswidth alignment in read_buf */ + aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); + aligned_len = eccfrag_len; + if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) + aligned_len++; + if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) + aligned_len++; + + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); + chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); + } + + for (i = 0; i < eccfrag_len; i++) + chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; + + p = bufpoi + data_col_addr; + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { + int stat; + + stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat == -1) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure @@ -994,6 +1075,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Now read the page into the buffer */ if (unlikely(ops->mode == MTD_OOB_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) + ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi); if (ret < 0) @@ -1001,7 +1084,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { - chip->pagebuf = realpage; + if (!NAND_SUBPAGE_READ(chip) && !oob) + chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -2521,6 +2605,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.calculate = nand_calculate_ecc; chip->ecc.correct = nand_correct_data; chip->ecc.read_page = nand_read_page_swecc; + chip->ecc.read_subpage = nand_read_subpage; chip->ecc.write_page = nand_write_page_swecc; chip->ecc.read_oob = nand_read_oob_std; chip->ecc.write_oob = nand_write_oob_std; -- cgit v1.1