From 26a6d240e2a1480a33d76ac4db8855b6a7f2bd89 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 20:11:26 +0100 Subject: mtd: make mtd_partition.name const This allows to drop a few casts. Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris --- include/linux/mtd/partitions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 1f8d24bdafd..335ffca10c1 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -37,7 +37,7 @@ */ struct mtd_partition { - char *name; /* identifier string */ + const char *name; /* identifier string */ uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ @@ -80,7 +80,7 @@ extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); -int mtd_add_partition(struct mtd_info *master, char *name, +int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length); int mtd_del_partition(struct mtd_info *master, int partno); uint64_t mtd_get_device_size(const struct mtd_info *mtd); -- cgit v1.2.3 From 776f265e279744e3f327ccd3e7eb378046311373 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:28 -0300 Subject: mtd: nand: pxa3xx: Add bad block handling Add support for flash-based bad block table using Marvell's custom in-flash bad block table layout. The support is enabled a 'flash_bbt' platform data or device tree parameter. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/pxa3xx-nand.txt | 2 ++ drivers/mtd/nand/pxa3xx_nand.c | 37 ++++++++++++++++++++++ include/linux/platform_data/mtd-nand-pxa3xx.h | 3 ++ 3 files changed, 42 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index bed83908edf..86e0a5601ff 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -15,6 +15,8 @@ Optional properties: - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader - num-cs: Number of chipselect lines to usw + - nand-on-flash-bbt: boolean to enable on flash bbt option if + not present false Example: diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a30116bfff4..84a6c649100 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #define ARCH_HAS_DMA @@ -241,6 +242,29 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, }; +static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; +static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; + +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 = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .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 = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_mirror_pattern +}; + /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) @@ -1122,6 +1146,18 @@ KEEP_CONFIG: if (nand_scan_ident(mtd, 1, def)) return -ENODEV; + + if (pdata->flash_bbt) { + /* + * We'll use a bad block table stored in-flash and don't + * allow writing the bad block marker to the flash. + */ + chip->bbt_options |= NAND_BBT_USE_FLASH | + NAND_BBT_NO_OOB_BBM; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + } + /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2; @@ -1316,6 +1352,7 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev) if (of_get_property(np, "marvell,nand-keep-config", NULL)) pdata->keep_config = 1; of_property_read_u32(np, "num-cs", &pdata->num_cs); + pdata->flash_bbt = of_get_nand_on_flash_bbt(np); pdev->dev.platform_data = pdata; diff --git a/include/linux/platform_data/mtd-nand-pxa3xx.h b/include/linux/platform_data/mtd-nand-pxa3xx.h index ffb801998e5..a9414712492 100644 --- a/include/linux/platform_data/mtd-nand-pxa3xx.h +++ b/include/linux/platform_data/mtd-nand-pxa3xx.h @@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data { /* indicate how many chip selects will be used */ int num_cs; + /* use an flash-based bad block table */ + bool flash_bbt; + const struct mtd_partition *parts[NUM_CHIP_SELECT]; unsigned int nr_parts[NUM_CHIP_SELECT]; -- cgit v1.2.3 From a55e85ce9bee97df63f85547a5e72df14851b338 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 2 Dec 2013 11:12:22 -0800 Subject: mtd: nand: fix misspelling in ONFI parameter field name s/strenght/strength/ This field isn't used anywhere, so this rename is safe. Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9e6c8f9f306..f3ea8daf08e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -279,7 +279,7 @@ struct nand_onfi_params { __le16 io_pin_capacitance_typ; __le16 input_pin_capacitance_typ; u8 input_pin_capacitance_max; - u8 driver_strenght_support; + u8 driver_strength_support; __le16 t_int_r; __le16 t_ald; u8 reserved4[7]; -- cgit v1.2.3 From e0b6047b73278d165ae0ad448177209a3c2067ad Mon Sep 17 00:00:00 2001 From: Philipp Rosenberger Date: Thu, 28 Nov 2013 12:36:52 +0100 Subject: of_mtd: fix header file include guard It seems the include guard was copied from of_net.h. Signed-off-by: Philipp Rosenberger Signed-off-by: Brian Norris --- include/linux/of_mtd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h index 6f10e938ff7..cb32d9c1e8d 100644 --- a/include/linux/of_mtd.h +++ b/include/linux/of_mtd.h @@ -7,7 +7,7 @@ */ #ifndef __LINUX_OF_MTD_H -#define __LINUX_OF_NET_H +#define __LINUX_OF_MTD_H #ifdef CONFIG_OF_MTD -- cgit v1.2.3 From cf3b2b1e24998ba67ca6defa71899bee2432046f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Dec 2013 18:59:15 +0800 Subject: mtd: make deregister_mtd_parser return void deregister_mtd_parser never fails; hence make it return void. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/mtdpart.c | 3 +-- include/linux/mtd/partitions.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 67a89bb4594..29ee91e6a70 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -682,12 +682,11 @@ int register_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(register_mtd_parser); -int deregister_mtd_parser(struct mtd_part_parser *p) +void deregister_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_del(&p->list); spin_unlock(&part_parser_lock); - return 0; } EXPORT_SYMBOL_GPL(deregister_mtd_parser); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 335ffca10c1..d513ffbd804 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -77,7 +77,7 @@ struct mtd_part_parser { }; extern int register_mtd_parser(struct mtd_part_parser *parser); -extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern void deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, const char *name, -- cgit v1.2.3 From 6e14a61d412eb87ef7bdcec8b08a95bead771a78 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Dec 2013 19:01:06 +0800 Subject: mtd: make register_mtd_parser return void register_mtd_parser never fails; hence make it return void. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/afs.c | 3 ++- drivers/mtd/ar7part.c | 3 ++- drivers/mtd/bcm47xxpart.c | 3 ++- drivers/mtd/bcm63xxpart.c | 3 ++- drivers/mtd/cmdlinepart.c | 3 ++- drivers/mtd/mtdpart.c | 4 +--- drivers/mtd/ofpart.c | 15 +++------------ drivers/mtd/redboot.c | 3 ++- include/linux/mtd/partitions.h | 2 +- 9 files changed, 17 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 5a3942bf109..96a33e3f7b0 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = { static int __init afs_parser_init(void) { - return register_mtd_parser(&afs_parser); + register_mtd_parser(&afs_parser); + return 0; } static void __exit afs_parser_exit(void) diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index ddc0a4287a4..7c9172ad262 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = { static int __init ar7_parser_init(void) { - return register_mtd_parser(&ar7_parser); + register_mtd_parser(&ar7_parser); + return 0; } static void __exit ar7_parser_exit(void) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 7a6384b0962..931746ded98 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -243,7 +243,8 @@ static struct mtd_part_parser bcm47xxpart_mtd_parser = { static int __init bcm47xxpart_init(void) { - return register_mtd_parser(&bcm47xxpart_mtd_parser); + register_mtd_parser(&bcm47xxpart_mtd_parser); + return 0; } static void __exit bcm47xxpart_exit(void) diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 5c813907661..b2443f7031c 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = { static int __init bcm63xx_cfe_parser_init(void) { - return register_mtd_parser(&bcm63xx_cfe_parser); + register_mtd_parser(&bcm63xx_cfe_parser); + return 0; } static void __exit bcm63xx_cfe_parser_exit(void) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 721caebbc5c..3e829b37af8 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void) { if (mtdparts) mtdpart_setup(mtdparts); - return register_mtd_parser(&cmdline_parser); + register_mtd_parser(&cmdline_parser); + return 0; } static void __exit cmdline_parser_exit(void) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 29ee91e6a70..3c7d6d7623c 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -672,13 +672,11 @@ static struct mtd_part_parser *get_partition_parser(const char *name) #define put_partition_parser(p) do { module_put((p)->owner); } while (0) -int register_mtd_parser(struct mtd_part_parser *p) +void register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); - - return 0; } EXPORT_SYMBOL_GPL(register_mtd_parser); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index f0a708bf9b0..aa26c32e1bc 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = { static int __init ofpart_parser_init(void) { - int rc; - rc = register_mtd_parser(&ofpart_parser); - if (rc) - goto out; - - rc = register_mtd_parser(&ofoldpart_parser); - if (!rc) - return 0; - - deregister_mtd_parser(&ofoldpart_parser); -out: - return rc; + register_mtd_parser(&ofpart_parser); + register_mtd_parser(&ofoldpart_parser); + return 0; } static void __exit ofpart_parser_exit(void) diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 580035c803d..5da911ebdf4 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot"); static int __init redboot_parser_init(void) { - return register_mtd_parser(&redboot_parser); + register_mtd_parser(&redboot_parser); + return 0; } static void __exit redboot_parser_exit(void) diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index d513ffbd804..6a35e6de5da 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -76,7 +76,7 @@ struct mtd_part_parser { struct mtd_part_parser_data *); }; -extern int register_mtd_parser(struct mtd_part_parser *parser); +extern void register_mtd_parser(struct mtd_part_parser *parser); extern void deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); -- cgit v1.2.3 From 111b5a317677d09fd6e2a1dc532f32b4df745166 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Dec 2013 12:00:20 +0530 Subject: mtd: omap2: Cleanup header files Commit 2203747c9771 ("ARM: omap: move platform_data definitions") moved the files to the current location but forgot to remove the pointer to its previous location. Clean it up. Signed-off-by: Sachin Kamat Acked-by: Pekon Gupta Signed-off-by: Brian Norris --- include/linux/platform_data/mtd-nand-omap2.h | 2 -- include/linux/platform_data/mtd-onenand-omap2.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 4da5bfa2147..3e9dd6676b9 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -1,6 +1,4 @@ /* - * arch/arm/plat-omap/include/mach/nand.h - * * Copyright (C) 2006 Micron Technology Inc. * * This program is free software; you can redistribute it and/or modify diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h index e9a9fb188f9..56ff0e6f5ad 100644 --- a/include/linux/platform_data/mtd-onenand-omap2.h +++ b/include/linux/platform_data/mtd-onenand-omap2.h @@ -1,6 +1,4 @@ /* - * arch/arm/plat-omap/include/mach/onenand.h - * * Copyright (C) 2006 Nokia Corporation * Author: Juha Yrjola * -- cgit v1.2.3 From 6bd8c02753bc0bb8dc14e23004a8effc46906638 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Dec 2013 12:00:21 +0530 Subject: mtd: orion: Cleanup mtd-orion_nand.h header Commit c02cecb92ed4 ("ARM: orion: move platform_data definitions") moved the file to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also change the header file protection macros appropriately. Signed-off-by: Sachin Kamat Signed-off-by: Brian Norris --- include/linux/platform_data/mtd-orion_nand.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/mtd-orion_nand.h b/include/linux/platform_data/mtd-orion_nand.h index 9f3c180834d..a7ce77c7c1a 100644 --- a/include/linux/platform_data/mtd-orion_nand.h +++ b/include/linux/platform_data/mtd-orion_nand.h @@ -1,13 +1,11 @@ /* - * arch/arm/plat-orion/include/plat/orion_nand.h - * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#ifndef __PLAT_ORION_NAND_H -#define __PLAT_ORION_NAND_H +#ifndef __MTD_ORION_NAND_H +#define __MTD_ORION_NAND_H /* * Device bus NAND private data -- cgit v1.2.3 From 6f0065b0124bef5e66869ec0b813d251797be439 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 3 Dec 2013 12:02:20 -0800 Subject: mtd: nand: add ONFI vendor block for Micron Signed-off-by: Brian Norris Acked-by: Huang Shijie --- include/linux/mtd/nand.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index f3ea8daf08e..029fe5948dc 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -285,7 +285,8 @@ struct nand_onfi_params { u8 reserved4[7]; /* vendor */ - u8 reserved5[90]; + __le16 vendor_revision; + u8 vendor[88]; __le16 crc; } __attribute__((packed)); @@ -326,6 +327,26 @@ struct onfi_ext_param_page { */ } __packed; +struct nand_onfi_vendor_micron { + u8 two_plane_read; + u8 read_cache; + u8 read_unique_id; + u8 dq_imped; + u8 dq_imped_num_settings; + u8 dq_imped_feat_addr; + u8 rb_pulldown_strength; + u8 rb_pulldown_strength_feat_addr; + u8 rb_pulldown_strength_num_settings; + u8 otp_mode; + u8 otp_page_start; + u8 otp_data_prot_addr; + u8 otp_num_pages; + u8 otp_feat_addr; + u8 read_retry_options; + u8 reserved[72]; + u8 param_revision; +} __packed; + /** * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices * @lock: protection lock -- cgit v1.2.3 From ba84fb5952af114e28ac82adcdef75297701ccc1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 3 Jan 2014 15:13:33 -0800 Subject: mtd: nand: add generic READ RETRY support Modern MLC (and even SLC?) NAND can experience a large number of bitflips (beyond the recommended correctability capacity) due to drifts in the voltage threshold (Vt). These bitflips can cause ECC errors to occur well within the expected lifetime of the flash. To account for this, some manufacturers provide a mechanism for shifting the Vt threshold after a corrupted read. The generic pattern seems to be that a particular flash has N read retry modes (where N = 0, traditionally), and after an ECC failure, the host should reconfigure the flash to use the next available mode, then retry the read operation. This process repeats until all bitfips can be corrected or until the host has tried all available retry modes. This patch adds the infrastructure support for a vendor-specific/flash-specific callback, used for setting the read-retry mode (i.e., voltage threshold). For now, this patch always returns the flash to mode 0 (the default mode) after a successful read-retry, according to the flowchart found in Micron's datasheets. This may need to change in the future if it is determined that eventually, mode 0 is insufficient for the majority of the flash cells (and so for performance reasons, we should leave the flash in mode 1, 2, etc.). Signed-off-by: Brian Norris Acked-by: Huang Shijie --- drivers/mtd/nand/nand_base.c | 56 ++++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/nand.h | 6 +++++ 2 files changed, 58 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b5c3768b32a..4c2f39f351d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1409,6 +1409,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, return NULL; } +/** + * nand_setup_read_retry - [INTERN] Set the READ RETRY mode + * @mtd: MTD device structure + * @retry_mode: the retry mode to use + * + * Some vendors supply a special command to shift the Vt threshold, to be used + * when there are too many bitflips in a page (i.e., ECC error). After setting + * a new threshold, the host should retry reading the page. + */ +static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + + pr_debug("setting READ RETRY mode %d\n", retry_mode); + + if (retry_mode >= chip->read_retries) + return -EINVAL; + + if (!chip->setup_read_retry) + return -EOPNOTSUPP; + + return chip->setup_read_retry(mtd, retry_mode); +} + /** * nand_do_read_ops - [INTERN] Read data with ECC * @mtd: MTD device structure @@ -1430,6 +1454,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint8_t *bufpoi, *oob, *buf; unsigned int max_bitflips = 0; + int retry_mode = 0; bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); @@ -1454,6 +1479,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; +read_retry: chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* @@ -1494,8 +1520,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, memcpy(buf, chip->buffers->databuf + col, bytes); } - buf += bytes; - if (unlikely(oob)) { int toread = min(oobreadlen, max_oobsize); @@ -1514,8 +1538,24 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } - if (mtd->ecc_stats.failed - ecc_failures) - ecc_fail = true; + if (mtd->ecc_stats.failed - ecc_failures) { + if (retry_mode + 1 <= chip->read_retries) { + retry_mode++; + ret = nand_setup_read_retry(mtd, + retry_mode); + if (ret < 0) + break; + + /* Reset failures; retry */ + mtd->ecc_stats.failed = ecc_failures; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_fail = true; + } + } + + buf += bytes; } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1525,6 +1565,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, readlen -= bytes; + /* Reset to retry mode 0 */ + if (retry_mode) { + ret = nand_setup_read_retry(mtd, 0); + if (ret < 0) + break; + retry_mode = 0; + } + if (!readlen) break; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 029fe5948dc..267d61dd89d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -472,6 +472,8 @@ struct nand_buffers { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. + * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for + * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure @@ -518,6 +520,7 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. + * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @bbt: [INTERN] bad block table pointer @@ -565,6 +568,7 @@ struct nand_chip { int feature_addr, uint8_t *subfeature_para); int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); + int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); int chip_delay; unsigned int options; @@ -589,6 +593,8 @@ struct nand_chip { int onfi_version; struct nand_onfi_params onfi_params; + int read_retries; + flstate_t state; uint8_t *oob_poi; -- cgit v1.2.3 From 8429bb3975ef81c114cde4da111e64d224d19f83 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 3 Dec 2013 15:51:09 -0800 Subject: mtd: nand: support Micron READ RETRY Micron provides READ RETRY support via the ONFI vendor-specific parameter block (to indicate how many read-retry modes are available) and the ONFI {GET,SET}_FEATURES commands with a vendor-specific feature address (to support reading/switching the current read-retry mode). The recommended sequence is as follows: 1. Perform PAGE_READ operation 2. If no ECC error, we are done 3. Run SET_FEATURES with feature address 89h, mode 1 4. Retry PAGE_READ operation 5. If ECC error and there are remaining supported modes, increment the mode and return to step 3. Otherwise, this is a true ECC error. 6. Run SET_FEATURES with feature address 89h, mode 0, to return to the default state. This patch implements the chip->setup_read_retry() callback for Micron and fills in the chip->read_retries. Tested on Micron MT29F32G08CBADA, which supports 8 read-retry modes. The Micron vendor-specific table was checked against the datasheets for the following Micron NAND: Needs retry Cell-type Part number Vendor revision Byte 180 ----------- --------- ---------------- --------------- ------------ No SLC MT29F16G08ABABA 1 Reserved (0) No MLC MT29F32G08CBABA 1 Reserved (0) No SLC MT29F1G08AACWP 1 0 Yes MLC MT29F32G08CBADA 1 08h Yes MLC MT29F64G08CBABA 2 08h Signed-off-by: Brian Norris Acked-by: Huang Shijie --- drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++++++++++ include/linux/mtd/nand.h | 3 +++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 4c2f39f351d..b8c74cda762 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2979,6 +2979,30 @@ ext_out: return ret; } +static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; + + return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); +} + +/* + * Configure chip properties from Micron vendor-specific ONFI table + */ +static void nand_onfi_detect_micron(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct nand_onfi_vendor_micron *micron = (void *)p->vendor; + + if (le16_to_cpu(p->vendor_revision) < 1) + return; + + chip->read_retries = micron->read_retry_options; + chip->setup_read_retry = nand_setup_read_retry_micron; +} + /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -3085,6 +3109,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, pr_warn("Could not retrieve ONFI ECC requirements\n"); } + if (p->jedec_id == NAND_MFR_MICRON) + nand_onfi_detect_micron(chip, p); + return 1; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 267d61dd89d..3080a8c8b62 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -219,6 +219,9 @@ struct nand_chip; /* ONFI feature address */ #define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 +/* Vendor-specific feature address (Micron) */ +#define ONFI_FEATURE_ADDR_READ_RETRY 0x89 + /* ONFI subfeature parameters length */ #define ONFI_SUBFEATURE_PARAM_LEN 4 -- cgit v1.2.3 From e2e6b7b7d64baeac1c38fa5eb0d3ec85f3d123f5 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 5 Dec 2013 12:06:54 -0800 Subject: mtd: nand: use __packed shorthand To be consistent with the rest of include/linux/mtd/nand.h, we should use the __packed shorthand instead of __attribute__((packed)). Signed-off-by: Brian Norris Acked-by: Huang Shijie --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 3080a8c8b62..05fcdfea640 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -292,7 +292,7 @@ struct nand_onfi_params { u8 vendor[88]; __le16 crc; -} __attribute__((packed)); +} __packed; #define ONFI_CRC_BASE 0x4F4E -- cgit v1.2.3 From 05f7835975dad6b3b517f9e23415985e648fb875 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 5 Dec 2013 22:22:04 +0100 Subject: mtd: nand: don't use {read,write}_buf for 8-bit transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the Open NAND Flash Interface Specification (ONFI) Revision 3.1 "Parameters are always transferred on the lower 8-bits of the data bus." for the Get Features and Set Features commands. So using read_buf and write_buf is wrong for 16-bit wide nand chips as they use I/O[15:0]. The Get Features command is easily fixed using 4 times the read_byte callback. For Set Features implement a new overwritable callback "write_byte". Still I expect the default to work just fine for all controllers and making it overwriteable was just done for symmetry. Signed-off-by: Uwe Kleine-König [Brian: fixed warning] Tested-by: Brian Norris Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 57 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/mtd/nand.h | 3 +++ 2 files changed, 58 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b8c74cda762..d388c7f6fec 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -203,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) } } +/** + * nand_write_byte - [DEFAULT] write single byte to chip + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + + chip->write_buf(mtd, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_onfi_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->write_buf(mtd, (uint8_t *)&word, 2); +} + /** * nand_write_buf - [DEFAULT] write buffer to chip * @mtd: MTD device structure @@ -2769,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { int status; + int i; if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -2776,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, return -EINVAL; chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->write_byte(mtd, subfeature_param[i]); + status = chip->waitfunc(mtd, chip); if (status & NAND_STATUS_FAIL) return -EIO; @@ -2793,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { + int i; + if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES)) @@ -2802,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + *subfeature_param++ = chip->read_byte(mtd); return 0; } @@ -2865,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf || chip->write_buf == nand_write_buf) chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->write_byte || chip->write_byte == nand_write_byte) + chip->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!chip->read_buf || chip->read_buf == nand_read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->scan_bbt) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 05fcdfea640..352e23891f5 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -456,6 +456,8 @@ struct nand_buffers { * flash device. * @read_byte: [REPLACEABLE] read one byte from the chip * @read_word: [REPLACEABLE] read one word from the chip + * @write_byte: [REPLACEABLE] write a single byte to the chip on the + * low 8 I/O lines * @write_buf: [REPLACEABLE] write data from the buffer to the chip * @read_buf: [REPLACEABLE] read data from the chip into the buffer * @select_chip: [REPLACEABLE] select chip nr @@ -548,6 +550,7 @@ struct nand_chip { uint8_t (*read_byte)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, uint8_t byte); void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip); -- cgit v1.2.3 From 3f97c6ff6de8a657e4d4d826e502698004cfc2ae Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 26 Dec 2013 15:37:45 +0800 Subject: mtd: nand: add SanDisk manufacturer ID Add the manufactor ID for SanDisk. Make preparation for SanDisk SDTNRGAMA-008G. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a87b0a3afa3..136a46321c6 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -169,6 +169,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_AMD, "AMD/Spansion"}, {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, + {NAND_MFR_SANDISK, "SanDisk"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 352e23891f5..e03a78c70de 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -633,6 +633,7 @@ struct nand_chip { #define NAND_MFR_AMD 0x01 #define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_EON 0x92 +#define NAND_MFR_SANDISK 0x45 /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 -- cgit v1.2.3 From 4968a4124cf2df4b3672eed4714c6755f10f400c Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 16:50:39 +0800 Subject: mtd: nand: add Intel manufacturer ID Add the Intel manufacturer Id. Tested with Intel JS29F32G08ACMD1(4096 + 224) which is ONFI 2.0 compliant nand. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 136a46321c6..daa2faacd7d 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -170,6 +170,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, {NAND_MFR_SANDISK, "SanDisk"}, + {NAND_MFR_INTEL, "Intel"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index e03a78c70de..32f8612469d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -634,6 +634,7 @@ struct nand_chip { #define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_EON 0x92 #define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_INTEL 0x89 /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 -- cgit v1.2.3 From 0a8899b31a7d6c4a3bc7fdbd7c8c1fc79e726363 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 11 Jan 2014 15:51:45 -0800 Subject: mtd: mtdram: add missing 'const' mtdram_init_device() wasn't updated along with mtd_partition.name. Signed-off-by: Brian Norris Cc: Geert Uytterhoeven --- drivers/mtd/devices/mtdram.c | 2 +- include/linux/mtd/mtdram.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index ec59d65897f..8e285089229 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void) } int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name) + unsigned long size, const char *name) { memset(mtd, 0, sizeof(*mtd)); diff --git a/include/linux/mtd/mtdram.h b/include/linux/mtd/mtdram.h index 68891313875..628a6a21ddf 100644 --- a/include/linux/mtd/mtdram.h +++ b/include/linux/mtd/mtdram.h @@ -3,6 +3,6 @@ #include int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name); + unsigned long size, const char *name); #endif /* __MTD_MTDRAM_H__ */ -- cgit v1.2.3