From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: avoid stack overflow in MTD CFI code
Message-ID: <E1b54Qo-0000Lv-3q@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=fddcca5107051adf9e4481d2a79ae0616577fd2c
Commit:     fddcca5107051adf9e4481d2a79ae0616577fd2c
Parent:     20c07a5bf094198ff2382aa5e7c930b3c9807792
Author:     Arnd Bergmann <arnd at arndb.de>
AuthorDate: Mon Feb 29 13:20:28 2016 +0100
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Sun Apr 3 16:46:24 2016 -0700

    mtd: avoid stack overflow in MTD CFI code
    
    When map_word gets too large, we use a lot of kernel stack, and for
    MTD_MAP_BANK_WIDTH_32, this means we use more than the recommended
    1024 bytes in a number of functions:
    
    drivers/mtd/chips/cfi_cmdset_0020.c: In function 'cfi_staa_write_buffers':
    drivers/mtd/chips/cfi_cmdset_0020.c:651:1: warning: the frame size of 1336 bytes is larger than 1024 bytes [-Wframe-larger-than=]
    drivers/mtd/chips/cfi_cmdset_0020.c: In function 'cfi_staa_erase_varsize':
    drivers/mtd/chips/cfi_cmdset_0020.c:972:1: warning: the frame size of 1208 bytes is larger than 1024 bytes [-Wframe-larger-than=]
    drivers/mtd/chips/cfi_cmdset_0001.c: In function 'do_write_buffer':
    drivers/mtd/chips/cfi_cmdset_0001.c:1835:1: warning: the frame size of 1240 bytes is larger than 1024 bytes [-Wframe-larger-than=]
    
    This can be avoided if all operations on the map word are done
    indirectly and the stack gets reused between the calls. We can
    mostly achieve this by selecting MTD_COMPLEX_MAPPINGS whenever
    MTD_MAP_BANK_WIDTH_32 is set, but for the case that no other
    bank width is enabled, we also need to use a non-constant
    map_bankwidth() to convince the compiler to use less stack.
    
    Signed-off-by: Arnd Bergmann <arnd at arndb.de>
    [Brian: this patch mostly achieves its goal by forcing
        MTD_COMPLEX_MAPPINGS (and the accompanying indirection) for 256-bit
        mappings; the rest of the change is mostly a wash, though it helps
        reduce stack size slightly. If we really care about supporting
        256-bit mappings though, we should consider rewriting some of this
        code to avoid keeping and assigning so many 256-bit objects on the
        stack.]
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/chips/Kconfig |  1 +
 include/linux/mtd/map.h   | 19 +++++++------------
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 3b3dabc..bbfa1f1 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -115,6 +115,7 @@ config MTD_MAP_BANK_WIDTH_16
 
 config MTD_MAP_BANK_WIDTH_32
 	bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
+	select MTD_COMPLEX_MAPPINGS if HAS_IOMEM
 	default n
 	help
 	  If you wish to support CFI devices on a physical bus which is
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 5e0eb7c..3aa56e3 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -122,18 +122,13 @@
 #endif
 
 #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
-# ifdef map_bankwidth
-#  undef map_bankwidth
-#  define map_bankwidth(map) ((map)->bankwidth)
-#  undef map_bankwidth_is_large
-#  define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
-#  undef map_words
-#  define map_words(map) map_calc_words(map)
-# else
-#  define map_bankwidth(map) 32
-#  define map_bankwidth_is_large(map) (1)
-#  define map_words(map) map_calc_words(map)
-# endif
+/* always use indirect access for 256-bit to preserve kernel stack */
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# undef map_bankwidth_is_large
+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+# undef map_words
+# define map_words(map) map_calc_words(map)
 #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
 #undef MAX_MAP_BANKWIDTH
 #define MAX_MAP_BANKWIDTH 32


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: bcm47xxsflash: use ioremap_cache() instead of KSEG0ADDR()
Message-ID: <E1b54Qo-0000MM-7l@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=5651d6aaf489d1db48c253cf884b40214e91c2c5
Commit:     5651d6aaf489d1db48c253cf884b40214e91c2c5
Parent:     fddcca5107051adf9e4481d2a79ae0616577fd2c
Author:     Brian Norris <computersforpeace at gmail.com>
AuthorDate: Fri Feb 26 11:50:28 2016 +0100
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Mon Apr 4 00:07:57 2016 -0700

    mtd: bcm47xxsflash: use ioremap_cache() instead of KSEG0ADDR()
    
    Using KSEG0ADDR makes code highly MIPS dependent and not portable.
    Thanks to the fix a68f376 ("MIPS: io.h: Define `ioremap_cache'") we can
    use ioremap_cache which is generic and supported on MIPS as well now.
    
    KSEG0ADDR was translating 0x1c000000 into 0x9c000000. With ioremap_cache
    we use MIPS's __ioremap (and then remap_area_pages). This results in
    different address (e.g. 0xc0080000) but it still should be cached as
    expected and it was successfully tested with BCM47186B0.
    
    Other than that drivers/bcma/driver_chipcommon_sflash.c nicely setups a
    struct resource for access window, but we wren't using it. Use it now
    and drop duplicated info.
    
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
---
 drivers/bcma/driver_chipcommon_sflash.c     |  1 -
 drivers/mtd/devices/bcm47xxsflash.c         | 29 ++++++++++++++++++++++++-----
 drivers/mtd/devices/bcm47xxsflash.h         |  3 ++-
 include/linux/bcma/bcma_driver_chipcommon.h |  1 -
 4 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c
index 04d706c..35b13a0 100644
--- a/drivers/bcma/driver_chipcommon_sflash.c
+++ b/drivers/bcma/driver_chipcommon_sflash.c
@@ -146,7 +146,6 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
 		return -ENOTSUPP;
 	}
 
-	sflash->window = BCMA_SOC_FLASH2;
 	sflash->blocksize = e->blocksize;
 	sflash->numblocks = e->numblocks;
 	sflash->size = sflash->blocksize * sflash->numblocks;
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
index 347bb83..1c65c15 100644
--- a/drivers/mtd/devices/bcm47xxsflash.c
+++ b/drivers/mtd/devices/bcm47xxsflash.c
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
@@ -109,8 +110,7 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 	if ((from + len) > mtd->size)
 		return -EINVAL;
 
-	memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
-		      len);
+	memcpy_fromio(buf, b47s->window + from, len);
 	*retlen = len;
 
 	return len;
@@ -275,15 +275,33 @@ static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
 
 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 {
-	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
+	struct device *dev = &pdev->dev;
+	struct bcma_sflash *sflash = dev_get_platdata(dev);
 	struct bcm47xxsflash *b47s;
+	struct resource *res;
 	int err;
 
-	b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
+	b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
 	if (!b47s)
 		return -ENOMEM;
 	sflash->priv = b47s;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "invalid resource\n");
+		return -EINVAL;
+	}
+	if (!devm_request_mem_region(dev, res->start, resource_size(res),
+				     res->name)) {
+		dev_err(dev, "can't request region for resource %pR\n", res);
+		return -EBUSY;
+	}
+	b47s->window = ioremap_cache(res->start, resource_size(res));
+	if (!b47s->window) {
+		dev_err(dev, "ioremap failed for resource %pR\n", res);
+		return -ENOMEM;
+	}
+
 	b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
 	b47s->cc_read = bcm47xxsflash_bcma_cc_read;
 	b47s->cc_write = bcm47xxsflash_bcma_cc_write;
@@ -297,7 +315,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 		break;
 	}
 
-	b47s->window = sflash->window;
 	b47s->blocksize = sflash->blocksize;
 	b47s->numblocks = sflash->numblocks;
 	b47s->size = sflash->size;
@@ -306,6 +323,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 	err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
 	if (err) {
 		pr_err("Failed to register MTD device: %d\n", err);
+		iounmap(b47s->window);
 		return err;
 	}
 
@@ -321,6 +339,7 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
 	struct bcm47xxsflash *b47s = sflash->priv;
 
 	mtd_device_unregister(&b47s->mtd);
+	iounmap(b47s->window);
 
 	return 0;
 }
diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h
index fe93daf..1564b62 100644
--- a/drivers/mtd/devices/bcm47xxsflash.h
+++ b/drivers/mtd/devices/bcm47xxsflash.h
@@ -65,7 +65,8 @@ struct bcm47xxsflash {
 
 	enum bcm47xxsflash_type type;
 
-	u32 window;
+	void __iomem *window;
+
 	u32 blocksize;
 	u16 numblocks;
 	u32 size;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 846513c..a5ac2ca 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -587,7 +587,6 @@ struct mtd_info;
 
 struct bcma_sflash {
 	bool present;
-	u32 window;
 	u32 blocksize;
 	u16 numblocks;
 	u32 size;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: devices: m25p80: add support for mmap read request
Message-ID: <E1b54Qo-0000Mn-9l@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=08922f644878c9163ada8df3ef9def89be1d5e90
Commit:     08922f644878c9163ada8df3ef9def89be1d5e90
Parent:     5651d6aaf489d1db48c253cf884b40214e91c2c5
Author:     Vignesh R <vigneshr at ti.com>
AuthorDate: Tue Mar 29 11:16:17 2016 +0530
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Tue Apr 5 11:06:57 2016 -0700

    mtd: devices: m25p80: add support for mmap read request
    
    Certain SPI controllers may provide accelerated hardware interface to
    read from m25p80 type flash devices in order to provide better read
    performance. SPI core supports such devices with spi_flash_read() API.
    Call spi_flash_read(), if supported, to make use of such interface.
    
    Signed-off-by: Vignesh R <vigneshr at ti.com>
    [Brian: add memset()]
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/devices/m25p80.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index c9c3b7f..9d68544 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 	/* convert the dummy cycles to the number of bytes */
 	dummy /= 8;
 
+	if (spi_flash_read_supported(spi)) {
+		struct spi_flash_read_message msg;
+		int ret;
+
+		memset(&msg, 0, sizeof(msg));
+
+		msg.buf = buf;
+		msg.from = from;
+		msg.len = len;
+		msg.read_opcode = nor->read_opcode;
+		msg.addr_width = nor->addr_width;
+		msg.dummy_bytes = dummy;
+		/* TODO: Support other combinations */
+		msg.opcode_nbits = SPI_NBITS_SINGLE;
+		msg.addr_nbits = SPI_NBITS_SINGLE;
+		msg.data_nbits = m25p80_rx_nbits(nor);
+
+		ret = spi_flash_read(spi, &msg);
+		*retlen = msg.retlen;
+		return ret;
+	}
+
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: maps: make uclinux.c driver more explicitly non-modular
Message-ID: <E1b54Qo-0000NC-Bt@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=025ce02d92b67d6c702676c11f7f1f5e8f0a81fa
Commit:     025ce02d92b67d6c702676c11f7f1f5e8f0a81fa
Parent:     08922f644878c9163ada8df3ef9def89be1d5e90
Author:     Paul Gortmaker <paul.gortmaker at windriver.com>
AuthorDate: Sun Mar 27 12:13:54 2016 -0400
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Mon Apr 25 20:19:13 2016 -0700

    mtd: maps: make uclinux.c driver more explicitly non-modular
    
    The Kconfig for this support is currently declared with:
    
    config MTD_UCLINUX
            bool "Generic uClinux RAM/ROM filesystem support"
    
    ...meaning that it currently is not being built as a module by anyone.
    Lets remove as much of the modular evidence that we can, so that when
    reading the driver there is less doubt it is builtin-only.
    
    Since module_init translates to device_initcall in the non-modular
    case, the init ordering remains unchanged with this commit.
    
    We also replace module.h with moduleparam.h since the file does use
    a module_param,  and leaving it as such is currently the easiest way
    to remain compatible with existing boot arg use cases.
    
    We also delete the MODULE_LICENSE tag etc. since all that information
    was (or is now) contained at the top of the file in the comments.
    
    Cc: David Woodhouse <dwmw2 at infradead.org>
    Cc: Greg Ungerer <gerg at snapgear.com>
    Signed-off-by: Paul Gortmaker <paul.gortmaker at windriver.com>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/maps/uclinux.c | 27 ++++-----------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index c1af83d..00a8190 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -4,11 +4,13 @@
  *	uclinux.c -- generic memory mapped MTD driver for uclinux
  *
  *	(C) Copyright 2002, Greg Ungerer (gerg at snapgear.com)
+ *
+ *      License: GPL
  */
 
 /****************************************************************************/
 
-#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -117,27 +119,6 @@ static int __init uclinux_mtd_init(void)
 
 	return(0);
 }
-
-/****************************************************************************/
-
-static void __exit uclinux_mtd_cleanup(void)
-{
-	if (uclinux_ram_mtdinfo) {
-		mtd_device_unregister(uclinux_ram_mtdinfo);
-		map_destroy(uclinux_ram_mtdinfo);
-		uclinux_ram_mtdinfo = NULL;
-	}
-	if (uclinux_ram_map.virt)
-		uclinux_ram_map.virt = 0;
-}
-
-/****************************************************************************/
-
-module_init(uclinux_mtd_init);
-module_exit(uclinux_mtd_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Greg Ungerer <gerg at snapgear.com>");
-MODULE_DESCRIPTION("Generic MTD for uClinux");
+device_initcall(uclinux_mtd_init);
 
 /****************************************************************************/


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: maps: add __init attribute
Message-ID: <E1b54Qo-0000Nh-Ev@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e4106a7c8236eb7b91686d36f3bf33ee43db94b4
Commit:     e4106a7c8236eb7b91686d36f3bf33ee43db94b4
Parent:     025ce02d92b67d6c702676c11f7f1f5e8f0a81fa
Author:     Julia Lawall <julia.lawall at lip6.fr>
AuthorDate: Tue Apr 19 14:33:33 2016 +0200
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Tue Apr 26 00:18:29 2016 -0600

    mtd: maps: add __init attribute
    
    Add __init attribute on functions that are only called from other __init
    functions and that are not inlined, at least with gcc version 4.8.4 on an
    x86 machine with allyesconfig.  Currently, the functions are put in the
    .text.unlikely segment.  Declaring them as __init will cause them to be
    put in the .init.text and to disappear after initialization.
    
    The result of objdump -x on the functions before the change is as follows:
    
    00000000000001bc l     F .text.unlikely 00000000000006a2 ck804xrom_init_one.isra.1
    00000000000001aa l     F .text.unlikely 0000000000000764 esb2rom_init_one.isra.1
    00000000000001db l     F .text.unlikely 0000000000000716 ichxrom_init_one.isra.1
    
    And after the change it is as follows:
    
    0000000000000000 l     F .init.text	000000000000069d ck804xrom_init_one.isra.1
    0000000000000000 l     F .init.text	000000000000075f esb2rom_init_one.isra.1
    0000000000000000 l     F .init.text	0000000000000711 ichxrom_init_one.isra.1
    
    Done with the help of Coccinelle.  The semantic patch checks for local
    static non-init functions that are called from an __init function and are
    not called from any other function.
    
    Note that in each case, the function is stored in the probe field of a
    pci_driver structure, but this code is under an #if 0.  The #if 0s have
    been unchanged since 2009 at the latest.
    
    Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/maps/ck804xrom.c | 4 ++--
 drivers/mtd/maps/esb2rom.c   | 4 ++--
 drivers/mtd/maps/ichxrom.c   | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 0455166..4f206a9 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
 }
 
 
-static int ck804xrom_init_one(struct pci_dev *pdev,
-			      const struct pci_device_id *ent)
+static int __init ck804xrom_init_one(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	u8 byte;
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index 76ed651..9646b07 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -144,8 +144,8 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
 	pci_dev_put(window->pdev);
 }
 
-static int esb2rom_init_one(struct pci_dev *pdev,
-			    const struct pci_device_id *ent)
+static int __init esb2rom_init_one(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	struct esb2rom_window *window = &esb2rom_window;
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index 8636bba..e17d02a 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -84,8 +84,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 }
 
 
-static int ichxrom_init_one(struct pci_dev *pdev,
-			    const struct pci_device_id *ent)
+static int __init ichxrom_init_one(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	struct ichxrom_window *window = &ichxrom_window;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: mtd: pmc551: add __init attribute
Message-ID: <E1b54Qo-0000O8-Hy@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=abbbc60a0c69e05c965ce51cb75c0bee56dc0025
Commit:     abbbc60a0c69e05c965ce51cb75c0bee56dc0025
Parent:     e4106a7c8236eb7b91686d36f3bf33ee43db94b4
Author:     Julia Lawall <julia.lawall at lip6.fr>
AuthorDate: Tue Apr 19 14:33:34 2016 +0200
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Tue Apr 26 00:18:29 2016 -0600

    mtd: pmc551: add __init attribute
    
    Add __init attribute on a function that is only called from other __init
    functions and that is not inlined, at least with gcc version 4.8.4 on an
    x86 machine with allyesconfig.  Currently, the function is put in the
    .text.unlikely segment.  Declaring it as __init will cause it to be put in
    the .init.text and to disappear after initialization.
    
    The result of objdump -x on the function before the change is as follows:
    
    00000000000000c6 l     F .text.unlikely 000000000000091c fixup_pmc551
    
    And after the change it is as follows:
    
    0000000000000000 l     F .init.text	0000000000000917 fixup_pmc551
    
    Done with the help of Coccinelle.  The semantic patch checks for local
    static non-init functions that are called from an __init function and are
    not called from any other function.
    
    Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/devices/pmc551.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 708b7e8..220f920 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -353,7 +353,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
  * mechanism
  * returns the size of the memory region found.
  */
-static int fixup_pmc551(struct pci_dev *dev)
+static int __init fixup_pmc551(struct pci_dev *dev)
 {
 #ifdef CONFIG_MTD_PMC551_BUGFIX
 	u32 dram_data;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: ARM: OMAP2+: gpmc: Add platform data
Message-ID: <E1b54Qo-0000OX-KX@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=58bc67fc32b1c67fb045f4828a67134dc8fee631
Commit:     58bc67fc32b1c67fb045f4828a67134dc8fee631
Parent:     f55532a0c0b8bb6148f4e07853b876ef73bc69ca
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Fri Jul 10 15:23:28 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:50:44 2016 +0300

    ARM: OMAP2+: gpmc: Add platform data
    
    Add a platform data structure for GPMC. It contains all the necessary
    platform information that needs to be passed from platform init code
    to GPMC driver.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 include/linux/omap-gpmc.h               |  3 +--
 include/linux/platform_data/gpmc-omap.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index d833eb4..45d9075 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -7,8 +7,7 @@
  *  option) any later version.
  */
 
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM		8
+#include <linux/platform_data/gpmc-omap.h>
 
 #define GPMC_CONFIG_WP		0x00000005
 
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
new file mode 100644
index 0000000..6804a8b
--- /dev/null
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -0,0 +1,30 @@
+/*
+ * OMAP GPMC Platform data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
+ *	Roger Quadros <rogerq at ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _GPMC_OMAP_H_
+#define _GPMC_OMAP_H_
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM		8
+
+/* Data for each chip select */
+struct gpmc_omap_cs_data {
+	bool valid;			/* data is valid */
+	bool is_nand;			/* device within this CS is NAND */
+	struct platform_device *pdev;	/* device within this CS region */
+	unsigned int pdata_size;
+};
+
+struct gpmc_omap_platform_data {
+	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
+};
+
+#endif /* _GPMC_OMAP_H */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
Message-ID: <E1b54Qo-0000Ow-QI@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=fabe7d7756d17f5da4bd80fa2373c4bd93ed39e5
Commit:     fabe7d7756d17f5da4bd80fa2373c4bd93ed39e5
Parent:     58bc67fc32b1c67fb045f4828a67134dc8fee631
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Fri Jul 10 15:23:29 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:51:02 2016 +0300

    ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
    
    Add device_timings, gpmc_timings and gpmc_setting to
    gpmc platform data.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 include/linux/omap-gpmc.h               | 269 ++++++++------------------------
 include/linux/platform_data/gpmc-omap.h | 142 +++++++++++++++++
 2 files changed, 207 insertions(+), 204 deletions(-)

diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
dissimilarity index 70%
index 45d9075..2dcef1c 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -1,204 +1,65 @@
-/*
- *  OMAP GPMC (General Purpose Memory Controller) defines
- *
- *  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.
- */
-
-#include <linux/platform_data/gpmc-omap.h>
-
-#define GPMC_CONFIG_WP		0x00000005
-
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-#define GPMC_BURST_4			4	/* 4 word burst */
-#define GPMC_BURST_8			8	/* 8 word burst */
-#define GPMC_BURST_16			16	/* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
-#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
-	bool cycle2cyclediffcsen;
-	bool cycle2cyclesamecsen;
-	bool we_extra_delay;
-	bool oe_extra_delay;
-	bool adv_extra_delay;
-	bool cs_extra_delay;
-	bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
-	/* Minimum clock period for synchronous mode (in picoseconds) */
-	u32 sync_clk;
-
-	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u32 cs_on;		/* Assertion time */
-	u32 cs_rd_off;		/* Read deassertion time */
-	u32 cs_wr_off;		/* Write deassertion time */
-
-	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u32 adv_on;		/* Assertion time */
-	u32 adv_rd_off;		/* Read deassertion time */
-	u32 adv_wr_off;		/* Write deassertion time */
-	u32 adv_aad_mux_on;	/* ADV assertion time for AAD */
-	u32 adv_aad_mux_rd_off;	/* ADV read deassertion time for AAD */
-	u32 adv_aad_mux_wr_off;	/* ADV write deassertion time for AAD */
-
-	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u32 we_on;		/* WE assertion time */
-	u32 we_off;		/* WE deassertion time */
-
-	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u32 oe_on;		/* OE assertion time */
-	u32 oe_off;		/* OE deassertion time */
-	u32 oe_aad_mux_on;	/* OE assertion time for AAD */
-	u32 oe_aad_mux_off;	/* OE deassertion time for AAD */
-
-	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u32 page_burst_access;	/* Multiple access word delay */
-	u32 access;		/* Start-cycle to first data valid delay */
-	u32 rd_cycle;		/* Total read cycle time */
-	u32 wr_cycle;		/* Total write cycle time */
-
-	u32 bus_turnaround;
-	u32 cycle2cycle_delay;
-
-	u32 wait_monitoring;
-	u32 clk_activation;
-
-	/* The following are only on OMAP3430 */
-	u32 wr_access;		/* WRACCESSTIME */
-	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
-
-	struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
-	u32 t_ceasu;	/* address setup to CS valid */
-	u32 t_avdasu;	/* address setup to ADV valid */
-	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
-	 * of tusb using these timings even for sync whilst
-	 * ideally for adv_rd/(wr)_off it should have considered
-	 * t_avdh instead. This indirectly necessitates r/w
-	 * variations of t_avdp as it is possible to have one
-	 * sync & other async
-	 */
-	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
-	u32 t_avdp_w;
-	u32 t_aavdh;	/* address hold time */
-	u32 t_oeasu;	/* address setup to OE valid */
-	u32 t_aa;	/* access time from ADV assertion */
-	u32 t_iaa;	/* initial access time */
-	u32 t_oe;	/* access time from OE assertion */
-	u32 t_ce;	/* access time from CS asertion */
-	u32 t_rd_cycle;	/* read cycle time */
-	u32 t_cez_r;	/* read CS deassertion to high Z */
-	u32 t_cez_w;	/* write CS deassertion to high Z */
-	u32 t_oez;	/* OE deassertion to high Z */
-	u32 t_weasu;	/* address setup to WE valid */
-	u32 t_wpl;	/* write assertion time */
-	u32 t_wph;	/* write deassertion time */
-	u32 t_wr_cycle;	/* write cycle time */
-
-	u32 clk;
-	u32 t_bacc;	/* burst access valid clock to output delay */
-	u32 t_ces;	/* CS setup time to clk */
-	u32 t_avds;	/* ADV setup time to clk */
-	u32 t_avdh;	/* ADV hold time from clk */
-	u32 t_ach;	/* address hold time from clk */
-	u32 t_rdyo;	/* clk to ready valid */
-
-	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
-	u32 t_ce_avd;	/* CS on to ADV on delay */
-
-	/* XXX: check the possibility of combining
-	 * cyc_aavhd_oe & cyc_aavdh_we
-	 */
-	u8 cyc_aavdh_oe;/* read address hold time in cycles */
-	u8 cyc_aavdh_we;/* write address hold time in cycles */
-	u8 cyc_oe;	/* access time from OE assertion in cycles */
-	u8 cyc_wpl;	/* write deassertion time in cycles */
-	u32 cyc_iaa;	/* initial access time in cycles */
-
-	/* extra delays */
-	bool ce_xdelay;
-	bool avd_xdelay;
-	bool oe_xdelay;
-	bool we_xdelay;
-};
-
-struct gpmc_settings {
-	bool burst_wrap;	/* enables wrap bursting */
-	bool burst_read;	/* enables read page/burst mode */
-	bool burst_write;	/* enables write page/burst mode */
-	bool device_nand;	/* device is NAND */
-	bool sync_read;		/* enables synchronous reads */
-	bool sync_write;	/* enables synchronous writes */
-	bool wait_on_read;	/* monitor wait on reads */
-	bool wait_on_write;	/* monitor wait on writes */
-	u32 burst_len;		/* page/burst length */
-	u32 device_width;	/* device bus width (8 or 16 bit) */
-	u32 mux_add_data;	/* multiplex address & data */
-	u32 wait_pin;		/* wait-pin to be used */
-};
-
-extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t);
-
-struct gpmc_nand_regs;
-struct device_node;
-
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
-extern int gpmc_get_client_irq(unsigned irq_config);
-
-extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-
-extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
-extern int gpmc_calc_divider(unsigned int sync_clk);
-extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
-			       const struct gpmc_settings *s);
-extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
-extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
-extern void gpmc_cs_free(int cs);
-extern int gpmc_configure(int cmd, int wval);
-extern void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p);
-
-extern void omap3_gpmc_save_context(void);
-extern void omap3_gpmc_restore_context(void);
-
-struct gpmc_timings;
-struct omap_nand_platform_data;
-struct omap_onenand_platform_data;
-
-#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
-extern int gpmc_nand_init(struct omap_nand_platform_data *d,
-			  struct gpmc_timings *gpmc_t);
-#else
-static inline int gpmc_nand_init(struct omap_nand_platform_data *d,
-				 struct gpmc_timings *gpmc_t)
-{
-	return 0;
-}
-#endif
-
-#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
-extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
-#else
-#define board_onenand_data	NULL
-static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
-{
-}
-#endif
+/*
+ *  OMAP GPMC (General Purpose Memory Controller) defines
+ *
+ *  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.
+ */
+
+#include <linux/platform_data/gpmc-omap.h>
+
+#define GPMC_CONFIG_WP		0x00000005
+
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
+extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t);
+
+struct gpmc_nand_regs;
+struct device_node;
+
+extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+extern int gpmc_get_client_irq(unsigned irq_config);
+
+extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
+
+extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
+extern int gpmc_calc_divider(unsigned int sync_clk);
+extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
+			       const struct gpmc_settings *s);
+extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
+extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
+extern void gpmc_cs_free(int cs);
+extern int gpmc_configure(int cmd, int wval);
+extern void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p);
+
+extern void omap3_gpmc_save_context(void);
+extern void omap3_gpmc_restore_context(void);
+
+struct gpmc_timings;
+struct omap_nand_platform_data;
+struct omap_onenand_platform_data;
+
+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
+extern int gpmc_nand_init(struct omap_nand_platform_data *d,
+			  struct gpmc_timings *gpmc_t);
+#else
+static inline int gpmc_nand_init(struct omap_nand_platform_data *d,
+				 struct gpmc_timings *gpmc_t)
+{
+	return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
+extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
+#else
+#define board_onenand_data	NULL
+static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
+{
+}
+#endif
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index 6804a8b..67ccdb0 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -15,10 +15,152 @@
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+	u32 adv_aad_mux_on;	/* ADV assertion time for AAD */
+	u32 adv_aad_mux_rd_off;	/* ADV read deassertion time for AAD */
+	u32 adv_aad_mux_wr_off;	/* ADV write deassertion time for AAD */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+	u32 oe_aad_mux_on;	/* OE assertion time for AAD */
+	u32 oe_aad_mux_off;	/* OE deassertion time for AAD */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+	u32 t_ceasu;	/* address setup to CS valid */
+	u32 t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32 t_avdp_w;
+	u32 t_aavdh;	/* address hold time */
+	u32 t_oeasu;	/* address setup to OE valid */
+	u32 t_aa;	/* access time from ADV assertion */
+	u32 t_iaa;	/* initial access time */
+	u32 t_oe;	/* access time from OE assertion */
+	u32 t_ce;	/* access time from CS asertion */
+	u32 t_rd_cycle;	/* read cycle time */
+	u32 t_cez_r;	/* read CS deassertion to high Z */
+	u32 t_cez_w;	/* write CS deassertion to high Z */
+	u32 t_oez;	/* OE deassertion to high Z */
+	u32 t_weasu;	/* address setup to WE valid */
+	u32 t_wpl;	/* write assertion time */
+	u32 t_wph;	/* write deassertion time */
+	u32 t_wr_cycle;	/* write cycle time */
+
+	u32 clk;
+	u32 t_bacc;	/* burst access valid clock to output delay */
+	u32 t_ces;	/* CS setup time to clk */
+	u32 t_avds;	/* ADV setup time to clk */
+	u32 t_avdh;	/* ADV hold time from clk */
+	u32 t_ach;	/* address hold time from clk */
+	u32 t_rdyo;	/* clk to ready valid */
+
+	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32 t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8 cyc_aavdh_oe;/* read address hold time in cycles */
+	u8 cyc_aavdh_we;/* write address hold time in cycles */
+	u8 cyc_oe;	/* access time from OE assertion in cycles */
+	u8 cyc_wpl;	/* write deassertion time in cycles */
+	u32 cyc_iaa;	/* initial access time in cycles */
+
+	/* extra delays */
+	bool ce_xdelay;
+	bool avd_xdelay;
+	bool oe_xdelay;
+	bool we_xdelay;
+};
+
+#define GPMC_BURST_4			4	/* 4 word burst */
+#define GPMC_BURST_8			8	/* 8 word burst */
+#define GPMC_BURST_16			16	/* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
+#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
+
+struct gpmc_settings {
+	bool burst_wrap;	/* enables wrap bursting */
+	bool burst_read;	/* enables read page/burst mode */
+	bool burst_write;	/* enables write page/burst mode */
+	bool device_nand;	/* device is NAND */
+	bool sync_read;		/* enables synchronous reads */
+	bool sync_write;	/* enables synchronous writes */
+	bool wait_on_read;	/* monitor wait on reads */
+	bool wait_on_write;	/* monitor wait on writes */
+	u32 burst_len;		/* page/burst length */
+	u32 device_width;	/* device bus width (8 or 16 bit) */
+	u32 mux_add_data;	/* multiplex address & data */
+	u32 wait_pin;		/* wait-pin to be used */
+};
+
 /* Data for each chip select */
 struct gpmc_omap_cs_data {
 	bool valid;			/* data is valid */
 	bool is_nand;			/* device within this CS is NAND */
+	struct gpmc_settings *settings;
+	struct gpmc_device_timings *device_timings;
+	struct gpmc_timings *gpmc_timings;
 	struct platform_device *pdev;	/* device within this CS region */
 	unsigned int pdata_size;
 };


From linux-mtd at lists.infradead.org  Mon May 23 21:59:02 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:02 +0000
Subject: memory: omap-gpmc: Introduce GPMC to NAND interface
Message-ID: <E1b54Qo-0000PL-TP@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f47fcad63f6847ea677c6c7030f30fd6438e0052
Commit:     f47fcad63f6847ea677c6c7030f30fd6438e0052
Parent:     fabe7d7756d17f5da4bd80fa2373c4bd93ed39e5
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed Aug 5 13:58:01 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:51:34 2016 +0300

    memory: omap-gpmc: Introduce GPMC to NAND interface
    
    The OMAP GPMC module has certain registers dedicated for NAND
    access and some NAND bits mixed with other GPMC functionality.
    
    For the NAND dedicated registers we have the struct gpmc_nand_regs.
    
    The NAND driver needs to access NAND specific bits from the
    following non-dedicated registers
    - EMPTYWRITEBUFFERSTATUS from GPMC_STATUS
    
    For accessing these bits we introduce the struct gpmc_nand_ops.
    
    Add gpmc_omap_get_nand_ops() that returns the gpmc_nand_ops along
    with updating the gpmc_nand_regs. This API will be called by the
    OMAP NAND driver to access the necessary bits in GPMC register space.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/memory/omap-gpmc.c | 21 +++++++++++++++++++++
 include/linux/omap-gpmc.h  | 35 +++++++++++++++++++++++++++++++++--
 2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 21825dd..0b62afd 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1118,6 +1118,27 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
+static struct gpmc_nand_ops nand_ops;
+
+/**
+ * gpmc_omap_get_nand_ops - Get the GPMC NAND interface
+ * @regs: the GPMC NAND register map exclusive for NAND use.
+ * @cs: GPMC chip select number on which the NAND sits. The
+ *      register map returned will be specific to this chip select.
+ *
+ * Returns NULL on error e.g. invalid cs.
+ */
+struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
+{
+	if (cs >= gpmc_cs_num)
+		return NULL;
+
+	gpmc_update_nand_reg(reg, cs);
+
+	return &nand_ops;
+}
+EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
+
 int gpmc_get_client_irq(unsigned irq_config)
 {
 	int i;
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 2dcef1c..dc2ada6 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -14,14 +14,45 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
+/**
+ * gpmc_nand_ops - Interface between NAND and GPMC
+ * @nand_write_buffer_empty: get the NAND write buffer empty status.
+ */
+struct gpmc_nand_ops {
+	bool (*nand_writebuffer_empty)(void);
+};
+
+struct gpmc_nand_regs;
+
+#if IS_ENABLED(CONFIG_OMAP_GPMC)
+struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
+					     int cs);
+#else
+static inline gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
+						    int cs)
+{
+	return NULL;
+}
+#endif /* CONFIG_OMAP_GPMC */
+
+/*--------------------------------*/
+
+/* deprecated APIs */
+#if IS_ENABLED(CONFIG_OMAP_GPMC)
+void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+#else
+static inline void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
+{
+}
+#endif /* CONFIG_OMAP_GPMC */
+/*--------------------------------*/
+
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
 
-struct gpmc_nand_regs;
 struct device_node;
 
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
 extern int gpmc_get_client_irq(unsigned irq_config);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status
Message-ID: <E1b54Qp-0000Po-1Z@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=512d73d1c64f15da9cdcdcdfba3cd8db0d4d94cc
Commit:     512d73d1c64f15da9cdcdcdfba3cd8db0d4d94cc
Parent:     f47fcad63f6847ea677c6c7030f30fd6438e0052
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed Aug 5 13:34:50 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:51:57 2016 +0300

    memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status
    
    This is needed by OMAP NAND driver to poll the empty status
    of the writebuffer.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/memory/omap-gpmc.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 0b62afd..90dfba5 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -81,6 +81,8 @@
 
 #define GPMC_CONFIG_LIMITEDADDRESS		BIT(1)
 
+#define GPMC_STATUS_EMPTYWRITEBUFFERSTATUS	BIT(0)
+
 #define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
@@ -1118,7 +1120,17 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
-static struct gpmc_nand_ops nand_ops;
+static bool gpmc_nand_writebuffer_empty(void)
+{
+	if (gpmc_read_reg(GPMC_STATUS) & GPMC_STATUS_EMPTYWRITEBUFFERSTATUS)
+		return true;
+
+	return false;
+}
+
+static struct gpmc_nand_ops nand_ops = {
+	.nand_writebuffer_empty = gpmc_nand_writebuffer_empty,
+};
 
 /**
  * gpmc_omap_get_nand_ops - Get the GPMC NAND interface


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: memory: omap-gpmc: Implement IRQ domain for NAND IRQs
Message-ID: <E1b54Qp-0000QD-5J@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=384258f252727c67772bbd48dad3185a30ba50d3
Commit:     384258f252727c67772bbd48dad3185a30ba50d3
Parent:     512d73d1c64f15da9cdcdcdfba3cd8db0d4d94cc
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Thu Jul 30 14:49:23 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:52:28 2016 +0300

    memory: omap-gpmc: Implement IRQ domain for NAND IRQs
    
    GPMC provides 2 interrupts for NAND use. i.e. fifoevent and termcount.
    Use IRQ domain for this. NAND device tree node can then
    get the necessary interrupts by using gpmc as the interrupt parent.
    
    Legacy boot uses gpmc_get_client_irq to get the
    NAND interrupts from the GPMC IRQ domain.
    Get rid of custom bitmasks and use IRQ domain for that
    as well.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 Documentation/devicetree/bindings/bus/ti-gpmc.txt |   8 +
 drivers/memory/omap-gpmc.c                        | 246 ++++++++++++----------
 include/linux/omap-gpmc.h                         |   5 +-
 3 files changed, 144 insertions(+), 115 deletions(-)

diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt
index 0168370..13f1378 100644
--- a/Documentation/devicetree/bindings/bus/ti-gpmc.txt
+++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt
@@ -32,6 +32,12 @@ Required properties:
 			bootloader) are used for the physical address decoding.
 			As this will change in the future, filling correct
 			values here is a requirement.
+ - interrupt-controller: The GPMC driver implements and interrupt controller for
+			the NAND events "fifoevent" and "termcount".
+			The interrupt number mapping is as follows
+			0 - NAND_fifoevent
+			1 - NAND_termcount
+ - interrupt-cells:	Must be set to 2
 
 Timing properties for child nodes. All are optional and default to 0.
 
@@ -130,6 +136,8 @@ Example for an AM33xx board:
 		#address-cells = <2>;
 		#size-cells = <1>;
 		ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
+		interrupt-controller;
+		#interrupt-cells = <2>;
 
 		/* child nodes go here */
 	};
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 90dfba5..e28d6bc 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -127,7 +128,6 @@
 #define GPMC_CONFIG_RDY_BSY	0x00000001
 #define GPMC_CONFIG_DEV_SIZE	0x00000002
 #define GPMC_CONFIG_DEV_TYPE	0x00000003
-#define GPMC_SET_IRQ_STATUS	0x00000004
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
@@ -176,8 +176,6 @@
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define WR_RD_PIN_MONITORING		0x00600000
 
-#define GPMC_ENABLE_IRQ		0x0000000d
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -201,11 +199,6 @@ struct gpmc_cs_data {
 	struct resource mem;
 };
 
-struct gpmc_client_irq	{
-	unsigned		irq;
-	u32			bitmask;
-};
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -233,9 +226,13 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
-static struct irq_chip gpmc_irq_chip;
-static int gpmc_irq_start;
+struct gpmc_device {
+	struct device *dev;
+	int irq;
+	struct irq_chip irq_chip;
+};
+
+static struct irq_domain *gpmc_irq_domain;
 
 static struct resource	gpmc_mem_root;
 static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
@@ -243,8 +240,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
 /* Define chip-selects as reserved by default until probe completes */
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
-static struct device *gpmc_dev;
-static int gpmc_irq;
 static resource_size_t phys_base, mem_size;
 static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
@@ -1056,14 +1051,6 @@ int gpmc_configure(int cmd, int wval)
 	u32 regval;
 
 	switch (cmd) {
-	case GPMC_ENABLE_IRQ:
-		gpmc_write_reg(GPMC_IRQENABLE, wval);
-		break;
-
-	case GPMC_SET_IRQ_STATUS:
-		gpmc_write_reg(GPMC_IRQSTATUS, wval);
-		break;
-
 	case GPMC_CONFIG_WP:
 		regval = gpmc_read_reg(GPMC_CONFIG);
 		if (wval)
@@ -1153,85 +1140,97 @@ EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
 
 int gpmc_get_client_irq(unsigned irq_config)
 {
-	int i;
-
-	if (hweight32(irq_config) > 1)
+	if (!gpmc_irq_domain) {
+		pr_warn("%s called before GPMC IRQ domain available\n",
+			__func__);
 		return 0;
+	}
 
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (gpmc_client_irq[i].bitmask & irq_config)
-			return gpmc_client_irq[i].irq;
+	if (irq_config >= GPMC_NR_IRQ)
+		return 0;
 
-	return 0;
+	return irq_create_mapping(gpmc_irq_domain, irq_config);
 }
 
-static int gpmc_irq_endis(unsigned irq, bool endis)
+static int gpmc_irq_endis(unsigned long hwirq, bool endis)
 {
-	int i;
 	u32 regval;
 
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (irq == gpmc_client_irq[i].irq) {
-			regval = gpmc_read_reg(GPMC_IRQENABLE);
-			if (endis)
-				regval |= gpmc_client_irq[i].bitmask;
-			else
-				regval &= ~gpmc_client_irq[i].bitmask;
-			gpmc_write_reg(GPMC_IRQENABLE, regval);
-			break;
-		}
+	regval = gpmc_read_reg(GPMC_IRQENABLE);
+	if (endis)
+		regval |= BIT(hwirq);
+	else
+		regval &= ~BIT(hwirq);
+	gpmc_write_reg(GPMC_IRQENABLE, regval);
 
 	return 0;
 }
 
 static void gpmc_irq_disable(struct irq_data *p)
 {
-	gpmc_irq_endis(p->irq, false);
+	gpmc_irq_endis(p->hwirq, false);
 }
 
 static void gpmc_irq_enable(struct irq_data *p)
 {
-	gpmc_irq_endis(p->irq, true);
+	gpmc_irq_endis(p->hwirq, true);
 }
 
 static void gpmc_irq_noop(struct irq_data *data) { }
 
 static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
 
-static int gpmc_setup_irq(void)
+static int gpmc_irq_map(struct irq_domain *d, unsigned int virq,
+			irq_hw_number_t hw)
 {
-	int i;
+	struct gpmc_device *gpmc = d->host_data;
+
+	irq_set_chip_data(virq, gpmc);
+	irq_set_chip_and_handler(virq, &gpmc->irq_chip, handle_simple_irq);
+	irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
+
+	return 0;
+}
+
+static const struct irq_domain_ops gpmc_irq_domain_ops = {
+	.map    = gpmc_irq_map,
+	.xlate  = irq_domain_xlate_twocell,
+};
+
+static irqreturn_t gpmc_handle_irq(int irq, void *data)
+{
+	int hwirq, virq;
 	u32 regval;
+	struct gpmc_device *gpmc = data;
 
-	if (!gpmc_irq)
-		return -EINVAL;
+	regval = gpmc_read_reg(GPMC_IRQSTATUS);
 
-	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
-	if (gpmc_irq_start < 0) {
-		pr_err("irq_alloc_descs failed\n");
-		return gpmc_irq_start;
-	}
+	if (!regval)
+		return IRQ_NONE;
 
-	gpmc_irq_chip.name = "gpmc";
-	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
-	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
-	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
-
-	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
-	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		gpmc_client_irq[i].irq = gpmc_irq_start + i;
-		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
-					&gpmc_irq_chip, handle_simple_irq);
-		irq_modify_status(gpmc_client_irq[i].irq, IRQ_NOREQUEST,
-				  IRQ_NOAUTOEN);
+	for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++) {
+		if (regval & BIT(hwirq)) {
+			virq = irq_find_mapping(gpmc_irq_domain, hwirq);
+			if (!virq) {
+				dev_warn(gpmc->dev,
+					 "spurious irq detected hwirq %d, virq %d\n",
+					 hwirq, virq);
+			}
+
+			generic_handle_irq(virq);
+		}
 	}
 
+	gpmc_write_reg(GPMC_IRQSTATUS, regval);
+
+	return IRQ_HANDLED;
+}
+
+static int gpmc_setup_irq(struct gpmc_device *gpmc)
+{
+	u32 regval;
+	int rc;
+
 	/* Disable interrupts */
 	gpmc_write_reg(GPMC_IRQENABLE, 0);
 
@@ -1239,22 +1238,46 @@ static int gpmc_setup_irq(void)
 	regval = gpmc_read_reg(GPMC_IRQSTATUS);
 	gpmc_write_reg(GPMC_IRQSTATUS, regval);
 
-	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
+	gpmc->irq_chip.name = "gpmc";
+	gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret;
+	gpmc->irq_chip.irq_enable = gpmc_irq_enable;
+	gpmc->irq_chip.irq_disable = gpmc_irq_disable;
+	gpmc->irq_chip.irq_shutdown = gpmc_irq_noop;
+	gpmc->irq_chip.irq_ack = gpmc_irq_noop;
+	gpmc->irq_chip.irq_mask = gpmc_irq_noop;
+	gpmc->irq_chip.irq_unmask = gpmc_irq_noop;
+
+	gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node,
+						GPMC_NR_IRQ,
+						&gpmc_irq_domain_ops,
+						gpmc);
+	if (!gpmc_irq_domain) {
+		dev_err(gpmc->dev, "IRQ domain add failed\n");
+		return -ENODEV;
+	}
+
+	rc = request_irq(gpmc->irq, gpmc_handle_irq, 0, "gpmc", gpmc);
+	if (rc) {
+		dev_err(gpmc->dev, "failed to request irq %d: %d\n",
+			gpmc->irq, rc);
+		irq_domain_remove(gpmc_irq_domain);
+		gpmc_irq_domain = NULL;
+	}
+
+	return rc;
 }
 
-static int gpmc_free_irq(void)
+static int gpmc_free_irq(struct gpmc_device *gpmc)
 {
-	int i;
+	int hwirq;
 
-	if (gpmc_irq)
-		free_irq(gpmc_irq, NULL);
+	free_irq(gpmc->irq, gpmc);
 
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		irq_set_handler(gpmc_client_irq[i].irq, NULL);
-		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
-	}
+	for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++)
+		irq_dispose_mapping(irq_find_mapping(gpmc_irq_domain, hwirq));
 
-	irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
+	irq_domain_remove(gpmc_irq_domain);
+	gpmc_irq_domain = NULL;
 
 	return 0;
 }
@@ -2154,6 +2177,14 @@ static int gpmc_probe(struct platform_device *pdev)
 	int rc;
 	u32 l;
 	struct resource *res;
+	struct gpmc_device *gpmc;
+
+	gpmc = devm_kzalloc(&pdev->dev, sizeof(*gpmc), GFP_KERNEL);
+	if (!gpmc)
+		return -ENOMEM;
+
+	gpmc->dev = &pdev->dev;
+	platform_set_drvdata(pdev, gpmc);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -2167,15 +2198,16 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_base);
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (res == NULL)
-		dev_warn(&pdev->dev, "Failed to get resource: irq\n");
-	else
-		gpmc_irq = res->start;
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -ENOENT;
+	}
+
+	gpmc->irq = res->start;
 
 	gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
 	if (IS_ERR(gpmc_l3_clk)) {
 		dev_err(&pdev->dev, "Failed to get GPMC fck\n");
-		gpmc_irq = 0;
 		return PTR_ERR(gpmc_l3_clk);
 	}
 
@@ -2187,8 +2219,6 @@ static int gpmc_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
-	gpmc_dev = &pdev->dev;
-
 	l = gpmc_read_reg(GPMC_REVISION);
 
 	/*
@@ -2207,13 +2237,16 @@ static int gpmc_probe(struct platform_device *pdev)
 		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	if (GPMC_REVISION_MAJOR(l) > 0x5)
 		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+	dev_info(gpmc->dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
 
-	if (gpmc_setup_irq() < 0)
-		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
+	rc = gpmc_setup_irq(gpmc);
+	if (rc) {
+		dev_err(gpmc->dev, "gpmc_setup_irq failed\n");
+		goto fail;
+	}
 
 	if (!pdev->dev.of_node) {
 		gpmc_cs_num	 = GPMC_CS_NUM;
@@ -2222,21 +2255,27 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	rc = gpmc_probe_dt(pdev);
 	if (rc < 0) {
-		pm_runtime_put_sync(&pdev->dev);
-		dev_err(gpmc_dev, "failed to probe DT parameters\n");
-		return rc;
+		dev_err(gpmc->dev, "failed to probe DT parameters\n");
+		gpmc_free_irq(gpmc);
+		goto fail;
 	}
 
 	return 0;
+
+fail:
+	pm_runtime_put_sync(&pdev->dev);
+	return rc;
 }
 
 static int gpmc_remove(struct platform_device *pdev)
 {
-	gpmc_free_irq();
+	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
+
+	gpmc_free_irq(gpmc);
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	gpmc_dev = NULL;
+
 	return 0;
 }
 
@@ -2282,25 +2321,6 @@ static __exit void gpmc_exit(void)
 postcore_initcall(gpmc_init);
 module_exit(gpmc_exit);
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev)
-{
-	int i;
-	u32 regval;
-
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-
-	if (!regval)
-		return IRQ_NONE;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (regval & gpmc_client_irq[i].bitmask)
-			generic_handle_irq(gpmc_client_irq[i].irq);
-
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return IRQ_HANDLED;
-}
-
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index dc2ada6..9e9d79e 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -11,8 +11,9 @@
 
 #define GPMC_CONFIG_WP		0x00000005
 
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
+/* IRQ numbers in GPMC IRQ domain for legacy boot use */
+#define GPMC_IRQ_FIFOEVENTENABLE	0
+#define GPMC_IRQ_COUNT_EVENT		1
 
 /**
  * gpmc_nand_ops - Interface between NAND and GPMC


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: mtd: nand: omap: Use gpmc_omap_get_nand_ops() to get NAND registers
Message-ID: <E1b54Qp-0000Qo-97@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c509aefd75d026f4ef4aa306131d7a780c2eda7b
Commit:     c509aefd75d026f4ef4aa306131d7a780c2eda7b
Parent:     384258f252727c67772bbd48dad3185a30ba50d3
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed Aug 5 14:01:50 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:02 2016 +0300

    mtd: nand: omap: Use gpmc_omap_get_nand_ops() to get NAND registers
    
    Deprecate nand register passing via platform data and use
    gpmc_omap_get_nand_ops() instead.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              | 2 --
 drivers/mtd/nand/omap2.c                     | 9 ++++++++-
 include/linux/platform_data/mtd-nand-omap2.h | 4 +++-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 72918c4..04e6998 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -121,8 +121,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		pr_err("omap2-nand: Unsupported NAND ECC scheme selected\n");
 		err = -EINVAL;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 0749ca1..cba9bf0 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -28,6 +28,7 @@
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
 
+#include <linux/omap-gpmc.h>
 #include <linux/platform_data/mtd-nand-omap2.h>
 
 #define	DRIVER_NAME	"omap2-nand"
@@ -168,7 +169,9 @@ struct omap_nand_info {
 	} iomode;
 	u_char				*buf;
 	int					buf_len;
+	/* Interface to GPMC */
 	struct gpmc_nand_regs		reg;
+	struct gpmc_nand_ops		*ops;
 	/* generated at runtime depending on ECC algorithm and layout selected */
 	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
@@ -1665,9 +1668,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, info);
 
+	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
+	if (!info->ops) {
+		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
+		return -ENODEV;
+	}
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
-	info->reg		= pdata->reg;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
 	nand_chip		= &info->nand;
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 090bbab..a067f58 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -75,10 +75,12 @@ struct omap_nand_platform_data {
 	enum nand_io		xfer_type;
 	int			devsize;
 	enum omap_ecc           ecc_opt;
-	struct gpmc_nand_regs	reg;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
+
+	/* deprecated */
+	struct gpmc_nand_regs	reg;
 };
 #endif


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: mtd: nand: omap: Switch to using GPMC-NAND ops for writebuffer empty
 check
Message-ID: <E1b54Qp-0000RD-CU@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d6e552168db59d627fd56074f2c588df1faf0c95
Commit:     d6e552168db59d627fd56074f2c588df1faf0c95
Parent:     c509aefd75d026f4ef4aa306131d7a780c2eda7b
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed Aug 5 13:36:43 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:20 2016 +0300

    mtd: nand: omap: Switch to using GPMC-NAND ops for writebuffer empty check
    
    Instead of accessing the gpmc_status register directly start
    using the gpmc_nand_ops->nand_writebuffer_empty() helper
    to check write buffer empty status.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/mtd/nand/omap2.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index cba9bf0..98023d5 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -291,14 +291,13 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 {
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 	u_char *p = (u_char *)buf;
-	u32	status = 0;
+	bool status;
 
 	while (len--) {
 		iowrite8(*p++, info->nand.IO_ADDR_W);
 		/* wait until buffer is available for write */
 		do {
-			status = readl(info->reg.gpmc_status) &
-					STATUS_BUFF_EMPTY;
+			status = info->ops->nand_writebuffer_empty();
 		} while (!status);
 	}
 }
@@ -326,7 +325,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 {
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 	u16 *p = (u16 *) buf;
-	u32	status = 0;
+	bool status;
 	/* FIXME try bursts of writesw() or DMA ... */
 	len >>= 1;
 
@@ -334,8 +333,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 		iowrite16(*p++, info->nand.IO_ADDR_W);
 		/* wait until buffer is available for write */
 		do {
-			status = readl(info->reg.gpmc_status) &
-					STATUS_BUFF_EMPTY;
+			status = info->ops->nand_writebuffer_empty();
 		} while (!status);
 	}
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: mtd: nand: omap: Copy platform data parameters to omap_nand_info data
Message-ID: <E1b54Qp-0000Rc-GS@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=01b95fc6b299b99075b8980371fc19b980236c32
Commit:     01b95fc6b299b99075b8980371fc19b980236c32
Parent:     d6e552168db59d627fd56074f2c588df1faf0c95
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Tue May 20 22:29:28 2014 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:28 2016 +0300

    mtd: nand: omap: Copy platform data parameters to omap_nand_info data
    
    Copy all the platform data parameters to the driver's local data
    structure 'omap_nand_info' and use it in the entire driver. This will
    make it easer for device tree migration.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/mtd/nand/omap2.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 98023d5..7e4e263 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -152,13 +152,17 @@ static struct nand_hw_control omap_gpmc_controller = {
 };
 
 struct omap_nand_info {
-	struct omap_nand_platform_data	*pdata;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
 
 	int				gpmc_cs;
-	unsigned long			phys_base;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
 	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
+	unsigned long			phys_base;
 	struct completion		comp;
 	struct dma_chan			*dma;
 	int				gpmc_irq_fifo;
@@ -1631,7 +1635,7 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
 			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
 		return false;
 	}
-	if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) {
+	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
 		dev_err(&info->pdev->dev, "ELM not available\n");
 		return false;
 	}
@@ -1675,6 +1679,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
+	info->dev_ready	= pdata->dev_ready;
+	info->xfer_type = pdata->xfer_type;
+	info->devsize = pdata->devsize;
+	info->elm_of_node = pdata->elm_of_node;
+
 	nand_chip		= &info->nand;
 	mtd			= nand_to_mtd(nand_chip);
 	mtd->dev.parent		= &pdev->dev;
@@ -1700,7 +1709,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (pdata->dev_ready) {
+	if (info->dev_ready) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
@@ -1714,15 +1723,16 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->options |= NAND_SKIP_BBTSCAN;
 
 	/* scan NAND device connected to chip controller */
-	nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 	if (nand_scan_ident(mtd, 1, NULL)) {
-		dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n");
+		dev_err(&info->pdev->dev,
+			"scan failed, may be bus-width mismatch\n");
 		err = -ENXIO;
 		goto return_error;
 	}
 
 	/* re-populate low-level callbacks based on xfer modes */
-	switch (pdata->xfer_type) {
+	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		nand_chip->read_buf   = omap_read_buf_pref;
 		nand_chip->write_buf  = omap_write_buf_pref;
@@ -1802,7 +1812,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	default:
 		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", pdata->xfer_type);
+			"xfer_type(%d) not supported!\n", info->xfer_type);
 		err = -EINVAL;
 		goto return_error;
 	}


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: mtd: nand: omap: Clean up device tree support
Message-ID: <E1b54Qp-0000S1-Jb@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c9711ec5250b22fd94e9b34c17c095e001a90e66
Commit:     c9711ec5250b22fd94e9b34c17c095e001a90e66
Parent:     01b95fc6b299b99075b8980371fc19b980236c32
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed May 21 07:29:03 2014 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:36 2016 +0300

    mtd: nand: omap: Clean up device tree support
    
    Move NAND specific device tree parsing to NAND driver.
    
    The NAND controller node must have a compatible id, register space
    resource and interrupt resource.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   5 +-
 drivers/memory/omap-gpmc.c                   | 143 +++++++--------------------
 drivers/mtd/nand/omap2.c                     | 134 +++++++++++++++++++++----
 include/linux/platform_data/mtd-nand-omap2.h |   3 +-
 4 files changed, 153 insertions(+), 132 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 04e6998..f6ac027 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -97,10 +97,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
-	if (gpmc_nand_data->of_node)
-		gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
-	else
-		gpmc_set_legacy(gpmc_nand_data, &s);
+	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index e28d6bc..8dc6e3b 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -30,7 +30,6 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/omap-gpmc.h>
-#include <linux/mtd/nand.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
@@ -1852,105 +1851,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED]		= "prefetch-polled",
-	[NAND_OMAP_POLLED]			= "polled",
-	[NAND_OMAP_PREFETCH_DMA]		= "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ]		= "prefetch-irq",
-};
-
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	const char *s;
-	struct gpmc_timings gpmc_t;
-	struct omap_nand_platform_data *gpmc_nand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
-				      GFP_KERNEL);
-	if (!gpmc_nand_data)
-		return -ENOMEM;
-
-	gpmc_nand_data->cs = val;
-	gpmc_nand_data->of_node = child;
-
-	/* Detect availability of ELM module */
-	gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		gpmc_nand_data->elm_of_node =
-					of_parse_phandle(child, "elm_id", 0);
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
-		return -ENODEV;
-	}
-
-	if (!strcmp(s, "sw"))
-		gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
-	else if (!strcmp(s, "ham1") ||
-		 !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
-		gpmc_nand_data->ecc_opt =
-				OMAP_ECC_HAM1_CODE_HW;
-	else if (!strcmp(s, "bch4"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch8"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch16"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH16_CODE_HW;
-		else
-			pr_err("%s: BCH16 requires ELM support\n", __func__);
-	else
-		pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
-
-	/* select data transfer mode for NAND controller */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
-		for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
-			if (!strcasecmp(s, nand_xfer_types[val])) {
-				gpmc_nand_data->xfer_type = val;
-				break;
-			}
-
-	gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
-
-	val = of_get_nand_bus_width(child);
-	if (val == 16)
-		gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_nand_init(gpmc_nand_data, &gpmc_t);
-
-	return 0;
-}
-#else
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 #if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
 				 struct device_node *child)
@@ -2069,9 +1969,42 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 		goto err;
 	}
 
-	ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
-	if (ret < 0)
-		goto err;
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* Warn about older DT blobs with no compatible property */
+		if (!of_property_read_bool(child, "compatible")) {
+			dev_warn(&pdev->dev,
+				 "Incompatible NAND node: missing compatible");
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+
+	if (of_device_is_compatible(child, "ti,omap2-nand")) {
+		/* NAND specific setup */
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		/* disable write protect */
+		gpmc_configure(GPMC_CONFIG_WP, 0);
+		gpmc_s.device_nand = true;
+	} else {
+		ret = of_property_read_u32(child, "bank-width",
+					   &gpmc_s.device_width);
+		if (ret < 0)
+			goto err;
+	}
 
 	gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
@@ -2155,9 +2088,7 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "nand") == 0)
-			ret = gpmc_probe_nand_child(pdev, child);
-		else if (of_node_cmp(child->name, "onenand") == 0)
+		if (of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else
 			ret = gpmc_probe_generic_child(pdev, child);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 7e4e263..35b8f33 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -176,11 +177,11 @@ struct omap_nand_info {
 	/* Interface to GPMC */
 	struct gpmc_nand_regs		reg;
 	struct gpmc_nand_ops		*ops;
+	bool				flash_bbt;
 	/* generated at runtime depending on ECC algorithm and layout selected */
 	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
 	struct device			*elm_dev;
-	struct device_node		*of_node;
 };
 
 static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@@ -1643,10 +1644,86 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
 	return true;
 }
 
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+	u32 cs;
+
+	if (of_property_read_u32(child, "reg", &cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	info->gpmc_cs = cs;
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (!info->elm_of_node)
+		dev_dbg(dev, "ti,elm-id not in DT\n");
+
+	/* select ecc-scheme for NAND */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		dev_err(dev, "ti,nand-ecc-opt not found\n");
+		return -EINVAL;
+	}
+
+	if (!strcmp(s, "sw")) {
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
+	} else if (!strcmp(s, "ham1") ||
+		   !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
+	} else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch16")) {
+		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				goto next;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+next:
+	of_get_nand_on_flash_bbt(child);
+
+	if (of_get_nand_bus_width(child) == 16)
+		info->devsize = NAND_BUSWIDTH_16;
+
+	return 0;
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info		*info;
-	struct omap_nand_platform_data	*pdata;
+	struct omap_nand_platform_data	*pdata = NULL;
 	struct mtd_info			*mtd;
 	struct nand_chip		*nand_chip;
 	struct nand_ecclayout		*ecclayout;
@@ -1656,39 +1733,47 @@ static int omap_nand_probe(struct platform_device *pdev)
 	unsigned			sig;
 	unsigned			oob_index;
 	struct resource			*res;
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
+	struct device			*dev = &pdev->dev;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, info);
+	info->pdev = pdev;
 
+	if (dev->of_node) {
+		if (omap_get_dt_info(dev, info))
+			return -EINVAL;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (!pdata) {
+			dev_err(&pdev->dev, "platform data missing\n");
+			return -EINVAL;
+		}
+
+		info->gpmc_cs = pdata->cs;
+		info->reg = pdata->reg;
+		info->ecc_opt = pdata->ecc_opt;
+		info->dev_ready	= pdata->dev_ready;
+		info->xfer_type = pdata->xfer_type;
+		info->devsize = pdata->devsize;
+		info->elm_of_node = pdata->elm_of_node;
+		info->flash_bbt = pdata->flash_bbt;
+	}
+
+	platform_set_drvdata(pdev, info);
 	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
 	if (!info->ops) {
 		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
 		return -ENODEV;
 	}
-	info->pdev		= pdev;
-	info->gpmc_cs		= pdata->cs;
-	info->of_node		= pdata->of_node;
-	info->ecc_opt		= pdata->ecc_opt;
-	info->dev_ready	= pdata->dev_ready;
-	info->xfer_type = pdata->xfer_type;
-	info->devsize = pdata->devsize;
-	info->elm_of_node = pdata->elm_of_node;
 
 	nand_chip		= &info->nand;
 	mtd			= nand_to_mtd(nand_chip);
 	mtd->dev.parent		= &pdev->dev;
 	nand_chip->ecc.priv	= NULL;
-	nand_set_flash_node(nand_chip, pdata->of_node);
+	nand_set_flash_node(nand_chip, dev->of_node);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
@@ -1717,7 +1802,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->chip_delay = 50;
 	}
 
-	if (pdata->flash_bbt)
+	if (info->flash_bbt)
 		nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 	else
 		nand_chip->options |= NAND_SKIP_BBTSCAN;
@@ -2035,7 +2120,10 @@ scan_tail:
 		goto return_error;
 	}
 
-	mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+	if (dev->of_node)
+		mtd_device_register(mtd, NULL, 0);
+	else
+		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
 
 	platform_set_drvdata(pdev, mtd);
 
@@ -2066,11 +2154,17 @@ static int omap_nand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
 	.remove		= omap_nand_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.of_match_table = of_match_ptr(omap_nand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index a067f58..ff27e5a 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -76,11 +76,10 @@ struct omap_nand_platform_data {
 	int			devsize;
 	enum omap_ecc           ecc_opt;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
 
 	/* deprecated */
 	struct gpmc_nand_regs	reg;
+	struct device_node	*of_node;
 };
 #endif


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: mtd: nand: omap: Update DT binding documentation
Message-ID: <E1b54Qp-0000SQ-NG@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=51735caad3db6237fa9d31a2ce8b54cbd42ff6f0
Commit:     51735caad3db6237fa9d31a2ce8b54cbd42ff6f0
Parent:     c9711ec5250b22fd94e9b34c17c095e001a90e66
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Mon May 26 11:54:45 2014 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:46 2016 +0300

    mtd: nand: omap: Update DT binding documentation
    
    Add compatible id and interrupts. The NAND interrupts are
    provided by the GPMC controller node.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index fb733c4..ff3215d2 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -13,7 +13,11 @@ Documentation/devicetree/bindings/mtd/nand.txt
 
 Required properties:
 
- - reg:		The CS line the peripheral is connected to
+ - compatible:	"ti,omap2-nand"
+ - reg:		range id (CS number), base offset and length of the
+		NAND I/O space
+ - interrupt-parent: must point to gpmc node
+ - interrupts:	Two interrupt specifiers, one for fifoevent, one for termcount.
 
 Optional properties:
 
@@ -55,17 +59,22 @@ Example for an AM33xx board:
 	gpmc: gpmc at 50000000 {
 		compatible = "ti,am3352-gpmc";
 		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x1000000>;
+		reg = <0x50000000 0x36c>;
 		interrupts = <100>;
 		gpmc,num-cs = <8>;
 		gpmc,num-waitpins = <2>;
 		#address-cells = <2>;
 		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x2000>;	/* CS0: NAND */
+		ranges = <0 0 0x08000000 0x1000000>;	/* CS0 space, 16MB */
 		elm_id = <&elm>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
 
 		nand at 0,0 {
-			reg = <0 0 0>; /* CS0, offset 0 */
+			compatible = "ti,omap2-nand";
+			reg = <0 0 4>;		/* CS0, offset 0, NAND I/O window 4 */
+			interrupt-parent = <&gpmc>;
+			interrupts = <0 IRQ_TYPE_NONE>, <1 IRQ_TYPE NONE>;
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: memory: omap-gpmc: Prevent mapping into 1st 16MB
Message-ID: <E1b54Qp-0000Sp-R8@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=bdd7e033fe4cc3836b141b75119a4a975a64d9bc
Commit:     bdd7e033fe4cc3836b141b75119a4a975a64d9bc
Parent:     51735caad3db6237fa9d31a2ce8b54cbd42ff6f0
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Thu Jul 9 17:31:45 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:53:54 2016 +0300

    memory: omap-gpmc: Prevent mapping into 1st 16MB
    
    We have been preventing mapping GPMC children in the
    first 1MB but really it has to be the first 16MB as
    the minimum GPMC partition size is 16MB.
    
    Also print an error message if CS mapping fails
    due to DT requesting address outside the GPMC
    map.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/memory/omap-gpmc.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 8dc6e3b..bfe4e87 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -94,6 +94,14 @@
 #define GPMC_CS_SIZE		0x30
 #define	GPMC_BCH_SIZE		0x10
 
+/*
+ * The first 1MB of GPMC address space is typically mapped to
+ * the internal ROM. Never allocate the first page, to
+ * facilitate bug detection; even if we didn't boot from ROM.
+ * As GPMC minimum partition size is 16MB we can only start from
+ * there.
+ */
+#define GPMC_MEM_START		0x1000000
 #define GPMC_MEM_END		0x3FFFFFFF
 
 #define GPMC_CHUNK_SHIFT	24		/* 16 MB */
@@ -1297,12 +1305,7 @@ static void gpmc_mem_init(void)
 {
 	int cs;
 
-	/*
-	 * The first 1MB of GPMC address space is typically mapped to
-	 * the internal ROM. Never allocate the first page, to
-	 * facilitate bug detection; even if we didn't boot from ROM.
-	 */
-	gpmc_mem_root.start = SZ_1M;
+	gpmc_mem_root.start = GPMC_MEM_START;
 	gpmc_mem_root.end = GPMC_MEM_END;
 
 	/* Reserve all regions that has been set up by bootloader */
@@ -1966,6 +1969,15 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	if (ret < 0) {
 		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
 			cs, &res.start);
+		if (res.start < GPMC_MEM_START) {
+			dev_info(&pdev->dev,
+				 "GPMC CS %d start cannot be lesser than 0x%x\n",
+				 cs, GPMC_MEM_START);
+		} else if (res.end > GPMC_MEM_END) {
+			dev_info(&pdev->dev,
+				 "GPMC CS %d end cannot be greater than 0x%x\n",
+				 cs, GPMC_MEM_END);
+		}
 		goto err;
 	}
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:03 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:03 +0000
Subject: memory: omap-gpmc: Move device tree binding to correct location
Message-ID: <E1b54Qp-0000TE-Td@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=3c76f6119a64eb8ff6d088ceb6ca03891e29a7ce
Commit:     3c76f6119a64eb8ff6d088ceb6ca03891e29a7ce
Parent:     bdd7e033fe4cc3836b141b75119a4a975a64d9bc
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Wed Aug 5 17:01:54 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:54:03 2016 +0300

    memory: omap-gpmc: Move device tree binding to correct location
    
    omap-gpmc.c is a memory controller so move the binding to the
    right place.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 Documentation/devicetree/bindings/bus/ti-gpmc.txt  | 143 ---------------------
 .../bindings/memory-controllers/omap-gpmc.txt      | 143 +++++++++++++++++++++
 2 files changed, 143 insertions(+), 143 deletions(-)

diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt
deleted file mode 100644
index 13f1378..0000000
--- a/Documentation/devicetree/bindings/bus/ti-gpmc.txt
+++ /dev/null
@@ -1,143 +0,0 @@
-Device tree bindings for OMAP general purpose memory controllers (GPMC)
-
-The actual devices are instantiated from the child nodes of a GPMC node.
-
-Required properties:
-
- - compatible:		Should be set to one of the following:
-
-			ti,omap2420-gpmc (omap2420)
-			ti,omap2430-gpmc (omap2430)
-			ti,omap3430-gpmc (omap3430 & omap3630)
-			ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
-			ti,am3352-gpmc   (am335x devices)
-
- - reg:			A resource specifier for the register space
-			(see the example below)
- - ti,hwmods:		Should be set to "ti,gpmc" until the DT transition is
-			completed.
- - #address-cells:	Must be set to 2 to allow memory address translation
- - #size-cells:		Must be set to 1 to allow CS address passing
- - gpmc,num-cs:		The maximum number of chip-select lines that controller
-			can support.
- - gpmc,num-waitpins:	The maximum number of wait pins that controller can
-			support.
- - ranges:		Must be set up to reflect the memory layout with four
-			integer values for each chip-select line in use:
-
-			   <cs-number> 0 <physical address of mapping> <size>
-
-			Currently, calculated values derived from the contents
-			of the per-CS register GPMC_CONFIG7 (as set up by the
-			bootloader) are used for the physical address decoding.
-			As this will change in the future, filling correct
-			values here is a requirement.
- - interrupt-controller: The GPMC driver implements and interrupt controller for
-			the NAND events "fifoevent" and "termcount".
-			The interrupt number mapping is as follows
-			0 - NAND_fifoevent
-			1 - NAND_termcount
- - interrupt-cells:	Must be set to 2
-
-Timing properties for child nodes. All are optional and default to 0.
-
- - gpmc,sync-clk-ps:	Minimum clock period for synchronous mode, in picoseconds
-
- Chip-select signal timings (in nanoseconds) corresponding to GPMC_CONFIG2:
- - gpmc,cs-on-ns:	Assertion time
- - gpmc,cs-rd-off-ns:	Read deassertion time
- - gpmc,cs-wr-off-ns:	Write deassertion time
-
- ADV signal timings (in nanoseconds) corresponding to GPMC_CONFIG3:
- - gpmc,adv-on-ns:	Assertion time
- - gpmc,adv-rd-off-ns:	Read deassertion time
- - gpmc,adv-wr-off-ns:	Write deassertion time
- - gpmc,adv-aad-mux-on-ns:	Assertion time for AAD
- - gpmc,adv-aad-mux-rd-off-ns:	Read deassertion time for AAD
- - gpmc,adv-aad-mux-wr-off-ns:	Write deassertion time for AAD
-
- WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
- - gpmc,we-on-ns	Assertion time
- - gpmc,we-off-ns:	Deassertion time
-
- OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
- - gpmc,oe-on-ns:	Assertion time
- - gpmc,oe-off-ns:	Deassertion time
- - gpmc,oe-aad-mux-on-ns:	Assertion time for AAD
- - gpmc,oe-aad-mux-off-ns:	Deassertion time for AAD
-
- Access time and cycle time timings (in nanoseconds) corresponding to
- GPMC_CONFIG5:
- - gpmc,page-burst-access-ns: 	Multiple access word delay
- - gpmc,access-ns:		Start-cycle to first data valid delay
- - gpmc,rd-cycle-ns:		Total read cycle time
- - gpmc,wr-cycle-ns:		Total write cycle time
- - gpmc,bus-turnaround-ns:	Turn-around time between successive accesses
- - gpmc,cycle2cycle-delay-ns:	Delay between chip-select pulses
- - gpmc,clk-activation-ns: 	GPMC clock activation time
- - gpmc,wait-monitoring-ns:	Start of wait monitoring with regard to valid
-				data
-
-Boolean timing parameters. If property is present parameter enabled and
-disabled if omitted:
- - gpmc,adv-extra-delay:	ADV signal is delayed by half GPMC clock
- - gpmc,cs-extra-delay:		CS signal is delayed by half GPMC clock
- - gpmc,cycle2cycle-diffcsen:	Add "cycle2cycle-delay" between successive
-				accesses to a different CS
- - gpmc,cycle2cycle-samecsen:	Add "cycle2cycle-delay" between successive
-				accesses to the same CS
- - gpmc,oe-extra-delay:		OE signal is delayed by half GPMC clock
- - gpmc,we-extra-delay:		WE signal is delayed by half GPMC clock
- - gpmc,time-para-granularity:	Multiply all access times by 2
-
-The following are only applicable to OMAP3+ and AM335x:
- - gpmc,wr-access-ns:		In synchronous write mode, for single or
-				burst accesses, defines the number of
-				GPMC_FCLK cycles from start access time
-				to the GPMC_CLK rising edge used by the
-				memory device for the first data capture.
- - gpmc,wr-data-mux-bus-ns:	In address-data multiplex mode, specifies
-				the time when the first data is driven on
-				the address-data bus.
-
-GPMC chip-select settings properties for child nodes. All are optional.
-
-- gpmc,burst-length	Page/burst length. Must be 4, 8 or 16.
-- gpmc,burst-wrap	Enables wrap bursting
-- gpmc,burst-read	Enables read page/burst mode
-- gpmc,burst-write	Enables write page/burst mode
-- gpmc,device-width	Total width of device(s) connected to a GPMC
-			chip-select in bytes. The GPMC supports 8-bit
-			and 16-bit devices and so this property must be
-			1 or 2.
-- gpmc,mux-add-data	Address and data multiplexing configuration.
-			Valid values are 1 for address-address-data
-			multiplexing mode and 2 for address-data
-			multiplexing mode.
-- gpmc,sync-read	Enables synchronous read. Defaults to asynchronous
-			is this is not set.
-- gpmc,sync-write	Enables synchronous writes. Defaults to asynchronous
-			is this is not set.
-- gpmc,wait-pin		Wait-pin used by client. Must be less than
-			"gpmc,num-waitpins".
-- gpmc,wait-on-read	Enables wait monitoring on reads.
-- gpmc,wait-on-write	Enables wait monitoring on writes.
-
-Example for an AM33xx board:
-
-	gpmc: gpmc at 50000000 {
-		compatible = "ti,am3352-gpmc";
-		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x2000>;
-		interrupts = <100>;
-
-		gpmc,num-cs = <8>;
-		gpmc,num-waitpins = <2>;
-		#address-cells = <2>;
-		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
-		interrupt-controller;
-		#interrupt-cells = <2>;
-
-		/* child nodes go here */
-	};
diff --git a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
new file mode 100644
index 0000000..13f1378
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
@@ -0,0 +1,143 @@
+Device tree bindings for OMAP general purpose memory controllers (GPMC)
+
+The actual devices are instantiated from the child nodes of a GPMC node.
+
+Required properties:
+
+ - compatible:		Should be set to one of the following:
+
+			ti,omap2420-gpmc (omap2420)
+			ti,omap2430-gpmc (omap2430)
+			ti,omap3430-gpmc (omap3430 & omap3630)
+			ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
+			ti,am3352-gpmc   (am335x devices)
+
+ - reg:			A resource specifier for the register space
+			(see the example below)
+ - ti,hwmods:		Should be set to "ti,gpmc" until the DT transition is
+			completed.
+ - #address-cells:	Must be set to 2 to allow memory address translation
+ - #size-cells:		Must be set to 1 to allow CS address passing
+ - gpmc,num-cs:		The maximum number of chip-select lines that controller
+			can support.
+ - gpmc,num-waitpins:	The maximum number of wait pins that controller can
+			support.
+ - ranges:		Must be set up to reflect the memory layout with four
+			integer values for each chip-select line in use:
+
+			   <cs-number> 0 <physical address of mapping> <size>
+
+			Currently, calculated values derived from the contents
+			of the per-CS register GPMC_CONFIG7 (as set up by the
+			bootloader) are used for the physical address decoding.
+			As this will change in the future, filling correct
+			values here is a requirement.
+ - interrupt-controller: The GPMC driver implements and interrupt controller for
+			the NAND events "fifoevent" and "termcount".
+			The interrupt number mapping is as follows
+			0 - NAND_fifoevent
+			1 - NAND_termcount
+ - interrupt-cells:	Must be set to 2
+
+Timing properties for child nodes. All are optional and default to 0.
+
+ - gpmc,sync-clk-ps:	Minimum clock period for synchronous mode, in picoseconds
+
+ Chip-select signal timings (in nanoseconds) corresponding to GPMC_CONFIG2:
+ - gpmc,cs-on-ns:	Assertion time
+ - gpmc,cs-rd-off-ns:	Read deassertion time
+ - gpmc,cs-wr-off-ns:	Write deassertion time
+
+ ADV signal timings (in nanoseconds) corresponding to GPMC_CONFIG3:
+ - gpmc,adv-on-ns:	Assertion time
+ - gpmc,adv-rd-off-ns:	Read deassertion time
+ - gpmc,adv-wr-off-ns:	Write deassertion time
+ - gpmc,adv-aad-mux-on-ns:	Assertion time for AAD
+ - gpmc,adv-aad-mux-rd-off-ns:	Read deassertion time for AAD
+ - gpmc,adv-aad-mux-wr-off-ns:	Write deassertion time for AAD
+
+ WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
+ - gpmc,we-on-ns	Assertion time
+ - gpmc,we-off-ns:	Deassertion time
+
+ OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
+ - gpmc,oe-on-ns:	Assertion time
+ - gpmc,oe-off-ns:	Deassertion time
+ - gpmc,oe-aad-mux-on-ns:	Assertion time for AAD
+ - gpmc,oe-aad-mux-off-ns:	Deassertion time for AAD
+
+ Access time and cycle time timings (in nanoseconds) corresponding to
+ GPMC_CONFIG5:
+ - gpmc,page-burst-access-ns: 	Multiple access word delay
+ - gpmc,access-ns:		Start-cycle to first data valid delay
+ - gpmc,rd-cycle-ns:		Total read cycle time
+ - gpmc,wr-cycle-ns:		Total write cycle time
+ - gpmc,bus-turnaround-ns:	Turn-around time between successive accesses
+ - gpmc,cycle2cycle-delay-ns:	Delay between chip-select pulses
+ - gpmc,clk-activation-ns: 	GPMC clock activation time
+ - gpmc,wait-monitoring-ns:	Start of wait monitoring with regard to valid
+				data
+
+Boolean timing parameters. If property is present parameter enabled and
+disabled if omitted:
+ - gpmc,adv-extra-delay:	ADV signal is delayed by half GPMC clock
+ - gpmc,cs-extra-delay:		CS signal is delayed by half GPMC clock
+ - gpmc,cycle2cycle-diffcsen:	Add "cycle2cycle-delay" between successive
+				accesses to a different CS
+ - gpmc,cycle2cycle-samecsen:	Add "cycle2cycle-delay" between successive
+				accesses to the same CS
+ - gpmc,oe-extra-delay:		OE signal is delayed by half GPMC clock
+ - gpmc,we-extra-delay:		WE signal is delayed by half GPMC clock
+ - gpmc,time-para-granularity:	Multiply all access times by 2
+
+The following are only applicable to OMAP3+ and AM335x:
+ - gpmc,wr-access-ns:		In synchronous write mode, for single or
+				burst accesses, defines the number of
+				GPMC_FCLK cycles from start access time
+				to the GPMC_CLK rising edge used by the
+				memory device for the first data capture.
+ - gpmc,wr-data-mux-bus-ns:	In address-data multiplex mode, specifies
+				the time when the first data is driven on
+				the address-data bus.
+
+GPMC chip-select settings properties for child nodes. All are optional.
+
+- gpmc,burst-length	Page/burst length. Must be 4, 8 or 16.
+- gpmc,burst-wrap	Enables wrap bursting
+- gpmc,burst-read	Enables read page/burst mode
+- gpmc,burst-write	Enables write page/burst mode
+- gpmc,device-width	Total width of device(s) connected to a GPMC
+			chip-select in bytes. The GPMC supports 8-bit
+			and 16-bit devices and so this property must be
+			1 or 2.
+- gpmc,mux-add-data	Address and data multiplexing configuration.
+			Valid values are 1 for address-address-data
+			multiplexing mode and 2 for address-data
+			multiplexing mode.
+- gpmc,sync-read	Enables synchronous read. Defaults to asynchronous
+			is this is not set.
+- gpmc,sync-write	Enables synchronous writes. Defaults to asynchronous
+			is this is not set.
+- gpmc,wait-pin		Wait-pin used by client. Must be less than
+			"gpmc,num-waitpins".
+- gpmc,wait-on-read	Enables wait monitoring on reads.
+- gpmc,wait-on-write	Enables wait monitoring on writes.
+
+Example for an AM33xx board:
+
+	gpmc: gpmc at 50000000 {
+		compatible = "ti,am3352-gpmc";
+		ti,hwmods = "gpmc";
+		reg = <0x50000000 0x2000>;
+		interrupts = <100>;
+
+		gpmc,num-cs = <8>;
+		gpmc,num-waitpins = <2>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		/* child nodes go here */
+	};


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: memory: omap-gpmc: Support general purpose input for WAITPINs
Message-ID: <E1b54Qq-0000Td-0M@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d2d00862dfbbd22d80ee67f816cb7eeaea71f03b
Commit:     d2d00862dfbbd22d80ee67f816cb7eeaea71f03b
Parent:     3c76f6119a64eb8ff6d088ceb6ca03891e29a7ce
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Mon Mar 7 12:18:43 2016 +0200
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:54:12 2016 +0300

    memory: omap-gpmc: Support general purpose input for WAITPINs
    
    OMAPs can have 2 to 4 WAITPINs that can be used as general purpose
    input if not used for memory wait state insertion.
    
    The first user will be the OMAP NAND chip to get the NAND
    read/busy status using gpiolib.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 .../bindings/memory-controllers/omap-gpmc.txt      |   6 ++
 drivers/memory/Kconfig                             |   1 +
 drivers/memory/omap-gpmc.c                         | 117 ++++++++++++++++++---
 3 files changed, 112 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
index 13f1378..97e7192 100644
--- a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
@@ -38,6 +38,10 @@ Required properties:
 			0 - NAND_fifoevent
 			1 - NAND_termcount
  - interrupt-cells:	Must be set to 2
+ - gpio-controller:	The GPMC driver implements a GPIO controller for the
+			GPMC WAIT pins that can be used as general purpose inputs.
+			0 maps to GPMC_WAIT0 pin.
+ - gpio-cells:		Must be set to 2
 
 Timing properties for child nodes. All are optional and default to 0.
 
@@ -138,6 +142,8 @@ Example for an AM33xx board:
 		ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
 		interrupt-controller;
 		#interrupt-cells = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
 
 		/* child nodes go here */
 	};
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 51d5cd2..a9b1c14 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -51,6 +51,7 @@ config TI_EMIF
 
 config OMAP_GPMC
 	bool
+	select GPIOLIB
 	help
 	  This driver is for the General Purpose Memory Controller (GPMC)
 	  present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index bfe4e87..4dd1c65 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/platform_device.h>
@@ -237,6 +238,7 @@ struct gpmc_device {
 	struct device *dev;
 	int irq;
 	struct irq_chip irq_chip;
+	struct gpio_chip gpio_chip;
 };
 
 static struct irq_domain *gpmc_irq_domain;
@@ -2064,10 +2066,71 @@ err:
 	return ret;
 }
 
+static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+	return 1;	/* we're input only */
+}
+
+static int gpmc_gpio_direction_input(struct gpio_chip *chip,
+				     unsigned int offset)
+{
+	return 0;	/* we're input only */
+}
+
+static int gpmc_gpio_direction_output(struct gpio_chip *chip,
+				      unsigned int offset, int value)
+{
+	return -EINVAL;	/* we're input only */
+}
+
+static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			  int value)
+{
+}
+
+static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	u32 reg;
+
+	offset += 8;
+
+	reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
+
+	return !!reg;
+}
+
+static int gpmc_gpio_init(struct gpmc_device *gpmc)
+{
+	int ret;
+
+	gpmc->gpio_chip.parent = gpmc->dev;
+	gpmc->gpio_chip.owner = THIS_MODULE;
+	gpmc->gpio_chip.label = DEVICE_NAME;
+	gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
+	gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
+	gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
+	gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
+	gpmc->gpio_chip.set = gpmc_gpio_set;
+	gpmc->gpio_chip.get = gpmc_gpio_get;
+	gpmc->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&gpmc->gpio_chip);
+	if (ret < 0) {
+		dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void gpmc_gpio_exit(struct gpmc_device *gpmc)
+{
+	gpiochip_remove(&gpmc->gpio_chip);
+}
+
 static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	int ret;
-	struct device_node *child;
 	const struct of_device_id *of_id =
 		of_match_device(gpmc_dt_ids, &pdev->dev);
 
@@ -2095,6 +2158,14 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		return ret;
 	}
 
+	return 0;
+}
+
+static int gpmc_probe_dt_children(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *child;
+
 	for_each_available_child_of_node(pdev->dev.of_node, child) {
 
 		if (!child->name)
@@ -2104,6 +2175,9 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else
 			ret = gpmc_probe_generic_child(pdev, child);
+
+		if (ret)
+			return ret;
 	}
 
 	return 0;
@@ -2113,6 +2187,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	return 0;
 }
+
+static int gpmc_probe_dt_children(struct platform_device *pdev)
+{
+	return 0;
+}
 #endif
 
 static int gpmc_probe(struct platform_device *pdev)
@@ -2159,6 +2238,15 @@ static int gpmc_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	if (pdev->dev.of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc)
+			return rc;
+	} else {
+		gpmc_cs_num = GPMC_CS_NUM;
+		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+	}
+
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
@@ -2184,29 +2272,33 @@ static int gpmc_probe(struct platform_device *pdev)
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
+	rc = gpmc_gpio_init(gpmc);
+	if (rc)
+		goto gpio_init_failed;
 
 	rc = gpmc_setup_irq(gpmc);
 	if (rc) {
 		dev_err(gpmc->dev, "gpmc_setup_irq failed\n");
-		goto fail;
+		goto setup_irq_failed;
 	}
 
-	if (!pdev->dev.of_node) {
-		gpmc_cs_num	 = GPMC_CS_NUM;
-		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-	}
-
-	rc = gpmc_probe_dt(pdev);
+	rc = gpmc_probe_dt_children(pdev);
 	if (rc < 0) {
-		dev_err(gpmc->dev, "failed to probe DT parameters\n");
-		gpmc_free_irq(gpmc);
-		goto fail;
+		dev_err(gpmc->dev, "failed to probe DT children\n");
+		goto dt_children_failed;
 	}
 
 	return 0;
 
-fail:
+dt_children_failed:
+	gpmc_free_irq(gpmc);
+setup_irq_failed:
+	gpmc_gpio_exit(gpmc);
+gpio_init_failed:
+	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	return rc;
 }
 
@@ -2215,6 +2307,7 @@ static int gpmc_remove(struct platform_device *pdev)
 	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
 
 	gpmc_free_irq(gpmc);
+	gpmc_gpio_exit(gpmc);
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring
Message-ID: <E1b54Qq-0000U2-41@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=210325f0f4eb531f83ffb0b0f95612e2a8063983
Commit:     210325f0f4eb531f83ffb0b0f95612e2a8063983
Parent:     d2d00862dfbbd22d80ee67f816cb7eeaea71f03b
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Thu Aug 6 13:21:40 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:55:00 2016 +0300

    memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring
    
    If the device attached to GPMC wants to use the WAIT pin
    for WAIT monitoring then we reserve it internally for
    exclusive use.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/memory/omap-gpmc.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 4dd1c65..784a64f 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1911,6 +1911,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	const char *name;
 	int ret, cs;
 	u32 val;
+	struct gpio_desc *waitpin_desc = NULL;
+	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
 
 	if (of_property_read_u32(child, "reg", &cs) < 0) {
 		dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -2020,16 +2022,30 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 			goto err;
 	}
 
+	/* Reserve wait pin if it is required and valid */
+	if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
+		unsigned int wait_pin = gpmc_s.wait_pin;
+
+		waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
+							 wait_pin, "WAITPIN");
+		if (IS_ERR(waitpin_desc)) {
+			dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
+			ret = PTR_ERR(waitpin_desc);
+			goto err;
+		}
+	}
+
 	gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
+
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
-		goto err;
+		goto err_cs;
 
 	ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
 			child->name);
-		goto err;
+		goto err_cs;
 	}
 
 	/* Clear limited address i.e. enable A26-A11 */
@@ -2060,6 +2076,10 @@ err_child_fail:
 	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
 	ret = -ENODEV;
 
+err_cs:
+	if (waitpin_desc)
+		gpiochip_free_own_desc(waitpin_desc);
+
 err:
 	gpmc_cs_free(cs);
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: memory: omap-gpmc: Support WAIT pin edge interrupts
Message-ID: <E1b54Qq-0000US-6y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=b2bac25a4d298309bb4b2649bb1107ddaa287c47
Commit:     b2bac25a4d298309bb4b2649bb1107ddaa287c47
Parent:     210325f0f4eb531f83ffb0b0f95612e2a8063983
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Fri Feb 19 11:01:02 2016 +0200
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:55:06 2016 +0300

    memory: omap-gpmc: Support WAIT pin edge interrupts
    
    OMAPs can have 2 to 4 WAITPINs that can be used as edge triggered
    interrupts if not used for memory wait state insertion.
    
    Support these interrupts via the gpmc IRQ domain.
    
    The gpmc IRQ domain interrupt map is:
    
    0 - NAND_fifoevent
    1 - NAND_termcount
    2 - GPMC_WAIT0 edge
    3 - GPMC_WAIT1 edge, and so on
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 .../bindings/memory-controllers/omap-gpmc.txt      |   5 +-
 drivers/memory/omap-gpmc.c                         | 106 +++++++++++++++++----
 2 files changed, 92 insertions(+), 19 deletions(-)

diff --git a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
index 97e7192..21055e2 100644
--- a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
@@ -33,10 +33,13 @@ Required properties:
 			As this will change in the future, filling correct
 			values here is a requirement.
  - interrupt-controller: The GPMC driver implements and interrupt controller for
-			the NAND events "fifoevent" and "termcount".
+			the NAND events "fifoevent" and "termcount" plus the
+			rising/falling edges on the GPMC_WAIT pins.
 			The interrupt number mapping is as follows
 			0 - NAND_fifoevent
 			1 - NAND_termcount
+			2 - GPMC_WAIT0 pin edge
+			3 - GPMC_WAIT1 pin edge, and so on.
  - interrupt-cells:	Must be set to 2
  - gpio-controller:	The GPMC driver implements a GPIO controller for the
 			GPMC WAIT pins that can be used as general purpose inputs.
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 784a64f..ea9c897 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -189,9 +189,7 @@
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
 #define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
 
-/* XXX: Only NAND irq has been considered,currently these are the only ones used
- */
-#define	GPMC_NR_IRQ		2
+#define	GPMC_NR_NAND_IRQS	2 /* number of NAND specific IRQs */
 
 enum gpmc_clk_domain {
 	GPMC_CD_FCLK,
@@ -239,6 +237,7 @@ struct gpmc_device {
 	int irq;
 	struct irq_chip irq_chip;
 	struct gpio_chip gpio_chip;
+	int nirqs;
 };
 
 static struct irq_domain *gpmc_irq_domain;
@@ -1155,7 +1154,8 @@ int gpmc_get_client_irq(unsigned irq_config)
 		return 0;
 	}
 
-	if (irq_config >= GPMC_NR_IRQ)
+	/* we restrict this to NAND IRQs only */
+	if (irq_config >= GPMC_NR_NAND_IRQS)
 		return 0;
 
 	return irq_create_mapping(gpmc_irq_domain, irq_config);
@@ -1165,6 +1165,10 @@ static int gpmc_irq_endis(unsigned long hwirq, bool endis)
 {
 	u32 regval;
 
+	/* bits GPMC_NR_NAND_IRQS to 8 are reserved */
+	if (hwirq >= GPMC_NR_NAND_IRQS)
+		hwirq += 8 - GPMC_NR_NAND_IRQS;
+
 	regval = gpmc_read_reg(GPMC_IRQENABLE);
 	if (endis)
 		regval |= BIT(hwirq);
@@ -1185,9 +1189,64 @@ static void gpmc_irq_enable(struct irq_data *p)
 	gpmc_irq_endis(p->hwirq, true);
 }
 
-static void gpmc_irq_noop(struct irq_data *data) { }
+static void gpmc_irq_mask(struct irq_data *d)
+{
+	gpmc_irq_endis(d->hwirq, false);
+}
+
+static void gpmc_irq_unmask(struct irq_data *d)
+{
+	gpmc_irq_endis(d->hwirq, true);
+}
+
+static void gpmc_irq_edge_config(unsigned long hwirq, bool rising_edge)
+{
+	u32 regval;
+
+	/* NAND IRQs polarity is not configurable */
+	if (hwirq < GPMC_NR_NAND_IRQS)
+		return;
+
+	/* WAITPIN starts at BIT 8 */
+	hwirq += 8 - GPMC_NR_NAND_IRQS;
+
+	regval = gpmc_read_reg(GPMC_CONFIG);
+	if (rising_edge)
+		regval &= ~BIT(hwirq);
+	else
+		regval |= BIT(hwirq);
+
+	gpmc_write_reg(GPMC_CONFIG, regval);
+}
+
+static void gpmc_irq_ack(struct irq_data *d)
+{
+	unsigned int hwirq = d->hwirq;
+
+	/* skip reserved bits */
+	if (hwirq >= GPMC_NR_NAND_IRQS)
+		hwirq += 8 - GPMC_NR_NAND_IRQS;
+
+	/* Setting bit to 1 clears (or Acks) the interrupt */
+	gpmc_write_reg(GPMC_IRQSTATUS, BIT(hwirq));
+}
+
+static int gpmc_irq_set_type(struct irq_data *d, unsigned int trigger)
+{
+	/* can't set type for NAND IRQs */
+	if (d->hwirq < GPMC_NR_NAND_IRQS)
+		return -EINVAL;
+
+	/* We can support either rising or falling edge at a time */
+	if (trigger == IRQ_TYPE_EDGE_FALLING)
+		gpmc_irq_edge_config(d->hwirq, false);
+	else if (trigger == IRQ_TYPE_EDGE_RISING)
+		gpmc_irq_edge_config(d->hwirq, true);
+	else
+		return -EINVAL;
 
-static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
+	return 0;
+}
 
 static int gpmc_irq_map(struct irq_domain *d, unsigned int virq,
 			irq_hw_number_t hw)
@@ -1195,8 +1254,14 @@ static int gpmc_irq_map(struct irq_domain *d, unsigned int virq,
 	struct gpmc_device *gpmc = d->host_data;
 
 	irq_set_chip_data(virq, gpmc);
-	irq_set_chip_and_handler(virq, &gpmc->irq_chip, handle_simple_irq);
-	irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
+	if (hw < GPMC_NR_NAND_IRQS) {
+		irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
+		irq_set_chip_and_handler(virq, &gpmc->irq_chip,
+					 handle_simple_irq);
+	} else {
+		irq_set_chip_and_handler(virq, &gpmc->irq_chip,
+					 handle_edge_irq);
+	}
 
 	return 0;
 }
@@ -1209,16 +1274,21 @@ static const struct irq_domain_ops gpmc_irq_domain_ops = {
 static irqreturn_t gpmc_handle_irq(int irq, void *data)
 {
 	int hwirq, virq;
-	u32 regval;
+	u32 regval, regvalx;
 	struct gpmc_device *gpmc = data;
 
 	regval = gpmc_read_reg(GPMC_IRQSTATUS);
+	regvalx = regval;
 
 	if (!regval)
 		return IRQ_NONE;
 
-	for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++) {
-		if (regval & BIT(hwirq)) {
+	for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++) {
+		/* skip reserved status bits */
+		if (hwirq == GPMC_NR_NAND_IRQS)
+			regvalx >>= 8 - GPMC_NR_NAND_IRQS;
+
+		if (regvalx & BIT(hwirq)) {
 			virq = irq_find_mapping(gpmc_irq_domain, hwirq);
 			if (!virq) {
 				dev_warn(gpmc->dev,
@@ -1248,16 +1318,15 @@ static int gpmc_setup_irq(struct gpmc_device *gpmc)
 	gpmc_write_reg(GPMC_IRQSTATUS, regval);
 
 	gpmc->irq_chip.name = "gpmc";
-	gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret;
 	gpmc->irq_chip.irq_enable = gpmc_irq_enable;
 	gpmc->irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc->irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc->irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc->irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc->irq_chip.irq_unmask = gpmc_irq_noop;
+	gpmc->irq_chip.irq_ack = gpmc_irq_ack;
+	gpmc->irq_chip.irq_mask = gpmc_irq_mask;
+	gpmc->irq_chip.irq_unmask = gpmc_irq_unmask;
+	gpmc->irq_chip.irq_set_type = gpmc_irq_set_type;
 
 	gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node,
-						GPMC_NR_IRQ,
+						gpmc->nirqs,
 						&gpmc_irq_domain_ops,
 						gpmc);
 	if (!gpmc_irq_domain) {
@@ -1282,7 +1351,7 @@ static int gpmc_free_irq(struct gpmc_device *gpmc)
 
 	free_irq(gpmc->irq, gpmc);
 
-	for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++)
+	for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++)
 		irq_dispose_mapping(irq_find_mapping(gpmc_irq_domain, hwirq));
 
 	irq_domain_remove(gpmc_irq_domain);
@@ -2296,6 +2365,7 @@ static int gpmc_probe(struct platform_device *pdev)
 	if (rc)
 		goto gpio_init_failed;
 
+	gpmc->nirqs = GPMC_NR_NAND_IRQS + gpmc_nr_waitpins;
 	rc = gpmc_setup_irq(gpmc);
 	if (rc) {
 		dev_err(gpmc->dev, "gpmc_setup_irq failed\n");


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via
 gpmc_regs
Message-ID: <E1b54Qq-0000Us-A1@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=9e6946215dbd9803e8b511928c9f61f3a49e2c58
Commit:     9e6946215dbd9803e8b511928c9f61f3a49e2c58
Parent:     b2bac25a4d298309bb4b2649bb1107ddaa287c47
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Fri Aug 7 10:38:13 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:55:28 2016 +0300

    memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs
    
    GPMC_STATUS register is private to the GPMC module and must not be
    accessed directly by NAND driver through the gpmc_regs.
    
    They must use gpmc_omap_get_nand_ops() instead.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 drivers/memory/omap-gpmc.c                   | 2 +-
 include/linux/platform_data/mtd-nand-omap2.h | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index ea9c897..33d69b1 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1081,7 +1081,7 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 {
 	int i;
 
-	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_status = NULL;	/* deprecated */
 	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index ff27e5a..7f6de53 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -45,7 +45,6 @@ enum omap_ecc {
 };
 
 struct gpmc_nand_regs {
-	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_nand_command;
 	void __iomem	*gpmc_nand_address;
 	void __iomem	*gpmc_nand_data;
@@ -64,6 +63,8 @@ struct gpmc_nand_regs {
 	void __iomem	*gpmc_bch_result4[GPMC_BCH_NUM_REMAINDER];
 	void __iomem	*gpmc_bch_result5[GPMC_BCH_NUM_REMAINDER];
 	void __iomem	*gpmc_bch_result6[GPMC_BCH_NUM_REMAINDER];
+	/* Deprecated. Do not use */
+	void __iomem	*gpmc_status;
 };
 
 struct omap_nand_platform_data {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: mtd: nand: omap2: Implement NAND ready using gpiolib
Message-ID: <E1b54Qq-0000VH-E6@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=10f22ee367c4aff7841da6a83c10445d7d6328d9
Commit:     10f22ee367c4aff7841da6a83c10445d7d6328d9
Parent:     9e6946215dbd9803e8b511928c9f61f3a49e2c58
Author:     Roger Quadros <rogerq at ti.com>
AuthorDate: Thu Aug 6 17:39:35 2015 +0300
Committer:  Roger Quadros <rogerq at ti.com>
CommitDate: Fri Apr 15 11:55:37 2016 +0300

    mtd: nand: omap2: Implement NAND ready using gpiolib
    
    The GPMC WAIT pin status are now available over gpiolib.
    Update the omap_dev_ready() function to use gpio instead of
    directly accessing GPMC register space.
    
    Signed-off-by: Roger Quadros <rogerq at ti.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Tony Lindgren <tony at atomide.com>
---
 .../devicetree/bindings/mtd/gpmc-nand.txt          |  2 ++
 drivers/mtd/nand/omap2.c                           | 29 ++++++++++++++--------
 include/linux/platform_data/mtd-nand-omap2.h       |  2 +-
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index ff3215d2..3ee7e20 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -48,6 +48,7 @@ Optional properties:
 		locating ECC errors for BCHx algorithms. SoC devices which have
 		ELM hardware engines should specify this device node in .dtsi
 		Using ELM for ECC error correction frees some CPU cycles.
+ - rb-gpios:	GPIO specifier for the ready/busy# pin.
 
 For inline partition table parsing (optional):
 
@@ -78,6 +79,7 @@ Example for an AM33xx board:
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";
+			rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */
 
 			gpmc,sync-clk-ps = <0>;
 			gpmc,cs-on-ns = <0>;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 35b8f33..e0b2b2f 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -12,6 +12,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
@@ -182,6 +183,8 @@ struct omap_nand_info {
 	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
 	struct device			*elm_dev;
+	/* NAND ready gpio */
+	struct gpio_desc		*ready_gpiod;
 };
 
 static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@@ -1023,21 +1026,16 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
- * omap_dev_ready - calls the platform specific dev_ready function
+ * omap_dev_ready - checks the NAND Ready GPIO line
  * @mtd: MTD device structure
+ *
+ * Returns true if ready and false if busy.
  */
 static int omap_dev_ready(struct mtd_info *mtd)
 {
-	unsigned int val = 0;
 	struct omap_nand_info *info = mtd_to_omap(mtd);
 
-	val = readl(info->reg.gpmc_status);
-
-	if ((val & 0x100) == 0x100) {
-		return 1;
-	} else {
-		return 0;
-	}
+	return gpiod_get_value(info->ready_gpiod);
 }
 
 /**
@@ -1755,7 +1753,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->gpmc_cs = pdata->cs;
 		info->reg = pdata->reg;
 		info->ecc_opt = pdata->ecc_opt;
-		info->dev_ready	= pdata->dev_ready;
+		if (pdata->dev_ready)
+			dev_info(&pdev->dev, "pdata->dev_ready is deprecated\n");
+
 		info->xfer_type = pdata->xfer_type;
 		info->devsize = pdata->devsize;
 		info->elm_of_node = pdata->elm_of_node;
@@ -1787,6 +1787,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
 	nand_chip->cmd_ctrl  = omap_hwcontrol;
 
+	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
+						    GPIOD_IN);
+	if (IS_ERR(info->ready_gpiod)) {
+		dev_err(dev, "failed to get ready gpio\n");
+		return PTR_ERR(info->ready_gpiod);
+	}
+
 	/*
 	 * If RDY/BSY line is connected to OMAP then use the omap ready
 	 * function and the generic nand_wait function which reads the status
@@ -1794,7 +1801,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (info->dev_ready) {
+	if (info->ready_gpiod) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 7f6de53..17d57a1 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -71,7 +71,6 @@ struct omap_nand_platform_data {
 	int			cs;
 	struct mtd_partition	*parts;
 	int			nr_parts;
-	bool			dev_ready;
 	bool			flash_bbt;
 	enum nand_io		xfer_type;
 	int			devsize;
@@ -82,5 +81,6 @@ struct omap_nand_platform_data {
 	/* deprecated */
 	struct gpmc_nand_regs	reg;
 	struct device_node	*of_node;
+	bool			dev_ready;
 };
 #endif


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: mtd: nand: add new enum for storing ECC algorithm
Message-ID: <E1b54Qq-0000Vi-LN@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=b0fcd8ab7b3c89b5da7fff5224d06ed73e7a33cc
Commit:     b0fcd8ab7b3c89b5da7fff5224d06ed73e7a33cc
Parent:     8de53481b433e45638e8e5252cbfeb78d64ca4d9
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Mar 23 11:19:00 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:02:32 2016 +0200

    mtd: nand: add new enum for storing ECC algorithm
    
    Our nand_ecc_modes_t is already a bit abused by value NAND_ECC_SOFT_BCH.
    This enum should store ECC mode only and putting algorithm details there
    is a bad idea. It would result in too many values impossible to support
    in a sane way.
    
    To solve this problem let's add a new enum. We'll have to modify all
    drivers to set it properly but once it's done it'll be possible to drop
    NAND_ECC_SOFT_BCH. That will result in a cleaner design and more
    possibilities like setting ECC algorithm for hardware ECC mode.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 include/linux/mtd/nand.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 56574ba..1b673e1 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -119,6 +119,12 @@ typedef enum {
 	NAND_ECC_SOFT_BCH,
 } nand_ecc_modes_t;
 
+enum nand_ecc_algo {
+	NAND_ECC_UNKNOWN,
+	NAND_ECC_HAMMING,
+	NAND_ECC_BCH,
+};
+
 /*
  * Constants for Hardware ECC
  */
@@ -458,6 +464,7 @@ struct nand_hw_control {
 /**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:	ECC mode
+ * @algo:	ECC algorithm
  * @steps:	number of ECC steps per page
  * @size:	data bytes per ECC step
  * @bytes:	ECC bytes per step
@@ -508,6 +515,7 @@ struct nand_hw_control {
  */
 struct nand_ecc_ctrl {
 	nand_ecc_modes_t mode;
+	enum nand_ecc_algo algo;
 	int steps;
 	int size;
 	int bytes;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: of: mtd: prepare helper reading NAND ECC algo from DT
Message-ID: <E1b54Qq-0000WD-PS@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=dd2dcc004230b9d8fa809102cd326e3ee4bbdb2a
Commit:     dd2dcc004230b9d8fa809102cd326e3ee4bbdb2a
Parent:     b0fcd8ab7b3c89b5da7fff5224d06ed73e7a33cc
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Mar 23 11:19:01 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:48 2016 +0200

    of: mtd: prepare helper reading NAND ECC algo from DT
    
    NAND subsystem is being slightly reworked to store ECC details in
    separated fields. In future we'll want to add support for more DT
    properties as specifying every possible setup with a single
    "nand-ecc-mode" is a pretty bad idea.
    To allow this let's add a helper that will support something like
    "nand-ecc-algo" in future. Right now we use it for keeping backward
    compatibility.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/of/of_mtd.c    | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/of_mtd.h |  6 ++++++
 2 files changed, 42 insertions(+)

diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
index b7361ed..15d056e 100644
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -50,6 +50,42 @@ int of_get_nand_ecc_mode(struct device_node *np)
 EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
 
 /**
+ * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
+ * @np:	Pointer to the given device_node
+ *
+ * The function gets ecc algorithm and returns its enum value, or errno in error
+ * case.
+ */
+int of_get_nand_ecc_algo(struct device_node *np)
+{
+	const char *pm;
+	int err;
+
+	/*
+	 * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
+	 * It's not implemented yet as currently NAND subsystem ignores
+	 * algorithm explicitly set this way. Once it's handled we should
+	 * document & support new property.
+	 */
+
+	/*
+	 * For backward compatibility we also read "nand-ecc-mode" checking
+	 * for some obsoleted values that were specifying ECC algorithm.
+	 */
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	if (!strcasecmp(pm, "soft"))
+		return NAND_ECC_HAMMING;
+	else if (!strcasecmp(pm, "soft_bch"))
+		return NAND_ECC_BCH;
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
+
+/**
  * of_get_nand_ecc_step_size - Get ECC step size associated to
  * the required ECC strength (see below).
  * @np:	Pointer to the given device_node
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
index e266caa..0f6aca5 100644
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -13,6 +13,7 @@
 
 #include <linux/of.h>
 int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_ecc_algo(struct device_node *np);
 int of_get_nand_ecc_step_size(struct device_node *np);
 int of_get_nand_ecc_strength(struct device_node *np);
 int of_get_nand_bus_width(struct device_node *np);
@@ -25,6 +26,11 @@ static inline int of_get_nand_ecc_mode(struct device_node *np)
 	return -ENOSYS;
 }
 
+static inline int of_get_nand_ecc_algo(struct device_node *np)
+{
+	return -ENOSYS;
+}
+
 static inline int of_get_nand_ecc_step_size(struct device_node *np)
 {
 	return -ENOSYS;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:04 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:04 +0000
Subject: mtd: nand: set ECC algorithm in nand_dt_init
Message-ID: <E1b54Qq-0000Wh-TU@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=79082457d71af879922e15f9dedf85384e84c29f
Commit:     79082457d71af879922e15f9dedf85384e84c29f
Parent:     dd2dcc004230b9d8fa809102cd326e3ee4bbdb2a
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Mar 23 11:19:02 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:49 2016 +0200

    mtd: nand: set ECC algorithm in nand_dt_init
    
    Use recently added of_get_nand_ecc_algo for that.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8d6287e..728543b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3954,7 +3954,7 @@ ident_done:
 static int nand_dt_init(struct nand_chip *chip)
 {
 	struct device_node *dn = nand_get_flash_node(chip);
-	int ecc_mode, ecc_strength, ecc_step;
+	int ecc_mode, ecc_algo, ecc_strength, ecc_step;
 
 	if (!dn)
 		return 0;
@@ -3966,6 +3966,7 @@ static int nand_dt_init(struct nand_chip *chip)
 		chip->bbt_options |= NAND_BBT_USE_FLASH;
 
 	ecc_mode = of_get_nand_ecc_mode(dn);
+	ecc_algo = of_get_nand_ecc_algo(dn);
 	ecc_strength = of_get_nand_ecc_strength(dn);
 	ecc_step = of_get_nand_ecc_step_size(dn);
 
@@ -3978,6 +3979,9 @@ static int nand_dt_init(struct nand_chip *chip)
 	if (ecc_mode >= 0)
 		chip->ecc.mode = ecc_mode;
 
+	if (ecc_algo >= 0)
+		chip->ecc.algo = ecc_algo;
+
 	if (ecc_strength >= 0)
 		chip->ecc.strength = ecc_strength;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: nand: nandsim: set ECC algorithm explicitly
Message-ID: <E1b54Qr-0000X9-3B@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=8ae6bcd1dcea249591b4165bd7f795c4868bc531
Commit:     8ae6bcd1dcea249591b4165bd7f795c4868bc531
Parent:     79082457d71af879922e15f9dedf85384e84c29f
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Mar 23 11:19:03 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:49 2016 +0200

    mtd: nand: nandsim: set ECC algorithm explicitly
    
    This follows recent work on switching to enum nand_ecc_algo and
    deprecating NAND_ECC_SOFT_BCH.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nandsim.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 1fd5195..6ff1d8d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2261,6 +2261,7 @@ static int __init ns_init_module(void)
 	chip->read_buf   = ns_nand_read_buf;
 	chip->read_word  = ns_nand_read_word;
 	chip->ecc.mode   = NAND_ECC_SOFT;
+	chip->ecc.algo   = NAND_ECC_HAMMING;
 	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
 	/* and 'badblocks' parameters to work */
 	chip->options   |= NAND_SKIP_BBTSCAN;
@@ -2339,6 +2340,7 @@ static int __init ns_init_module(void)
 			goto error;
 		}
 		chip->ecc.mode = NAND_ECC_SOFT_BCH;
+		chip->ecc.algo = NAND_ECC_BCH;
 		chip->ecc.size = 512;
 		chip->ecc.strength = bch;
 		chip->ecc.bytes = eccbytes;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: nand: atmel: correct bitflips in erased pages for pre-sama5d4
 SoCs
Message-ID: <E1b54Qr-0000XY-6b@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ff6ee101584c17c4f30ca48d75e2910c49d0b0ff
Commit:     ff6ee101584c17c4f30ca48d75e2910c49d0b0ff
Parent:     8ae6bcd1dcea249591b4165bd7f795c4868bc531
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Tue Mar 1 14:11:52 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:50 2016 +0200

    mtd: nand: atmel: correct bitflips in erased pages for pre-sama5d4 SoCs
    
    New atmel SoCs are able to fix bitflips in erased pages, but old ones
    are still impacted by this problem. Use nand_check_erased_ecc_chunk() to
    handle this case.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Reported-by: Herve Codina <herve.CODINA at celad.com>
    Reviewed-by: Herve Codina <herve.CODINA at celad.com>
    Tested-by: Herve Codina <herve.CODINA at celad.com>
---
 drivers/mtd/nand/atmel_nand.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 20cbaab..0b5da72 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -863,17 +863,6 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
 	uint8_t *buf_pos;
 	int max_bitflips = 0;
 
-	/* If can correct bitfilps from erased page, do the normal check */
-	if (host->caps->pmecc_correct_erase_page)
-		goto normal_check;
-
-	for (i = 0; i < nand_chip->ecc.total; i++)
-		if (ecc[i] != 0xff)
-			goto normal_check;
-	/* Erased page, return OK */
-	return 0;
-
-normal_check:
 	for (i = 0; i < nand_chip->ecc.steps; i++) {
 		err_nbr = 0;
 		if (pmecc_stat & 0x1) {
@@ -884,16 +873,30 @@ normal_check:
 			pmecc_get_sigma(mtd);
 
 			err_nbr = pmecc_err_location(mtd);
-			if (err_nbr == -1) {
+			if (err_nbr >= 0) {
+				pmecc_correct_data(mtd, buf_pos, ecc, i,
+						   nand_chip->ecc.bytes,
+						   err_nbr);
+			} else if (!host->caps->pmecc_correct_erase_page) {
+				u8 *ecc_pos = ecc + (i * nand_chip->ecc.bytes);
+
+				/* Try to detect erased pages */
+				err_nbr = nand_check_erased_ecc_chunk(buf_pos,
+							host->pmecc_sector_size,
+							ecc_pos,
+							nand_chip->ecc.bytes,
+							NULL, 0,
+							nand_chip->ecc.strength);
+			}
+
+			if (err_nbr < 0) {
 				dev_err(host->dev, "PMECC: Too many errors\n");
 				mtd->ecc_stats.failed++;
 				return -EIO;
-			} else {
-				pmecc_correct_data(mtd, buf_pos, ecc, i,
-					nand_chip->ecc.bytes, err_nbr);
-				mtd->ecc_stats.corrected += err_nbr;
-				max_bitflips = max_t(int, max_bitflips, err_nbr);
 			}
+
+			mtd->ecc_stats.corrected += err_nbr;
+			max_bitflips = max_t(int, max_bitflips, err_nbr);
 		}
 		pmecc_stat >>= 1;
 	}


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: nand: jz4780: fixup, device structure assigned at probe
Message-ID: <E1b54Qr-0000Y1-B2@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ce8716e97149d15379603890c4c7a2acfcf4a7ee
Commit:     ce8716e97149d15379603890c4c7a2acfcf4a7ee
Parent:     ff6ee101584c17c4f30ca48d75e2910c49d0b0ff
Author:     Jorge Ramirez-Ortiz <jorge.ramirez-ortiz at linaro.org>
AuthorDate: Wed Mar 23 21:53:27 2016 -0400
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:50 2016 +0200

    mtd: nand: jz4780: fixup, device structure assigned at probe
    
    bch->dev is already assigned to &pdev->dev in the probe function.
    Remove the duplicate assignment done in jz4780_bch_get().
    
    Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz at linaro.org>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Acked-by: Harvey Hunt <harvey.hunt at imgtec.com>
---
 drivers/mtd/nand/jz4780_bch.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/jz4780_bch.c
index 755499c..d74f4ba 100644
--- a/drivers/mtd/nand/jz4780_bch.c
+++ b/drivers/mtd/nand/jz4780_bch.c
@@ -287,7 +287,6 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
 	bch = platform_get_drvdata(pdev);
 	clk_prepare_enable(bch->clk);
 
-	bch->dev = &pdev->dev;
 	return bch;
 }
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: nand: document the NAND controller/NAND chip DT representation
Message-ID: <E1b54Qr-0000YX-E3@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2d472aba15ff169a30dc3661f837d8535af9b9ee
Commit:     2d472aba15ff169a30dc3661f837d8535af9b9ee
Parent:     ce8716e97149d15379603890c4c7a2acfcf4a7ee
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:26:35 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:51 2016 +0200

    mtd: nand: document the NAND controller/NAND chip DT representation
    
    Standardize the NAND controller/NAND chip DT representation. Now, all new
    NAND controller drivers should comply with this representation, even if
    they are only supporting a single NAND chip.
    
    Existing drivers can keep support for the old representation (where only
    the NAND chip was described), but are encouraged to also support the new
    one.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Rob Herring <robh at kernel.org>
---
 Documentation/devicetree/bindings/mtd/nand.txt | 37 +++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index b53f92e..a17662b 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -1,4 +1,23 @@
-* MTD generic binding
+* NAND chip and NAND controller generic binding
+
+NAND controller/NAND chip representation:
+
+The NAND controller should be represented with its own DT node, and all
+NAND chips attached to this controller should be defined as children nodes
+of the NAND controller. This representation should be enforced even for
+simple controllers supporting only one chip.
+
+Mandatory NAND controller properties:
+- #address-cells: depends on your controller. Should at least be 1 to
+		  encode the CS line id.
+- #size-cells: depends on your controller. Put zero unless you need a
+	       mapping between CS lines and dedicated memory regions
+
+Optional NAND controller properties
+- ranges: only needed if you need to define a mapping between CS lines and
+	  memory regions
+
+Optional NAND chip properties:
 
 - nand-ecc-mode : String, operation mode of the NAND ecc mode.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
@@ -19,3 +38,19 @@ errors per {size} bytes".
 The interpretation of these parameters is implementation-defined, so not all
 implementations must support all possible combinations. However, implementations
 are encouraged to further specify the value(s) they support.
+
+Example:
+
+	nand-controller {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* controller specific properties */
+
+		nand at 0 {
+			reg = <0>;
+			nand-ecc-mode = "soft_bch";
+
+			/* controller specific properties */
+		};
+	};


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: brcmnand: Add support for v6.2 controllers
Message-ID: <E1b54Qr-0000Z3-L2@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=269ecf03a5b32b0d1de1f60a4b86b75c0521053f
Commit:     269ecf03a5b32b0d1de1f60a4b86b75c0521053f
Parent:     2d472aba15ff169a30dc3661f837d8535af9b9ee
Author:     Florian Fainelli <f.fainelli at gmail.com>
AuthorDate: Thu Mar 10 15:34:16 2016 -0800
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:51 2016 +0200

    mtd: brcmnand: Add support for v6.2 controllers
    
    Document and match the brcm,brcmnand-v6.2 compatible string, the controller has
    a register layout identical to the v6.0 version and supports prefetch. Update the
    command shift logic to account for v6.2 controller which are the first ones to
    use a shift of 0 (6.1 used a shift of 24).
    
    Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
    Signed-off-by: Florian Fainelli <f.fainelli at gmail.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt | 1 +
 drivers/mtd/nand/brcmnand/brcmnand.c                    | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
index c2546ce..deb24cb 100644
--- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
+++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
@@ -24,6 +24,7 @@ Required properties:
                          brcm,brcmnand-v5.0
                          brcm,brcmnand-v6.0
                          brcm,brcmnand-v6.1
+                         brcm,brcmnand-v6.2
                          brcm,brcmnand-v7.0
                          brcm,brcmnand-v7.1
                          brcm,brcmnand
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index e052839..0b7a698 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -601,7 +601,7 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
 
 static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
 {
-	if (ctrl->nand_version < 0x0700)
+	if (ctrl->nand_version < 0x0602)
 		return 24;
 	return 0;
 }
@@ -2115,6 +2115,7 @@ static const struct of_device_id brcmnand_of_match[] = {
 	{ .compatible = "brcm,brcmnand-v5.0" },
 	{ .compatible = "brcm,brcmnand-v6.0" },
 	{ .compatible = "brcm,brcmnand-v6.1" },
+	{ .compatible = "brcm,brcmnand-v6.2" },
 	{ .compatible = "brcm,brcmnand-v7.0" },
 	{ .compatible = "brcm,brcmnand-v7.1" },
 	{},


From linux-mtd at lists.infradead.org  Mon May 23 21:59:05 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:05 +0000
Subject: mtd: gpmi: fix raw_buffer pointer double free issue
Message-ID: <E1b54Qr-0000ZS-PM@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2cd395d13a104cd96ddae5c5612871dc18553cca
Commit:     2cd395d13a104cd96ddae5c5612871dc18553cca
Parent:     269ecf03a5b32b0d1de1f60a4b86b75c0521053f
Author:     Han Xu <han.xu at nxp.com>
AuthorDate: Mon Apr 4 15:41:29 2016 -0500
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:52 2016 +0200

    mtd: gpmi: fix raw_buffer pointer double free issue
    
    fix the raw_buffer pointer double free issue found by coverify.
    
    CID 18344 (#2 of 2): Double free (USE_AFTER_FREE)
    3. double_free: Calling gpmi_alloc_dma_buffer frees pointer
    this->raw_buffer which has already been freed
    
    Signed-off-by: Han Xu <han.xu at nxp.com>
    Reviewed-by: Richard Weinberger <richard at nod.at>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 8122c69..dcb60b0 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -797,6 +797,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
 
 	this->cmd_buffer	= NULL;
 	this->data_buffer_dma	= NULL;
+	this->raw_buffer	= NULL;
 	this->page_buffer_virt	= NULL;
 	this->page_buffer_size	=  0;
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: Remove BUG() abuse in nand_scan_tail
Message-ID: <E1b54Qr-0000Zt-Tf@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=11eaf6df1cce3c5e9f51b422aaedc42dc4aa1d37
Commit:     11eaf6df1cce3c5e9f51b422aaedc42dc4aa1d37
Parent:     2cd395d13a104cd96ddae5c5612871dc18553cca
Author:     Ezequiel Garc?a <ezequiel at vanguardiasur.com.ar>
AuthorDate: Fri Apr 1 18:29:24 2016 -0300
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:52 2016 +0200

    mtd: nand: Remove BUG() abuse in nand_scan_tail
    
    There's no reason to BUG() when parameters are being
    validated. Drivers can get things wrong, and it's much nicer
    to just throw a noisy warn and fail gracefully, than calling
    BUG() and throwing the whole system down the drain.
    
    Signed-off-by: Ezequiel Garcia <ezequiel at vanguardiasur.com.ar>
    Reviewed-by: Richard Weinberger <richard at nod.at>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 52 ++++++++++++++++++++++++++++----------------
 1 file changed, 33 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 728543b..0f0c5b1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4107,10 +4107,12 @@ int nand_scan_tail(struct mtd_info *mtd)
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct nand_buffers *nbuf;
+	int ret;
 
 	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
-	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
-			!(chip->bbt_options & NAND_BBT_USE_FLASH));
+	if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+		   !(chip->bbt_options & NAND_BBT_USE_FLASH)))
+		return -EINVAL;
 
 	if (!(chip->options & NAND_OWN_BUFFERS)) {
 		nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
@@ -4148,9 +4150,10 @@ int nand_scan_tail(struct mtd_info *mtd)
 			ecc->layout = &nand_oob_128;
 			break;
 		default:
-			pr_warn("No oob scheme defined for oobsize %d\n",
-				   mtd->oobsize);
-			BUG();
+			WARN(1, "No oob scheme defined for oobsize %d\n",
+				mtd->oobsize);
+			ret = -EINVAL;
+			goto err_free;
 		}
 	}
 
@@ -4166,8 +4169,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 	case NAND_ECC_HW_OOB_FIRST:
 		/* Similar to NAND_ECC_HW, but a separate read_page handle */
 		if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
-			pr_warn("No ECC functions supplied; hardware ECC not possible\n");
-			BUG();
+			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+			ret = -EINVAL;
+			goto err_free;
 		}
 		if (!ecc->read_page)
 			ecc->read_page = nand_read_page_hwecc_oob_first;
@@ -4197,8 +4201,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 		     ecc->read_page == nand_read_page_hwecc ||
 		     !ecc->write_page ||
 		     ecc->write_page == nand_write_page_hwecc)) {
-			pr_warn("No ECC functions supplied; hardware ECC not possible\n");
-			BUG();
+			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+			ret = -EINVAL;
+			goto err_free;
 		}
 		/* Use standard syndrome read/write page function? */
 		if (!ecc->read_page)
@@ -4216,8 +4221,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 
 		if (mtd->writesize >= ecc->size) {
 			if (!ecc->strength) {
-				pr_warn("Driver must set ecc.strength when using hardware ECC\n");
-				BUG();
+				WARN(1, "Driver must set ecc.strength when using hardware ECC\n");
+				ret = -EINVAL;
+				goto err_free;
 			}
 			break;
 		}
@@ -4243,8 +4249,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 
 	case NAND_ECC_SOFT_BCH:
 		if (!mtd_nand_has_bch()) {
-			pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");
-			BUG();
+			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+			ret = -EINVAL;
+			goto err_free;
 		}
 		ecc->calculate = nand_bch_calculate_ecc;
 		ecc->correct = nand_bch_correct_data;
@@ -4269,8 +4276,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 		ecc->bytes = 0;
 		ecc->priv = nand_bch_init(mtd);
 		if (!ecc->priv) {
-			pr_warn("BCH ECC initialization failed!\n");
-			BUG();
+			WARN(1, "BCH ECC initialization failed!\n");
+			ret = -EINVAL;
+			goto err_free;
 		}
 		break;
 
@@ -4288,8 +4296,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 		break;
 
 	default:
-		pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);
-		BUG();
+		WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
+		ret = -EINVAL;
+		goto err_free;
 	}
 
 	/* For many systems, the standard OOB write also works for raw */
@@ -4319,8 +4328,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 	 */
 	ecc->steps = mtd->writesize / ecc->size;
 	if (ecc->steps * ecc->size != mtd->writesize) {
-		pr_warn("Invalid ECC parameters\n");
-		BUG();
+		WARN(1, "Invalid ECC parameters\n");
+		ret = -EINVAL;
+		goto err_free;
 	}
 	ecc->total = ecc->steps * ecc->bytes;
 
@@ -4398,6 +4408,10 @@ int nand_scan_tail(struct mtd_info *mtd)
 
 	/* Build bad block table */
 	return chip->scan_bbt(mtd);
+err_free:
+	if (!(chip->options & NAND_OWN_BUFFERS))
+		kfree(chip->buffers);
+	return ret;
 }
 EXPORT_SYMBOL(nand_scan_tail);
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd/ifc: Add support for IFC controller version 2.0
Message-ID: <E1b54Qs-0000aO-3M@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=7a654172161c8c9c7d59cbd0054d9e63c7411219
Commit:     7a654172161c8c9c7d59cbd0054d9e63c7411219
Parent:     11eaf6df1cce3c5e9f51b422aaedc42dc4aa1d37
Author:     Raghav Dogra <raghav.dogra at nxp.com>
AuthorDate: Wed Feb 17 16:54:18 2016 +0530
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:53 2016 +0200

    mtd/ifc: Add support for IFC controller version 2.0
    
    The new IFC controller version 2.0 has a different memory map page.
    Upto IFC 1.4 PAGE size is 4 KB and from IFC2.0 PAGE size is 64KB.
    This patch segregates the IFC global and runtime registers to appropriate
    PAGE sizes.
    
    Signed-off-by: Jaiprakash Singh <b44839 at freescale.com>
    Signed-off-by: Raghav Dogra <raghav at freescale.com>
    Acked-by: Li Yang <leoyang.li at nxp.com>
    Signed-off-by: Raghav Dogra <raghav.dogra at nxp.com>
    Acked-by: Scott Wood <oss at buserror.net>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/memory/fsl_ifc.c        | 36 ++++++++++-----------
 drivers/mtd/nand/fsl_ifc_nand.c | 72 ++++++++++++++++++++++-------------------
 include/linux/fsl_ifc.h         | 45 +++++++++++++++++---------
 3 files changed, 87 insertions(+), 66 deletions(-)

diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index 2a691da..904b4af 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -59,11 +59,11 @@ int fsl_ifc_find(phys_addr_t addr_base)
 {
 	int i = 0;
 
-	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs)
 		return -ENODEV;
 
 	for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
-		u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
+		u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
 		if (cspr & CSPR_V && (cspr & CSPR_BA) ==
 				convert_ifc_address(addr_base))
 			return i;
@@ -75,7 +75,7 @@ EXPORT_SYMBOL(fsl_ifc_find);
 
 static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
 {
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
 
 	/*
 	 * Clear all the common status and event registers
@@ -104,7 +104,7 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev)
 	irq_dispose_mapping(ctrl->nand_irq);
 	irq_dispose_mapping(ctrl->irq);
 
-	iounmap(ctrl->regs);
+	iounmap(ctrl->gregs);
 
 	dev_set_drvdata(&dev->dev, NULL);
 	kfree(ctrl);
@@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(nand_irq_lock);
 
 static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
 {
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 	unsigned long flags;
 	u32 stat;
 
@@ -157,7 +157,7 @@ static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
 static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
 {
 	struct fsl_ifc_ctrl *ctrl = data;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
 	u32 err_axiid, err_srcid, status, cs_err, err_addr;
 	irqreturn_t ret = IRQ_NONE;
 
@@ -215,6 +215,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 {
 	int ret = 0;
 	int version, banks;
+	void __iomem *addr;
 
 	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
 
@@ -225,22 +226,13 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 	dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
 
 	/* IOMAP the entire IFC region */
-	fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
-	if (!fsl_ifc_ctrl_dev->regs) {
+	fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
+	if (!fsl_ifc_ctrl_dev->gregs) {
 		dev_err(&dev->dev, "failed to get memory region\n");
 		ret = -ENODEV;
 		goto err;
 	}
 
-	version = ifc_in32(&fsl_ifc_ctrl_dev->regs->ifc_rev) &
-			FSL_IFC_VERSION_MASK;
-	banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
-	dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
-		version >> 24, (version >> 16) & 0xf, banks);
-
-	fsl_ifc_ctrl_dev->version = version;
-	fsl_ifc_ctrl_dev->banks = banks;
-
 	if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
 		fsl_ifc_ctrl_dev->little_endian = true;
 		dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
@@ -249,8 +241,9 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 		dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
 	}
 
-	version = ioread32be(&fsl_ifc_ctrl_dev->regs->ifc_rev) &
+	version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
 			FSL_IFC_VERSION_MASK;
+
 	banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
 	dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
 		version >> 24, (version >> 16) & 0xf, banks);
@@ -258,6 +251,13 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 	fsl_ifc_ctrl_dev->version = version;
 	fsl_ifc_ctrl_dev->banks = banks;
 
+	addr = fsl_ifc_ctrl_dev->gregs;
+	if (version >= FSL_IFC_VERSION_2_0_0)
+		addr += PGOFFSET_64K;
+	else
+		addr += PGOFFSET_4K;
+	fsl_ifc_ctrl_dev->rregs = addr;
+
 	/* get the Controller level irq */
 	fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
 	if (fsl_ifc_ctrl_dev->irq == 0) {
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 43f5a3a..f8a016f 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -232,7 +232,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 	int buf_num;
 
 	ifc_nand_ctrl->page = page_addr;
@@ -295,7 +295,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
 	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 	u32 eccstat[4];
 	int i;
 
@@ -371,7 +371,7 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
 {
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 
 	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
 	if (mtd->writesize > 512) {
@@ -411,7 +411,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 
 	/* clear the read buffer */
 	ifc_nand_ctrl->read_bytes = 0;
@@ -723,7 +723,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 	u32 nand_fsr;
 
 	/* Use READ_STATUS command, but wait for the device to be ready */
@@ -825,39 +825,42 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
 static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 {
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
+	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
 	uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
 	uint32_t cs = priv->bank;
 
 	/* Save CSOR and CSOR_ext */
-	csor = ifc_in32(&ifc->csor_cs[cs].csor);
-	csor_ext = ifc_in32(&ifc->csor_cs[cs].csor_ext);
+	csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
+	csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
 
 	/* chage PageSize 8K and SpareSize 1K*/
 	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
-	ifc_out32(csor_8k, &ifc->csor_cs[cs].csor);
-	ifc_out32(0x0000400, &ifc->csor_cs[cs].csor_ext);
+	ifc_out32(csor_8k, &ifc_global->csor_cs[cs].csor);
+	ifc_out32(0x0000400, &ifc_global->csor_cs[cs].csor_ext);
 
 	/* READID */
 	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-		  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-		  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
-		  &ifc->ifc_nand.nand_fir0);
+		    (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+		    (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
+		    &ifc_runtime->ifc_nand.nand_fir0);
 	ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
-		  &ifc->ifc_nand.nand_fcr0);
-	ifc_out32(0x0, &ifc->ifc_nand.row3);
+		    &ifc_runtime->ifc_nand.nand_fcr0);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.row3);
 
-	ifc_out32(0x0, &ifc->ifc_nand.nand_fbcr);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.nand_fbcr);
 
 	/* Program ROW0/COL0 */
-	ifc_out32(0x0, &ifc->ifc_nand.row0);
-	ifc_out32(0x0, &ifc->ifc_nand.col0);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.row0);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.col0);
 
 	/* set the chip select for NAND Transaction */
-	ifc_out32(cs << IFC_NAND_CSEL_SHIFT, &ifc->ifc_nand.nand_csel);
+	ifc_out32(cs << IFC_NAND_CSEL_SHIFT,
+		&ifc_runtime->ifc_nand.nand_csel);
 
 	/* start read seq */
-	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
+	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT,
+		&ifc_runtime->ifc_nand.nandseq_strt);
 
 	/* wait for command complete flag or timeout */
 	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
@@ -867,14 +870,15 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 		printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
 
 	/* Restore CSOR and CSOR_ext */
-	ifc_out32(csor, &ifc->csor_cs[cs].csor);
-	ifc_out32(csor_ext, &ifc->csor_cs[cs].csor_ext);
+	ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
+	ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
 }
 
 static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 {
 	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
+	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
 	struct nand_chip *chip = &priv->chip;
 	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
 	struct nand_ecclayout *layout;
@@ -886,7 +890,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
 	/* fill in nand_chip structure */
 	/* set up function call table */
-	if ((ifc_in32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+	if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
+		& CSPR_PORT_SIZE_16)
 		chip->read_byte = fsl_ifc_read_byte16;
 	else
 		chip->read_byte = fsl_ifc_read_byte;
@@ -900,13 +905,14 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	chip->bbt_td = &bbt_main_descr;
 	chip->bbt_md = &bbt_mirror_descr;
 
-	ifc_out32(0x0, &ifc->ifc_nand.ncfgr);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.ncfgr);
 
 	/* set up nand options */
 	chip->bbt_options = NAND_BBT_USE_FLASH;
 	chip->options = NAND_NO_SUBPAGE_WRITE;
 
-	if (ifc_in32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+	if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
+		& CSPR_PORT_SIZE_16) {
 		chip->read_byte = fsl_ifc_read_byte16;
 		chip->options |= NAND_BUSWIDTH_16;
 	} else {
@@ -919,7 +925,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	chip->ecc.read_page = fsl_ifc_read_page;
 	chip->ecc.write_page = fsl_ifc_write_page;
 
-	csor = ifc_in32(&ifc->csor_cs[priv->bank].csor);
+	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
 
 	/* Hardware generates ECC per 512 Bytes */
 	chip->ecc.size = 512;
@@ -1007,10 +1013,10 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 	return 0;
 }
 
-static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
+static int match_bank(struct fsl_ifc_global __iomem *ifc_global, int bank,
 		      phys_addr_t addr)
 {
-	u32 cspr = ifc_in32(&ifc->cspr_cs[bank].cspr);
+	u32 cspr = ifc_in32(&ifc_global->cspr_cs[bank].cspr);
 
 	if (!(cspr & CSPR_V))
 		return 0;
@@ -1024,7 +1030,7 @@ static DEFINE_MUTEX(fsl_ifc_nand_mutex);
 
 static int fsl_ifc_nand_probe(struct platform_device *dev)
 {
-	struct fsl_ifc_regs __iomem *ifc;
+	struct fsl_ifc_runtime __iomem *ifc;
 	struct fsl_ifc_mtd *priv;
 	struct resource res;
 	static const char *part_probe_types[]
@@ -1034,9 +1040,9 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
 	struct device_node *node = dev->dev.of_node;
 	struct mtd_info *mtd;
 
-	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->rregs)
 		return -ENODEV;
-	ifc = fsl_ifc_ctrl_dev->regs;
+	ifc = fsl_ifc_ctrl_dev->rregs;
 
 	/* get, allocate and map the memory resource */
 	ret = of_address_to_resource(node, 0, &res);
@@ -1047,7 +1053,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
 
 	/* find which chip select it is connected to */
 	for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
-		if (match_bank(ifc, bank, res.start))
+		if (match_bank(fsl_ifc_ctrl_dev->gregs, bank, res.start))
 			break;
 	}
 
diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h
index 0023088..3f9778c 100644
--- a/include/linux/fsl_ifc.h
+++ b/include/linux/fsl_ifc.h
@@ -39,6 +39,10 @@
 #define FSL_IFC_VERSION_MASK	0x0F0F0000
 #define FSL_IFC_VERSION_1_0_0	0x01000000
 #define FSL_IFC_VERSION_1_1_0	0x01010000
+#define FSL_IFC_VERSION_2_0_0	0x02000000
+
+#define PGOFFSET_64K	(64*1024)
+#define PGOFFSET_4K	(4*1024)
 
 /*
  * CSPR - Chip Select Property Register
@@ -723,20 +727,26 @@ struct fsl_ifc_nand {
 	__be32 nand_evter_en;
 	u32 res17[0x2];
 	__be32 nand_evter_intr_en;
-	u32 res18[0x2];
+	__be32 nand_vol_addr_stat;
+	u32 res18;
 	__be32 nand_erattr0;
 	__be32 nand_erattr1;
 	u32 res19[0x10];
 	__be32 nand_fsr;
-	u32 res20;
-	__be32 nand_eccstat[4];
-	u32 res21[0x20];
+	u32 res20[0x3];
+	__be32 nand_eccstat[6];
+	u32 res21[0x1c];
 	__be32 nanndcr;
 	u32 res22[0x2];
 	__be32 nand_autoboot_trgr;
 	u32 res23;
 	__be32 nand_mdr;
-	u32 res24[0x5C];
+	u32 res24[0x1C];
+	__be32 nand_dll_lowcfg0;
+	__be32 nand_dll_lowcfg1;
+	u32 res25;
+	__be32 nand_dll_lowstat;
+	u32 res26[0x3c];
 };
 
 /*
@@ -771,13 +781,12 @@ struct fsl_ifc_gpcm {
 	__be32 gpcm_erattr1;
 	__be32 gpcm_erattr2;
 	__be32 gpcm_stat;
-	u32 res4[0x1F3];
 };
 
 /*
  * IFC Controller Registers
  */
-struct fsl_ifc_regs {
+struct fsl_ifc_global {
 	__be32 ifc_rev;
 	u32 res1[0x2];
 	struct {
@@ -803,21 +812,26 @@ struct fsl_ifc_regs {
 	} ftim_cs[FSL_IFC_BANK_COUNT];
 	u32 res9[0x30];
 	__be32 rb_stat;
-	u32 res10[0x2];
+	__be32 rb_map;
+	__be32 wb_map;
 	__be32 ifc_gcr;
-	u32 res11[0x2];
+	u32 res10[0x2];
 	__be32 cm_evter_stat;
-	u32 res12[0x2];
+	u32 res11[0x2];
 	__be32 cm_evter_en;
-	u32 res13[0x2];
+	u32 res12[0x2];
 	__be32 cm_evter_intr_en;
-	u32 res14[0x2];
+	u32 res13[0x2];
 	__be32 cm_erattr0;
 	__be32 cm_erattr1;
-	u32 res15[0x2];
+	u32 res14[0x2];
 	__be32 ifc_ccr;
 	__be32 ifc_csr;
-	u32 res16[0x2EB];
+	__be32 ddr_ccr_low;
+};
+
+
+struct fsl_ifc_runtime {
 	struct fsl_ifc_nand ifc_nand;
 	struct fsl_ifc_nor ifc_nor;
 	struct fsl_ifc_gpcm ifc_gpcm;
@@ -831,7 +845,8 @@ extern int fsl_ifc_find(phys_addr_t addr_base);
 struct fsl_ifc_ctrl {
 	/* device info */
 	struct device			*dev;
-	struct fsl_ifc_regs __iomem	*regs;
+	struct fsl_ifc_global __iomem	*gregs;
+	struct fsl_ifc_runtime __iomem	*rregs;
 	int				irq;
 	int				nand_irq;
 	spinlock_t			lock;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: s3c2410: fix bug in s3c2410_nand_correct_data()
Message-ID: <E1b54Qs-0000ar-8T@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=03a97550941d17c7d5b621afde5945bbc0da6546
Commit:     03a97550941d17c7d5b621afde5945bbc0da6546
Parent:     7a654172161c8c9c7d59cbd0054d9e63c7411219
Author:     Zhaoxiu Zeng <zhaoxiu.zeng at gmail.com>
AuthorDate: Tue Apr 12 15:30:35 2016 +0800
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:53 2016 +0200

    mtd: nand: s3c2410: fix bug in s3c2410_nand_correct_data()
    
    If there is only one bit difference in the ECC, the function should
    return 1.
    The result of "diff0 & ~(1<<fls(diff0))" is equal to diff0, so the
    function actually returns -1.
    
    Signed-off-by: Zhaoxiu Zeng <zhaoxiu.zeng at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/s3c2410.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 9c9397b..86ffb73 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -542,7 +542,8 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 	diff0 |= (diff1 << 8);
 	diff0 |= (diff2 << 16);
 
-	if ((diff0 & ~(1<<fls(diff0))) == 0)
+	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
+	if ((diff0 & (diff0 - 1)) == 0)
 		return 1;
 
 	return -1;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: remove unneeded of_mtd.h inclusions
Message-ID: <E1b54Qs-0000bI-Bb@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=24d990e237d1822fb108ed9be41d1542af001185
Commit:     24d990e237d1822fb108ed9be41d1542af001185
Parent:     03a97550941d17c7d5b621afde5945bbc0da6546
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:21 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:53 2016 +0200

    mtd: nand: remove unneeded of_mtd.h inclusions
    
    Some drivers are including linux/of_mtd.h even if they don't use any of
    the of_get_nand_xxx() helpers.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Harvey Hunt <harvey.hunt at imgtec.com>
---
 drivers/mtd/nand/jz4780_nand.c | 1 -
 drivers/mtd/nand/lpc32xx_mlc.c | 1 -
 drivers/mtd/nand/qcom_nandc.c  | 1 -
 drivers/mtd/nand/sunxi_nand.c  | 1 -
 drivers/mtd/nand/vf610_nfc.c   | 1 -
 5 files changed, 5 deletions(-)

diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
index e1c016c..23a1999 100644
--- a/drivers/mtd/nand/jz4780_nand.c
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -17,7 +17,6 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/gpio/consumer.h>
-#include <linux/of_mtd.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index d8c3e7a..8e43978 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -35,7 +35,6 @@
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
-#include <linux/of_mtd.h>
 #include <linux/of_gpio.h>
 #include <linux/mtd/lpc32xx_mlc.h>
 #include <linux/io.h>
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index f550a57..f3de983 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -21,7 +21,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 #include <linux/delay.h>
 
 /* NANDc reg offsets */
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 1c03eee..3a97093 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -30,7 +30,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
-#include <linux/of_mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 293feb1..a7f2756 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -33,7 +33,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
-#include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: omap2: rely on generic DT parsing done in nand_scan_ident()
Message-ID: <E1b54Qs-0000bk-Hl@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f679888f29fe5c4a4c44459f2c1fc62b72188773
Commit:     f679888f29fe5c4a4c44459f2c1fc62b72188773
Parent:     24d990e237d1822fb108ed9be41d1542af001185
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Tue Apr 19 20:29:58 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:04:54 2016 +0200

    mtd: nand: omap2: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Roger Quadros <rogerq at ti.com>
    Tested-by: Franklin S Cooper Jr. <fcooper at ti.com>
---
 drivers/memory/omap-gpmc.c |  4 ++--
 drivers/mtd/nand/omap2.c   | 18 +++++++-----------
 2 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 33d69b1..af4884b 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -27,7 +27,6 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/omap-gpmc.h>
@@ -2066,7 +2065,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 	if (of_device_is_compatible(child, "ti,omap2-nand")) {
 		/* NAND specific setup */
-		val = of_get_nand_bus_width(child);
+		val = 8;
+		of_property_read_u32(child, "nand-bus-width", &val);
 		switch (val) {
 		case 8:
 			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index e0b2b2f..c59bc85 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -1701,7 +1700,7 @@ static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
 		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
 			if (!strcasecmp(s, nand_xfer_types[i])) {
 				info->xfer_type = i;
-				goto next;
+				return 0;
 			}
 		}
 
@@ -1709,12 +1708,6 @@ static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
 		return -EINVAL;
 	}
 
-next:
-	of_get_nand_on_flash_bbt(child);
-
-	if (of_get_nand_bus_width(child) == 16)
-		info->devsize = NAND_BUSWIDTH_16;
-
 	return 0;
 }
 
@@ -1810,9 +1803,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	if (info->flash_bbt)
-		nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-	else
-		nand_chip->options |= NAND_SKIP_BBTSCAN;
+		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
 
 	/* scan NAND device connected to chip controller */
 	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
@@ -1823,6 +1814,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
+	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
+		nand_chip->bbt_options |= NAND_BBT_NO_OOB;
+	else
+		nand_chip->options |= NAND_SKIP_BBTSCAN;
+
 	/* re-populate low-level callbacks based on xfer modes */
 	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: brcm: rely on generic DT parsing done in nand_scan_ident()
Message-ID: <E1b54Qs-0000cG-Mr@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=541e3c8912fe4257ba0b71908ea8fbf79143f510
Commit:     541e3c8912fe4257ba0b71908ea8fbf79143f510
Parent:     f679888f29fe5c4a4c44459f2c1fc62b72188773
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:24 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:30 2016 +0200

    mtd: nand: brcm: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/nand/brcmnand/brcmnand.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 0b7a698..e5f281f 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -32,7 +32,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
-#include <linux/of_mtd.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 #include <linux/list.h>
@@ -2001,8 +2000,8 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
 	 */
 	chip->options |= NAND_USE_BOUNCE_BUFFER;
 
-	if (of_get_nand_on_flash_bbt(dn))
-		chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->bbt_options |= NAND_BBT_NO_OOB;
 
 	if (brcmnand_setup_dev(host))
 		return -ENXIO;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: ams-delta: set ECC algorithm explicitly
Message-ID: <E1b54Qs-0000ci-QF@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e58dd3c33d3046c3ad3c849cb95365b45b9ecb5f
Commit:     e58dd3c33d3046c3ad3c849cb95365b45b9ecb5f
Parent:     541e3c8912fe4257ba0b71908ea8fbf79143f510
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:44 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:31 2016 +0200

    mtd: nand: ams-delta: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/ams-delta.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 68b58c8..78e12cc 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -224,6 +224,7 @@ static int ams_delta_init(struct platform_device *pdev)
 	/* 25 us command delay time */
 	this->chip_delay = 30;
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	platform_set_drvdata(pdev, io_base);
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: nuc900: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000e3-7Z@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=37afb2034f17c5f17423bfe5a4fc100d6803b554
Commit:     37afb2034f17c5f17423bfe5a4fc100d6803b554
Parent:     c1c7040e072caac6445a1e298bd1fc5e8da0a5f5
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:47 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:32 2016 +0200

    mtd: nand: nuc900: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nuc900_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
index dbc5b57..8f64011 100644
--- a/drivers/mtd/nand/nuc900_nand.c
+++ b/drivers/mtd/nand/nuc900_nand.c
@@ -261,6 +261,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
 	chip->chip_delay	= 50;
 	chip->options		= 0;
 	chip->ecc.mode		= NAND_ECC_SOFT;
+	chip->ecc.algo		= NAND_ECC_HAMMING;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: orion: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000eZ-CV@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ac7efcbe0e3d64565f5b086d231589e3637e9b0b
Commit:     ac7efcbe0e3d64565f5b086d231589e3637e9b0b
Parent:     37afb2034f17c5f17423bfe5a4fc100d6803b554
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:48 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:33 2016 +0200

    mtd: nand: orion: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/orion_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index d4614bf..40a7c4a 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -130,6 +130,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 	nc->cmd_ctrl = orion_nand_cmd_ctrl;
 	nc->read_buf = orion_nand_read_buf;
 	nc->ecc.mode = NAND_ECC_SOFT;
+	nc->ecc.algo = NAND_ECC_HAMMING;
 
 	if (board->chip_delay)
 		nc->chip_delay = board->chip_delay;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: pasemi: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000ez-Gd@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=a9670a9c7ff9488d66d6fd7593415bb978017509
Commit:     a9670a9c7ff9488d66d6fd7593415bb978017509
Parent:     ac7efcbe0e3d64565f5b086d231589e3637e9b0b
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:49 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:34 2016 +0200

    mtd: nand: pasemi: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/pasemi_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 3ab53ca..63fcb8c 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -151,6 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 	chip->write_buf = pasemi_write_buf;
 	chip->chip_delay = 0;
 	chip->ecc.mode = NAND_ECC_SOFT;
+	chip->ecc.algo = NAND_ECC_HAMMING;
 
 	/* Enable the following for a flash based bad block table */
 	chip->bbt_options = NAND_BBT_USE_FLASH;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: plat: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000fQ-MA@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=41ccb49e9123e268e8f84d019893cacd6a312c69
Commit:     41ccb49e9123e268e8f84d019893cacd6a312c69
Parent:     a9670a9c7ff9488d66d6fd7593415bb978017509
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:50 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:34 2016 +0200

    mtd: nand: plat: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/plat_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index e4e50da..415a53a 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -74,6 +74,7 @@ static int plat_nand_probe(struct platform_device *pdev)
 
 	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
 	data->chip.ecc.mode = NAND_ECC_SOFT;
+	data->chip.ecc.algo = NAND_ECC_HAMMING;
 
 	platform_set_drvdata(pdev, data);
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: socrates: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000fs-Q4@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ce111afd01bce7c137c92e9ed0dbe294a0f2373a
Commit:     ce111afd01bce7c137c92e9ed0dbe294a0f2373a
Parent:     41ccb49e9123e268e8f84d019893cacd6a312c69
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:51 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:35 2016 +0200

    mtd: nand: socrates: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/socrates_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index e3305f9..888fd31 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -180,6 +180,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
 	nand_chip->dev_ready = socrates_nand_device_ready;
 
 	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
+	nand_chip->ecc.algo = NAND_ECC_HAMMING;
 
 	/* TODO: I have no idea what real delay is. */
 	nand_chip->chip_delay = 20;		/* 20us command delay time */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: pasemi: switch to dev_* printing functions
Message-ID: <E1b54Qu-0000gN-04@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ff05fdb187cc25bff3e7ee9f79d94077c8d16a44
Commit:     ff05fdb187cc25bff3e7ee9f79d94077c8d16a44
Parent:     ce111afd01bce7c137c92e9ed0dbe294a0f2373a
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 11:48:05 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:35 2016 +0200

    mtd: nand: pasemi: switch to dev_* printing functions
    
    It also contains some minor related changes:
    1) Don't warn if kzalloc fails as it dumps stack on its own
    2) Use %pR format for displaying whole resource to avoid invalid format
       warning
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/pasemi_nand.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 63fcb8c..5de7591 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -92,8 +92,9 @@ int pasemi_device_ready(struct mtd_info *mtd)
 
 static int pasemi_nand_probe(struct platform_device *ofdev)
 {
+	struct device *dev = &ofdev->dev;
 	struct pci_dev *pdev;
-	struct device_node *np = ofdev->dev.of_node;
+	struct device_node *np = dev->of_node;
 	struct resource res;
 	struct nand_chip *chip;
 	int err = 0;
@@ -107,13 +108,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 	if (pasemi_nand_mtd)
 		return -ENODEV;
 
-	pr_debug("pasemi_nand at %pR\n", &res);
+	dev_dbg(dev, "pasemi_nand at %pR\n", &res);
 
 	/* Allocate memory for MTD device structure and private data */
 	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 	if (!chip) {
-		printk(KERN_WARNING
-		       "Unable to allocate PASEMI NAND MTD device structure\n");
 		err = -ENOMEM;
 		goto out;
 	}
@@ -121,7 +120,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 	pasemi_nand_mtd = nand_to_mtd(chip);
 
 	/* Link the private data with the MTD structure */
-	pasemi_nand_mtd->dev.parent = &ofdev->dev;
+	pasemi_nand_mtd->dev.parent = dev;
 
 	chip->IO_ADDR_R = of_iomap(np, 0);
 	chip->IO_ADDR_W = chip->IO_ADDR_R;
@@ -163,13 +162,13 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 	}
 
 	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
-		printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n");
+		dev_err(dev, "Unable to register MTD device\n");
 		err = -ENODEV;
 		goto out_lpc;
 	}
 
-	printk(KERN_INFO "PA Semi NAND flash at %08llx, control at I/O %x\n",
-	       res.start, lpcctl);
+	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
+		 lpcctl);
 
 	return 0;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: atmel: rely on generic DT parsing done in nand_scan_ident()
Message-ID: <E1b54Qu-0000gr-40@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=4f3cab9b4457108a8241ec7a66e03fe0b2cb3646
Commit:     4f3cab9b4457108a8241ec7a66e03fe0b2cb3646
Parent:     ff05fdb187cc25bff3e7ee9f79d94077c8d16a44
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:22 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:36 2016 +0200

    mtd: nand: atmel: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Tested-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Reviewed-by: Nicolas Ferre <nicolas.ferre at atmel.com>
---
 drivers/mtd/nand/atmel_nand.c | 133 +++++++++++++++++++++++-------------------
 1 file changed, 73 insertions(+), 60 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 0b5da72..5e716f2 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -36,7 +36,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
-#include <linux/of_mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -434,14 +433,13 @@ err_buf:
 static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand_host *host = nand_get_controller_data(chip);
 
 	if (use_dma && len > mtd->oobsize)
 		/* only use DMA for bigger than oob size: better performances */
 		if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
 			return;
 
-	if (host->board.bus_width_16)
+	if (chip->options & NAND_BUSWIDTH_16)
 		atmel_read_buf16(mtd, buf, len);
 	else
 		atmel_read_buf8(mtd, buf, len);
@@ -450,14 +448,13 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand_host *host = nand_get_controller_data(chip);
 
 	if (use_dma && len > mtd->oobsize)
 		/* only use DMA for bigger than oob size: better performances */
 		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
 			return;
 
-	if (host->board.bus_width_16)
+	if (chip->options & NAND_BUSWIDTH_16)
 		atmel_write_buf16(mtd, buf, len);
 	else
 		atmel_write_buf8(mtd, buf, len);
@@ -1507,58 +1504,17 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 		ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
 }
 
-static int atmel_of_init_port(struct atmel_nand_host *host,
-			      struct device_node *np)
+static int atmel_of_init_ecc(struct atmel_nand_host *host,
+			     struct device_node *np)
 {
-	u32 val;
 	u32 offset[2];
-	int ecc_mode;
-	struct atmel_nand_data *board = &host->board;
-	enum of_gpio_flags flags = 0;
-
-	host->caps = (struct atmel_nand_caps *)
-		of_device_get_match_data(host->dev);
-
-	if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
-		if (val >= 32) {
-			dev_err(host->dev, "invalid addr-offset %u\n", val);
-			return -EINVAL;
-		}
-		board->ale = val;
-	}
-
-	if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
-		if (val >= 32) {
-			dev_err(host->dev, "invalid cmd-offset %u\n", val);
-			return -EINVAL;
-		}
-		board->cle = val;
-	}
-
-	ecc_mode = of_get_nand_ecc_mode(np);
-
-	board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode;
-
-	board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
-
-	board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
-
-	if (of_get_nand_bus_width(np) == 16)
-		board->bus_width_16 = 1;
-
-	board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
-	board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
-
-	board->enable_pin = of_get_gpio(np, 1);
-	board->det_pin = of_get_gpio(np, 2);
+	u32 val;
 
 	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 
-	/* load the nfc driver if there is */
-	of_platform_populate(np, NULL, NULL, host->dev);
-
-	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
-		return 0;	/* Not using PMECC */
+	/* Not using PMECC */
+	if (!(host->nand_chip.ecc.mode == NAND_ECC_HW) || !host->has_pmecc)
+		return 0;
 
 	/* use PMECC, get correction capability, sector size and lookup
 	 * table offset.
@@ -1599,16 +1555,64 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 		/* Will build a lookup table and initialize the offset later */
 		return 0;
 	}
+
 	if (!offset[0] && !offset[1]) {
 		dev_err(host->dev, "Invalid PMECC lookup table offset\n");
 		return -EINVAL;
 	}
+
 	host->pmecc_lookup_table_offset_512 = offset[0];
 	host->pmecc_lookup_table_offset_1024 = offset[1];
 
 	return 0;
 }
 
+static int atmel_of_init_port(struct atmel_nand_host *host,
+			      struct device_node *np)
+{
+	u32 val;
+	struct atmel_nand_data *board = &host->board;
+	enum of_gpio_flags flags = 0;
+
+	host->caps = (struct atmel_nand_caps *)
+		of_device_get_match_data(host->dev);
+
+	if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
+		if (val >= 32) {
+			dev_err(host->dev, "invalid addr-offset %u\n", val);
+			return -EINVAL;
+		}
+		board->ale = val;
+	}
+
+	if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
+		if (val >= 32) {
+			dev_err(host->dev, "invalid cmd-offset %u\n", val);
+			return -EINVAL;
+		}
+		board->cle = val;
+	}
+
+	board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
+
+	board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
+	board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
+
+	board->enable_pin = of_get_gpio(np, 1);
+	board->det_pin = of_get_gpio(np, 2);
+
+	/* load the nfc driver if there is */
+	of_platform_populate(np, NULL, NULL, host->dev);
+
+	/*
+	 * Initialize ECC mode to NAND_ECC_SOFT so that we have a correct value
+	 * even if the nand-ecc-mode property is not defined.
+	 */
+	host->nand_chip.ecc.mode = NAND_ECC_SOFT;
+
+	return 0;
+}
+
 static int atmel_hw_nand_init_params(struct platform_device *pdev,
 					 struct atmel_nand_host *host)
 {
@@ -2150,6 +2154,11 @@ static int atmel_nand_probe(struct platform_device *pdev)
 	} else {
 		memcpy(&host->board, dev_get_platdata(&pdev->dev),
 		       sizeof(struct atmel_nand_data));
+		nand_chip->ecc.mode = host->board.ecc_mode;
+
+		/* 16-bit bus width */
+		if (host->board.bus_width_16)
+			nand_chip->options |= NAND_BUSWIDTH_16;
 	}
 
 	 /* link the private data structures */
@@ -2191,11 +2200,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
 		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 
-	nand_chip->ecc.mode = host->board.ecc_mode;
 	nand_chip->chip_delay = 40;		/* 40us command delay time */
 
-	if (host->board.bus_width_16)	/* 16-bit bus width */
-		nand_chip->options |= NAND_BUSWIDTH_16;
 
 	nand_chip->read_buf = atmel_read_buf;
 	nand_chip->write_buf = atmel_write_buf;
@@ -2228,11 +2234,6 @@ static int atmel_nand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (host->board.on_flash_bbt || on_flash_bbt) {
-		dev_info(&pdev->dev, "Use On Flash BBT\n");
-		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
-	}
-
 	if (!host->board.has_dma)
 		use_dma = 0;
 
@@ -2259,6 +2260,18 @@ static int atmel_nand_probe(struct platform_device *pdev)
 		goto err_scan_ident;
 	}
 
+	if (host->board.on_flash_bbt || on_flash_bbt)
+		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
+		dev_info(&pdev->dev, "Use On Flash BBT\n");
+
+	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+		res = atmel_of_init_ecc(host, pdev->dev.of_node);
+		if (res)
+			goto err_hw_ecc;
+	}
+
 	if (nand_chip->ecc.mode == NAND_ECC_HW) {
 		if (host->has_pmecc)
 			res = atmel_pmecc_nand_init_params(pdev, host);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: pxa3xx: rely on generic DT parsing done in
 nand_scan_ident()
Message-ID: <E1b54Qu-0000hJ-9z@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=44ccb64fa56ad6d6d2d33a8625d9464f54c63eba
Commit:     44ccb64fa56ad6d6d2d33a8625d9464f54c63eba
Parent:     4f3cab9b4457108a8241ec7a66e03fe0b2cb3646
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:30 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:36 2016 +0200

    mtd: nand: pxa3xx: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Ezequiel Garcia <ezequiel at vanguardiasur.com.ar>
---
 drivers/mtd/nand/pxa3xx_nand.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index d650885..38d26ab 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
 #define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
@@ -1651,6 +1650,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
 		nand_writel(info, NDECCCTRL, 0x0);
 
+	if (pdata->flash_bbt)
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	chip->ecc.strength = pdata->ecc_strength;
+	chip->ecc.size = pdata->ecc_step_size;
+
 	if (nand_scan_ident(mtd, 1, NULL))
 		return -ENODEV;
 
@@ -1663,13 +1668,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 		}
 	}
 
-	if (pdata->flash_bbt) {
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
 		/*
 		 * 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_options |= NAND_BBT_NO_OOB_BBM;
 		chip->bbt_td = &bbt_main_descr;
 		chip->bbt_md = &bbt_mirror_descr;
 	}
@@ -1689,10 +1693,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 		}
 	}
 
-	if (pdata->ecc_strength && pdata->ecc_step_size) {
-		ecc_strength = pdata->ecc_strength;
-		ecc_step = pdata->ecc_step_size;
-	} else {
+	ecc_strength = chip->ecc.strength;
+	ecc_step = chip->ecc.size;
+	if (!ecc_strength || !ecc_step) {
 		ecc_strength = chip->ecc_strength_ds;
 		ecc_step = chip->ecc_step_ds;
 	}
@@ -1903,15 +1906,6 @@ 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);
-
-	pdata->ecc_strength = of_get_nand_ecc_strength(np);
-	if (pdata->ecc_strength < 0)
-		pdata->ecc_strength = 0;
-
-	pdata->ecc_step_size = of_get_nand_ecc_step_size(np);
-	if (pdata->ecc_step_size < 0)
-		pdata->ecc_step_size = 0;
 
 	pdev->dev.platform_data = pdata;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: sunxi: fix call order in sunxi_nand_chip_init()
Message-ID: <E1b54Qu-0000hl-Ec@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=9edb47004e2afb5884d0c900cbd1ece8b2d6f403
Commit:     9edb47004e2afb5884d0c900cbd1ece8b2d6f403
Parent:     44ccb64fa56ad6d6d2d33a8625d9464f54c63eba
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Dec 2 16:00:57 2015 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:36 2016 +0200

    mtd: nand: sunxi: fix call order in sunxi_nand_chip_init()
    
    sunxi_nand_chip_set_timings() is extracting a pointer to the nfc from the
    nand->controller field, but this field is initialized after
    sunxi_nand_chip_set_timings() call.
    Reorder the calls to avoid any problem.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 3a97093..546a9ca 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1535,21 +1535,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 		}
 	}
 
-	timings = onfi_async_timing_mode_to_sdr_timings(0);
-	if (IS_ERR(timings)) {
-		ret = PTR_ERR(timings);
-		dev_err(dev,
-			"could not retrieve timings for ONFI mode 0: %d\n",
-			ret);
-		return ret;
-	}
-
-	ret = sunxi_nand_chip_set_timings(chip, timings);
-	if (ret) {
-		dev_err(dev, "could not configure chip timings: %d\n", ret);
-		return ret;
-	}
-
 	nand = &chip->nand;
 	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
 	nand->chip_delay = 200;
@@ -1569,6 +1554,21 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	mtd = nand_to_mtd(nand);
 	mtd->dev.parent = dev;
 
+	timings = onfi_async_timing_mode_to_sdr_timings(0);
+	if (IS_ERR(timings)) {
+		ret = PTR_ERR(timings);
+		dev_err(dev,
+			"could not retrieve timings for ONFI mode 0: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = sunxi_nand_chip_set_timings(chip, timings);
+	if (ret) {
+		dev_err(dev, "could not configure chip timings: %d\n", ret);
+		return ret;
+	}
+
 	ret = nand_scan_ident(mtd, nsels, NULL);
 	if (ret)
 		return ret;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: sunxi: fix clk rate calculation
Message-ID: <E1b54Qu-0000iI-JX@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2f9992e080b8892a10d189cbc846c06e6594ad0b
Commit:     2f9992e080b8892a10d189cbc846c06e6594ad0b
Parent:     9edb47004e2afb5884d0c900cbd1ece8b2d6f403
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Dec 2 15:10:40 2015 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:37 2016 +0200

    mtd: nand: sunxi: fix clk rate calculation
    
    Unlike what is specified in the Allwinner datasheets, the NAND clock rate
    is not equal to 2/T but 1/T. Fix the clock rate selection accordingly.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 546a9ca..05b3303 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1208,12 +1208,12 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
 	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
 
 	/*
-	 * Convert min_clk_period into a clk frequency, then get the
-	 * appropriate rate for the NAND controller IP given this formula
-	 * (specified in the datasheet):
-	 * nand clk_rate = 2 * min_clk_rate
+	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
+	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
+	 * This new formula was verified with a scope and validated by
+	 * Allwinner engineers.
 	 */
-	chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period;
+	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
 
 	return 0;
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:08 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:08 +0000
Subject: mtd: nand: sunxi: fix EDO mode selection
Message-ID: <E1b54Qu-0000ij-Of@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2d43457f79e48ee427666fdbfe9a53f35d3a1672
Commit:     2d43457f79e48ee427666fdbfe9a53f35d3a1672
Parent:     2f9992e080b8892a10d189cbc846c06e6594ad0b
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Dec 2 15:57:20 2015 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:37 2016 +0200

    mtd: nand: sunxi: fix EDO mode selection
    
    The ONFI spec says that EDO should be enabled if the host drives tRC less
    than 30ns, but the code just tests for the tRC_min value extracted from
    the timings exposed by the NAND chip not the timings actually configured
    in the NAND controller.
    Fix that by first rounding down the requested clk_rate with
    clk_round_rate() and then checking if tRC is actually smaller than 30ns.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 05b3303..b906fc5 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1100,6 +1100,7 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
 	struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
 	u32 min_clk_period = 0;
 	s32 tWB, tADL, tWHR, tRHW, tCAD;
+	long real_clk_rate;
 
 	/* T1 <=> tCLS */
 	if (timings->tCLS_min > min_clk_period)
@@ -1197,13 +1198,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
 	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
 	chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
 
-	/*
-	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
-	 * output cycle timings shall be used if the host drives tRC less than
-	 * 30 ns.
-	 */
-	chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0;
-
 	/* Convert min_clk_period from picoseconds to nanoseconds */
 	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
 
@@ -1214,6 +1208,16 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
 	 * Allwinner engineers.
 	 */
 	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
+	real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
+
+	/*
+	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
+	 * output cycle timings shall be used if the host drives tRC less than
+	 * 30 ns.
+	 */
+	min_clk_period = NSEC_PER_SEC / real_clk_rate;
+	chip->timing_ctl = ((min_clk_period * 2) < 30) ?
+			   NFC_TIMING_CTL_EDO : 0;
 
 	return 0;
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: sunxi: adapt clk_rate to tWB, tADL, tWHR and tRHW timings
Message-ID: <E1b54Qu-0000jD-TW@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=5abcd95d8c69008c72d54d7763e0ee2b5df84ac4
Commit:     5abcd95d8c69008c72d54d7763e0ee2b5df84ac4
Parent:     2d43457f79e48ee427666fdbfe9a53f35d3a1672
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Nov 11 22:30:30 2015 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:38 2016 +0200

    mtd: nand: sunxi: adapt clk_rate to tWB, tADL, tWHR and tRHW timings
    
    Adapt the NAND controller clk rate to the tWB, tADL, tWHR and tRHW
    timings instead of returning an error when the maximum clk divisor is
    not big enough to provide an appropriate timing.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index b906fc5..e30276d 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1163,6 +1163,18 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
 		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
 
 	/* T16 - T19 + tCAD */
+	if (timings->tWB_max > (min_clk_period * 20))
+		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
+
+	if (timings->tADL_min > (min_clk_period * 32))
+		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
+
+	if (timings->tWHR_min > (min_clk_period * 32))
+		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
+
+	if (timings->tRHW_min > (min_clk_period * 20))
+		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
+
 	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
 					min_clk_period);
 	if (tWB < 0) {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: export default read/write oob functions
Message-ID: <E1b54Qv-0000jg-4N@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=9d02fc2a5129449581c3108c260e96377cf35f7e
Commit:     9d02fc2a5129449581c3108c260e96377cf35f7e
Parent:     5abcd95d8c69008c72d54d7763e0ee2b5df84ac4
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Aug 26 16:08:12 2015 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:38 2016 +0200

    mtd: nand: export default read/write oob functions
    
    Export the default read/write oob functions (for the standard and syndrome
    scheme), so that drivers can use them for their raw implementation and
    implement their own functions for the normal oob operation.
    
    This is required if your ECC engine is capable of fixing some of the OOB
    data. In this case you have to overload the ->read_oob() and ->write_oob(),
    but if you don't specify the ->read/write_oob_raw() functions they are
    assigned to the ->read/write_oob() implementation, which is not what you
    want.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 18 ++++++++++--------
 include/linux/mtd/nand.h     | 14 ++++++++++++++
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0f0c5b1..13fcddc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1893,13 +1893,13 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @chip: nand chip info structure
  * @page: page number to read
  */
-static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-			     int page)
+int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
 {
 	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 	return 0;
 }
+EXPORT_SYMBOL(nand_read_oob_std);
 
 /**
  * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
@@ -1908,8 +1908,8 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip: nand chip info structure
  * @page: page number to read
  */
-static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-				  int page)
+int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page)
 {
 	int length = mtd->oobsize;
 	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
@@ -1937,6 +1937,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 
 	return 0;
 }
+EXPORT_SYMBOL(nand_read_oob_syndrome);
 
 /**
  * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
@@ -1944,8 +1945,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip: nand chip info structure
  * @page: page number to write
  */
-static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-			      int page)
+int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
 {
 	int status = 0;
 	const uint8_t *buf = chip->oob_poi;
@@ -1960,6 +1960,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 
 	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
+EXPORT_SYMBOL(nand_write_oob_std);
 
 /**
  * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
@@ -1968,8 +1969,8 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip: nand chip info structure
  * @page: page number to write
  */
-static int nand_write_oob_syndrome(struct mtd_info *mtd,
-				   struct nand_chip *chip, int page)
+int nand_write_oob_syndrome(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;
@@ -2019,6 +2020,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
 
 	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
+EXPORT_SYMBOL(nand_write_oob_syndrome);
 
 /**
  * nand_do_read_oob - [INTERN] NAND read out-of-band
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 1b673e1..7e06afb 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1078,4 +1078,18 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
 				void *ecc, int ecclen,
 				void *extraoob, int extraooblen,
 				int threshold);
+
+/* Default write_oob implementation */
+int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
+
+/* Default write_oob syndrome implementation */
+int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page);
+
+/* Default read_oob implementation */
+int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
+
+/* Default read_oob syndrome implementation */
+int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page);
 #endif /* __LINUX_MTD_NAND_H */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: sunxi: implement ->read_oob()/->write_oob()
Message-ID: <E1b54Qv-0000kB-AA@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=1c1bdd6f866e08b2a34318ce089b678200e8de85
Commit:     1c1bdd6f866e08b2a34318ce089b678200e8de85
Parent:     9d02fc2a5129449581c3108c260e96377cf35f7e
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Sep 2 15:05:52 2015 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:39 2016 +0200

    mtd: nand: sunxi: implement ->read_oob()/->write_oob()
    
    Allwinner's ECC engine is capable of protecting a few bytes of the OOB
    area. Implement specific OOB functions to benefit from this capability.
    
    Also, when in raw mode, the randomizer is disabled, which means you'll
    only be able to retrieve randomized data, which is not really useful
    for most applications.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index e30276d..d8ad50f 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1073,6 +1073,40 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
 	return 0;
 }
 
+static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    int page)
+{
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+	chip->pagebuf = -1;
+
+	return chip->ecc.read_page(mtd, chip, chip->buffers->databuf, 1, page);
+}
+
+static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     int page)
+{
+	int ret, status;
+
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+
+	chip->pagebuf = -1;
+
+	memset(chip->buffers->databuf, 0xff, mtd->writesize);
+	ret = chip->ecc.write_page(mtd, chip, chip->buffers->databuf, 1, page);
+	if (ret)
+		return ret;
+
+	/* Send command to program the OOB data */
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	status = chip->waitfunc(mtd, chip);
+
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
 static const s32 tWB_lut[] = {6, 12, 16, 20};
 static const s32 tRHW_lut[] = {4, 8, 12, 20};
 
@@ -1320,6 +1354,8 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 
 	layout->eccbytes = (ecc->bytes * nsectors);
 
+	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
+	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
 	ecc->layout = layout;
 	ecc->priv = data;
 
@@ -1351,6 +1387,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
 
 	ecc->read_page = sunxi_nfc_hw_ecc_read_page;
 	ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+	ecc->read_oob_raw = nand_read_oob_std;
+	ecc->write_oob_raw = nand_write_oob_std;
 	layout = ecc->layout;
 	nsectors = mtd->writesize / ecc->size;
 
@@ -1405,6 +1443,8 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
 	ecc->prepad = 4;
 	ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
 	ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
+	ecc->read_oob_raw = nand_read_oob_syndrome;
+	ecc->write_oob_raw = nand_write_oob_syndrome;
 
 	layout = ecc->layout;
 	nsectors = mtd->writesize / ecc->size;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: sunxi: implement ->read_subpage()
Message-ID: <E1b54Qv-0000kf-FZ@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=fe82ccefc992b255c35e0e56d6aded2ce090e9af
Commit:     fe82ccefc992b255c35e0e56d6aded2ce090e9af
Parent:     1c1bdd6f866e08b2a34318ce089b678200e8de85
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Sep 16 09:01:45 2015 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:39 2016 +0200

    mtd: nand: sunxi: implement ->read_subpage()
    
    Being able to read subpages can greatly improve read performances if the
    MTD user is only interested in a small section of a NAND page.
    This is particularly true with large pages (>= 8k).
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index d8ad50f..e4d487c 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -973,6 +973,39 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
 	return max_bitflips;
 }
 
+static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
+					 struct nand_chip *chip,
+					 u32 data_offs, u32 readlen,
+					 u8 *bufpoi, int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i, cur_off = 0;
+	unsigned int max_bitflips = 0;
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+	for (i = data_offs / ecc->size;
+	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		u8 *data = bufpoi + data_off;
+		u8 *oob = chip->oob_poi + oob_off;
+
+		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
+						  oob,
+						  oob_off + mtd->writesize,
+						  &cur_off, &max_bitflips,
+						  !i, page);
+		if (ret < 0)
+			return ret;
+	}
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return max_bitflips;
+}
+
 static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
 				       struct nand_chip *chip,
 				       const uint8_t *buf, int oob_required,
@@ -1389,6 +1422,7 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
 	ecc->write_page = sunxi_nfc_hw_ecc_write_page;
 	ecc->read_oob_raw = nand_read_oob_std;
 	ecc->write_oob_raw = nand_write_oob_std;
+	ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
 	layout = ecc->layout;
 	nsectors = mtd->writesize / ecc->size;
 
@@ -1635,6 +1669,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 	if (nand->options & NAND_NEED_SCRAMBLING)
 		nand->options |= NAND_NO_SUBPAGE_WRITE;
 
+	nand->options |= NAND_SUBPAGE_READ;
+
 	ret = sunxi_nand_chip_init_timings(chip, np);
 	if (ret) {
 		dev_err(dev, "could not configure chip timings: %d\n", ret);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: sunxi: improve ->cmd_ctrl() function
Message-ID: <E1b54Qv-0000lD-KY@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e9aa671f69acb87db4835e4f0b41f5fa16d16562
Commit:     e9aa671f69acb87db4835e4f0b41f5fa16d16562
Parent:     fe82ccefc992b255c35e0e56d6aded2ce090e9af
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Sep 16 09:05:31 2015 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:40 2016 +0200

    mtd: nand: sunxi: improve ->cmd_ctrl() function
    
    Try to pack address and command cycles into a single NAND controller
    command to avoid polling the status register for each single change
    on the NAND bus.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 52 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index e4d487c..ab572dd 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -238,6 +238,10 @@ struct sunxi_nand_chip {
 	u32 timing_cfg;
 	u32 timing_ctl;
 	int selected;
+	int addr_cycles;
+	u32 addr[2];
+	int cmd_cycles;
+	u8 cmd[2];
 	int nsels;
 	struct sunxi_nand_chip_sel sels[0];
 };
@@ -525,17 +529,49 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
 		writel(tmp, nfc->regs + NFC_REG_CTL);
 	}
 
-	if (dat == NAND_CMD_NONE)
-		return;
+	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
+	    !(ctrl & (NAND_CLE | NAND_ALE))) {
+		u32 cmd = 0;
 
-	if (ctrl & NAND_CLE) {
-		writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD);
-	} else {
-		writel(dat, nfc->regs + NFC_REG_ADDR_LOW);
-		writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD);
+		if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
+			return;
+
+		if (sunxi_nand->cmd_cycles--)
+			cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
+
+		if (sunxi_nand->cmd_cycles--) {
+			cmd |= NFC_SEND_CMD2;
+			writel(sunxi_nand->cmd[1],
+			       nfc->regs + NFC_REG_RCMD_SET);
+		}
+
+		sunxi_nand->cmd_cycles = 0;
+
+		if (sunxi_nand->addr_cycles) {
+			cmd |= NFC_SEND_ADR |
+			       NFC_ADR_NUM(sunxi_nand->addr_cycles);
+			writel(sunxi_nand->addr[0],
+			       nfc->regs + NFC_REG_ADDR_LOW);
+		}
+
+		if (sunxi_nand->addr_cycles > 4)
+			writel(sunxi_nand->addr[1],
+			       nfc->regs + NFC_REG_ADDR_HIGH);
+
+		writel(cmd, nfc->regs + NFC_REG_CMD);
+		sunxi_nand->addr[0] = 0;
+		sunxi_nand->addr[1] = 0;
+		sunxi_nand->addr_cycles = 0;
+		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
 	}
 
-	sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+	if (ctrl & NAND_CLE) {
+		sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
+	} else if (ctrl & NAND_ALE) {
+		sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
+				dat << ((sunxi_nand->addr_cycles % 4) * 8);
+		sunxi_nand->addr_cycles++;
+	}
 }
 
 /* These seed values have been extracted from Allwinner's BSP */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:09 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:09 +0000
Subject: mtd: nand: sunxi: let the NAND controller control the CE line
Message-ID: <E1b54Qv-0000lg-RW@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ece03cfd5260e0349442dea1d1065f44fbed1ea8
Commit:     ece03cfd5260e0349442dea1d1065f44fbed1ea8
Parent:     e9aa671f69acb87db4835e4f0b41f5fa16d16562
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 17:21:35 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:40 2016 +0200

    mtd: nand: sunxi: let the NAND controller control the CE line
    
    We don't need to manually toggle the CE line since the controller handles
    it for us. Moreover, keeping the CE line low when interacting with a DDR
    NAND can be problematic (data loss in some corner cases).
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index ab572dd..4dcc0e4 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -514,21 +514,11 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	int ret;
-	u32 tmp;
 
 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
 	if (ret)
 		return;
 
-	if (ctrl & NAND_CTRL_CHANGE) {
-		tmp = readl(nfc->regs + NFC_REG_CTL);
-		if (ctrl & NAND_NCE)
-			tmp |= NFC_CE_CTL;
-		else
-			tmp &= ~NFC_CE_CTL;
-		writel(tmp, nfc->regs + NFC_REG_CTL);
-	}
-
 	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
 	    !(ctrl & (NAND_CLE | NAND_ALE))) {
 		u32 cmd = 0;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: fix the NFC_ECC_ERR_CNT() macro
Message-ID: <E1b54Qv-0000m9-W0@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f8b04746a4ba389d609b5ddcfbf95835c7dfcb31
Commit:     f8b04746a4ba389d609b5ddcfbf95835c7dfcb31
Parent:     ece03cfd5260e0349442dea1d1065f44fbed1ea8
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 17:25:08 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:41 2016 +0200

    mtd: nand: sunxi: fix the NFC_ECC_ERR_CNT() macro
    
    NFC_ECC_ERR_CNT() is not taking into account the case when the NAND chip
    contains more than 4 ECC blocks (NANDs with 4kB+ pages).
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 4dcc0e4..4cb5c6f 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -154,7 +154,7 @@
 /* define bit use in NFC_ECC_ST */
 #define NFC_ECC_ERR(x)		BIT(x)
 #define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
-#define NFC_ECC_ERR_CNT(b, x)	(((x) >> ((b) * 8)) & 0xff)
+#define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
 
 #define NFC_DEFAULT_TIMEOUT_MS	1000
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: fix NFC_CTL setting
Message-ID: <E1b54Qw-0000md-4R@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=68ffbf7f9fb11323238cb31c956b4f381e6b05cc
Commit:     68ffbf7f9fb11323238cb31c956b4f381e6b05cc
Parent:     f8b04746a4ba389d609b5ddcfbf95835c7dfcb31
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 17:29:20 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:41 2016 +0200

    mtd: nand: sunxi: fix NFC_CTL setting
    
    NFC_PAGE_SHIFT() already takes the real page_shift value and subtract 10
    to it.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 4cb5c6f..f8b3a72 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -410,7 +410,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
 		sel = &sunxi_nand->sels[chip];
 
 		ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
-		       NFC_PAGE_SHIFT(nand->page_shift - 10);
+		       NFC_PAGE_SHIFT(nand->page_shift);
 		if (sel->rb.type == RB_NONE) {
 			nand->dev_ready = NULL;
 		} else {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: disable clks on device removal
Message-ID: <E1b54Qw-0000n4-96@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=dd26a4584c37687b8bbe89233bcc23279ca361b1
Commit:     dd26a4584c37687b8bbe89233bcc23279ca361b1
Parent:     68ffbf7f9fb11323238cb31c956b4f381e6b05cc
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 18:26:40 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:42 2016 +0200

    mtd: nand: sunxi: disable clks on device removal
    
    mod and ahb clocks are not disabled when the NAND controller device is
    removed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index f8b3a72..cad20fb 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1845,6 +1845,8 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
 	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
 
 	sunxi_nand_chips_cleanup(nfc);
+	clk_disable_unprepare(nfc->mod_clk);
+	clk_disable_unprepare(nfc->ahb_clk);
 
 	return 0;
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: enable ECC pipelining
Message-ID: <E1b54Qw-0000nZ-GC@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=336de7b1e07e6c666dbed522120547b852b3fba7
Commit:     336de7b1e07e6c666dbed522120547b852b3fba7
Parent:     dd26a4584c37687b8bbe89233bcc23279ca361b1
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 17:33:10 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:42 2016 +0200

    mtd: nand: enable ECC pipelining
    
    When the NAND controller operates in DMA mode it can pipeline ECC
    operations which improves the throughput.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index cad20fb..fe3730a 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -742,7 +742,8 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
 	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
 		     NFC_ECC_BLOCK_SIZE_MSK);
-	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION;
+	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
+		   NFC_ECC_PIPELINE;
 
 	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
 }


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: fix ->dev_ready() implementation
Message-ID: <E1b54Qw-0000o5-L5@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=a9a416f0c723e10ecccfe7ea30e93dfee0dbf10d
Commit:     a9a416f0c723e10ecccfe7ea30e93dfee0dbf10d
Parent:     336de7b1e07e6c666dbed522120547b852b3fba7
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Mon Mar 7 15:10:28 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:44 2016 +0200

    mtd: nand: sunxi: fix ->dev_ready() implementation
    
    ->dev_ready() is not supposed to wait for busy to ready solution (this is
    the role of ->waitfunc()).
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index fe3730a..fff28512c 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -357,7 +357,6 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	struct sunxi_nand_rb *rb;
-	unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20);
 	int ret;
 
 	if (sunxi_nand->selected < 0)
@@ -369,12 +368,6 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 	case RB_NATIVE:
 		ret = !!(readl(nfc->regs + NFC_REG_ST) &
 			 NFC_RB_STATE(rb->info.nativeid));
-		if (ret)
-			break;
-
-		sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo);
-		ret = !!(readl(nfc->regs + NFC_REG_ST) &
-			 NFC_RB_STATE(rb->info.nativeid));
 		break;
 	case RB_GPIO:
 		ret = gpio_get_value(rb->info.gpio);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: make use of readl_poll_timeout()
Message-ID: <E1b54Qw-0000oX-P2@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=166f08c7b6ab2f98eebbb6fc1fdb0be1efe0a566
Commit:     166f08c7b6ab2f98eebbb6fc1fdb0be1efe0a566
Parent:     a9a416f0c723e10ecccfe7ea30e93dfee0dbf10d
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Mon Mar 7 15:25:17 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:45 2016 +0200

    mtd: nand: sunxi: make use of readl_poll_timeout()
    
    Replace open coded polling loops by readl_poll_timeout() calls.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index fff28512c..d4d79b2 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -38,7 +38,7 @@
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
-#include <linux/io.h>
+#include <linux/iopoll.h>
 
 #define NFC_REG_CTL		0x0000
 #define NFC_REG_ST		0x0004
@@ -322,33 +322,33 @@ static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags,
 
 static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
 {
-	unsigned long timeout = jiffies +
-				msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS);
+	u32 status;
+	int ret;
 
-	do {
-		if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
-			return 0;
-	} while (time_before(jiffies, timeout));
+	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+				 !(status & NFC_CMD_FIFO_STATUS), 1,
+				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+	if (ret)
+		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
 
-	dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
-	return -ETIMEDOUT;
+	return ret;
 }
 
 static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
 {
-	unsigned long timeout = jiffies +
-				msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS);
+	u32 ctl;
+	int ret;
 
 	writel(0, nfc->regs + NFC_REG_ECC_CTL);
 	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
 
-	do {
-		if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET))
-			return 0;
-	} while (time_before(jiffies, timeout));
+	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
+				 !(ctl & NFC_RESET), 1,
+				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+	if (ret)
+		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
 
-	dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
-	return -ETIMEDOUT;
+	return ret;
 }
 
 static int sunxi_nfc_dev_ready(struct mtd_info *mtd)


From linux-mtd at lists.infradead.org  Mon May 23 21:59:10 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:10 +0000
Subject: mtd: nand: sunxi: poll for events instead of using interrupts
Message-ID: <E1b54Qw-0000ox-V7@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c0c9dfa8adf09dbbb7dc32c20d9ccb33e19250c0
Commit:     c0c9dfa8adf09dbbb7dc32c20d9ccb33e19250c0
Parent:     166f08c7b6ab2f98eebbb6fc1fdb0be1efe0a566
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Mon Mar 7 15:34:39 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:45 2016 +0200

    mtd: nand: sunxi: poll for events instead of using interrupts
    
    Some NAND operations are so fast that it doesn't make any sense to use
    interrupt based waits (the scheduling overhead is not worth it).
    Rename sunxi_nfc_wait_int() into sunxi_nfc_wait_events() and add a
    parameter to specify whether polling should be used or not.
    
    Note that all sunxi_nfc_wait_int() are moved to the polling approach now,
    but this should change as soon as we have more information about the
    approximate time we are about to wait (can be extracted from the NAND
    timings, and the type of operation).
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 45 +++++++++++++++++++++++++++++--------------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index d4d79b2..8be3dba 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -301,23 +301,40 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags,
-			      unsigned int timeout_ms)
+static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
+				 bool use_polling, unsigned int timeout_ms)
 {
-	init_completion(&nfc->complete);
+	int ret;
 
-	writel(flags, nfc->regs + NFC_REG_INT);
+	if (events & ~NFC_INT_MASK)
+		return -EINVAL;
 
 	if (!timeout_ms)
 		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
 
-	if (!wait_for_completion_timeout(&nfc->complete,
-					 msecs_to_jiffies(timeout_ms))) {
-		dev_err(nfc->dev, "wait interrupt timedout\n");
-		return -ETIMEDOUT;
+	if (!use_polling) {
+		init_completion(&nfc->complete);
+
+		writel(events, nfc->regs + NFC_REG_INT);
+
+		ret = wait_for_completion_timeout(&nfc->complete,
+						msecs_to_jiffies(timeout_ms));
+
+		writel(0, nfc->regs + NFC_REG_INT);
+	} else {
+		u32 status;
+
+		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+					 (status & events) == events, 1,
+					 timeout_ms * 1000);
 	}
 
-	return 0;
+	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+
+	if (ret)
+		dev_err(nfc->dev, "wait interrupt timedout\n");
+
+	return ret;
 }
 
 static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
@@ -448,7 +465,7 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
 		writel(tmp, nfc->regs + NFC_REG_CMD);
 
-		ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
 		if (ret)
 			break;
 
@@ -483,7 +500,7 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 		      NFC_ACCESS_DIR;
 		writel(tmp, nfc->regs + NFC_REG_CMD);
 
-		ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
 		if (ret)
 			break;
 
@@ -545,7 +562,7 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
 		sunxi_nand->addr[0] = 0;
 		sunxi_nand->addr[1] = 0;
 		sunxi_nand->addr_cycles = 0;
-		sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+		sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
 	}
 
 	if (ctrl & NAND_CLE) {
@@ -788,7 +805,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
 	       nfc->regs + NFC_REG_CMD);
 
-	ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
 	sunxi_nfc_randomizer_disable(mtd);
 	if (ret)
 		return ret;
@@ -926,7 +943,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 	       NFC_ACCESS_DIR | NFC_ECC_OP,
 	       nfc->regs + NFC_REG_CMD);
 
-	ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
 	sunxi_nfc_randomizer_disable(mtd);
 	if (ret)
 		return ret;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: nand: sunxi: move some ECC related operations to their own
 functions
Message-ID: <E1b54Qx-0000pO-3t@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=cc6822fb756b5080ca127fef1a89f35558bd2610
Commit:     cc6822fb756b5080ca127fef1a89f35558bd2610
Parent:     c0c9dfa8adf09dbbb7dc32c20d9ccb33e19250c0
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 17:56:47 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:46 2016 +0200

    mtd: nand: sunxi: move some ECC related operations to their own functions
    
    In order to support DMA operations in a clean way we need to extract some
    of the logic coded in sunxi_nfc_hw_ecc_read/write_page() into their own
    function.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 163 ++++++++++++++++++++++++++++--------------
 1 file changed, 108 insertions(+), 55 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 8be3dba..c20bf59 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -775,6 +775,94 @@ static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
 	buf[3] = user_data >> 24;
 }
 
+static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
+{
+	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
+						int step, bool bbm, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
+				   oob);
+
+	/* De-randomize the Bad Block Marker. */
+	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
+		sunxi_nfc_randomize_bbm(mtd, page, oob);
+}
+
+static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
+						const u8 *oob, int step,
+						bool bbm, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	u8 user_data[4];
+
+	/* Randomize the Bad Block Marker. */
+	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
+		memcpy(user_data, oob, sizeof(user_data));
+		sunxi_nfc_randomize_bbm(mtd, page, user_data);
+		oob = user_data;
+	}
+
+	writel(sunxi_nfc_buf_to_user_data(oob),
+	       nfc->regs + NFC_REG_USER_DATA(step));
+}
+
+static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
+					  unsigned int *max_bitflips, int ret)
+{
+	if (ret < 0) {
+		mtd->ecc_stats.failed++;
+	} else {
+		mtd->ecc_stats.corrected += ret;
+		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+	}
+}
+
+static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
+				    int step, bool *erased)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	u32 status, tmp;
+
+	*erased = false;
+
+	status = readl(nfc->regs + NFC_REG_ECC_ST);
+
+	if (status & NFC_ECC_ERR(step))
+		return -EBADMSG;
+
+	if (status & NFC_ECC_PAT_FOUND(step)) {
+		u8 pattern;
+
+		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
+			pattern = 0x0;
+		} else {
+			pattern = 0xff;
+			*erased = true;
+		}
+
+		if (data)
+			memset(data, pattern, ecc->size);
+
+		if (oob)
+			memset(oob, pattern, ecc->bytes + 4);
+
+		return 0;
+	}
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
+
+	return NFC_ECC_ERR_CNT(step, tmp);
+}
+
 static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 				       u8 *data, int data_off,
 				       u8 *oob, int oob_off,
@@ -786,7 +874,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	int raw_mode = 0;
-	u32 status;
+	bool erased;
 	int ret;
 
 	if (*cur_off != data_off)
@@ -812,27 +900,11 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 
 	*cur_off = oob_off + ecc->bytes + 4;
 
-	status = readl(nfc->regs + NFC_REG_ECC_ST);
-	if (status & NFC_ECC_PAT_FOUND(0)) {
-		u8 pattern = 0xff;
-
-		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
-			pattern = 0x0;
-
-		memset(data, pattern, ecc->size);
-		memset(oob, pattern, ecc->bytes + 4);
-
+	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob, 0, &erased);
+	if (erased)
 		return 1;
-	}
-
-	ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
-
-	memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
-	nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-	sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
-
-	if (status & NFC_ECC_ERR(0)) {
+	if (ret < 0) {
 		/*
 		 * Re-read the data with the randomizer disabled to identify
 		 * bitflips in erased pages.
@@ -840,35 +912,32 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 		if (nand->options & NAND_NEED_SCRAMBLING) {
 			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
 			nand->read_buf(mtd, data, ecc->size);
-			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-			nand->read_buf(mtd, oob, ecc->bytes + 4);
+		} else {
+			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
+				      ecc->size);
 		}
 
+		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+		nand->read_buf(mtd, oob, ecc->bytes + 4);
+
 		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
 						  oob, ecc->bytes + 4,
 						  NULL, 0, ecc->strength);
 		if (ret >= 0)
 			raw_mode = 1;
 	} else {
-		/*
-		 * The engine protects 4 bytes of OOB data per chunk.
-		 * Retrieve the corrected OOB bytes.
-		 */
-		sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)),
-					   oob);
+		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
-		/* De-randomize the Bad Block Marker. */
-		if (bbm && nand->options & NAND_NEED_SCRAMBLING)
-			sunxi_nfc_randomize_bbm(mtd, page, oob);
-	}
+		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+		sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
+					      true, page);
 
-	if (ret < 0) {
-		mtd->ecc_stats.failed++;
-	} else {
-		mtd->ecc_stats.corrected += ret;
-		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+		sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
+						    bbm, page);
 	}
 
+	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
+
 	return raw_mode;
 }
 
@@ -897,11 +966,6 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
 	*cur_off = mtd->oobsize + mtd->writesize;
 }
 
-static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
-{
-	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 					const u8 *data, int data_off,
 					const u8 *oob, int oob_off,
@@ -918,19 +982,6 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 
 	sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
 
-	/* Fill OOB data in */
-	if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) {
-		u8 user_data[4];
-
-		memcpy(user_data, oob, 4);
-		sunxi_nfc_randomize_bbm(mtd, page, user_data);
-		writel(sunxi_nfc_buf_to_user_data(user_data),
-		       nfc->regs + NFC_REG_USER_DATA(0));
-	} else {
-		writel(sunxi_nfc_buf_to_user_data(oob),
-		       nfc->regs + NFC_REG_USER_DATA(0));
-	}
-
 	if (data_off + ecc->size != oob_off)
 		nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
 
@@ -939,6 +990,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 		return ret;
 
 	sunxi_nfc_randomizer_enable(mtd);
+	sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
+
 	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
 	       NFC_ACCESS_DIR | NFC_ECC_OP,
 	       nfc->regs + NFC_REG_CMD);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: nand: sunxi: make OOB retrieval optional
Message-ID: <E1b54Qx-0000pr-8Y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=828dec153044805506cc2b8e39cb3f62d5f76a12
Commit:     828dec153044805506cc2b8e39cb3f62d5f76a12
Parent:     cc6822fb756b5080ca127fef1a89f35558bd2610
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 18:09:21 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:46 2016 +0200

    mtd: nand: sunxi: make OOB retrieval optional
    
    sunxi_nfc_hw_ecc_read_chunk() always retrieves the ECC and protected free
    bytes, no matter if the user really asked for it or not. This can take a
    non negligible amount of time, especially on NAND chips exposing large OOB
    areas (> 1KB). Make it optional.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index c20bf59..b710532 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -868,7 +868,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 				       u8 *oob, int oob_off,
 				       int *cur_off,
 				       unsigned int *max_bitflips,
-				       bool bbm, int page)
+				       bool bbm, bool oob_required, int page)
 {
 	struct nand_chip *nand = mtd_to_nand(mtd);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
@@ -900,7 +900,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 
 	*cur_off = oob_off + ecc->bytes + 4;
 
-	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob, 0, &erased);
+	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
+				       &erased);
 	if (erased)
 		return 1;
 
@@ -928,12 +929,14 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 	} else {
 		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
-		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-		sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
-					      true, page);
+		if (oob_required) {
+			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+			sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
+						      true, page);
 
-		sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
-						    bbm, page);
+			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
+							    bbm, page);
+		}
 	}
 
 	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
@@ -1047,7 +1050,7 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
 		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
 						  oob_off + mtd->writesize,
 						  &cur_off, &max_bitflips,
-						  !i, page);
+						  !i, oob_required, page);
 		if (ret < 0)
 			return ret;
 		else if (ret)
@@ -1085,8 +1088,8 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
 		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
 						  oob,
 						  oob_off + mtd->writesize,
-						  &cur_off, &max_bitflips,
-						  !i, page);
+						  &cur_off, &max_bitflips, !i,
+						  false, page);
 		if (ret < 0)
 			return ret;
 	}
@@ -1148,7 +1151,9 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
 
 		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
 						  oob_off, &cur_off,
-						  &max_bitflips, !i, page);
+						  &max_bitflips, !i,
+						  oob_required,
+						  page);
 		if (ret < 0)
 			return ret;
 		else if (ret)


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: nand: sunxi: make cur_off parameter optional in extra oob helpers
Message-ID: <E1b54Qx-0000qQ-ET@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c4f3ef2c6c219c3e58e0f5a9589a67685a75d787
Commit:     c4f3ef2c6c219c3e58e0f5a9589a67685a75d787
Parent:     828dec153044805506cc2b8e39cb3f62d5f76a12
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 4 18:13:10 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:47 2016 +0200

    mtd: nand: sunxi: make cur_off parameter optional in extra oob helpers
    
    Allow for NULL cur_offs values when the caller does not know where the
    NAND page register pointer points to.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index b710532..b12ed83 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -956,7 +956,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
 	if (len <= 0)
 		return;
 
-	if (*cur_off != offset)
+	if (!cur_off || *cur_off != offset)
 		nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
 			      offset + mtd->writesize, -1);
 
@@ -966,7 +966,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
 		sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
 					      false, page);
 
-	*cur_off = mtd->oobsize + mtd->writesize;
+	if (cur_off)
+		*cur_off = mtd->oobsize + mtd->writesize;
 }
 
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
@@ -1021,13 +1022,14 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
 	if (len <= 0)
 		return;
 
-	if (*cur_off != offset)
+	if (!cur_off || *cur_off != offset)
 		nand->cmdfunc(mtd, NAND_CMD_RNDIN,
 			      offset + mtd->writesize, -1);
 
 	sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
 
-	*cur_off = mtd->oobsize + mtd->writesize;
+	if (cur_off)
+		*cur_off = mtd->oobsize + mtd->writesize;
 }
 
 static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: add mtd_ooblayout_xxx() helper functions
Message-ID: <E1b54Qx-0000qq-Jd@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=75eb2cec251fda33c9bb716ecc372819abb9278a
Commit:     75eb2cec251fda33c9bb716ecc372819abb9278a
Parent:     c4f3ef2c6c219c3e58e0f5a9589a67685a75d787
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Thu Feb 4 09:52:30 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:47 2016 +0200

    mtd: add mtd_ooblayout_xxx() helper functions
    
    In order to make the ecclayout definition completely dynamic we need to
    rework the way the OOB layout are defined and iterated.
    
    Create a few mtd_ooblayout_xxx() helpers to ease OOB bytes manipulation
    and hide ecclayout internals to their users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/mtdcore.c   | 400 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/mtd.h |  33 ++++
 2 files changed, 433 insertions(+)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index bee180bd..0290c41 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1016,6 +1016,406 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
 
+/**
+ * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
+ * @mtd: MTD device structure
+ * @section: ECC section. Depending on the layout you may have all the ECC
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobecc: OOB region struct filled with the appropriate ECC position
+ *	    information
+ *
+ * This functions return ECC section information in the OOB area. I you want
+ * to get all the ECC bytes information, then you should call
+ * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
+		      struct mtd_oob_region *oobecc)
+{
+	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
+
+	memset(oobecc, 0, sizeof(*oobecc));
+
+	if (!mtd || section < 0)
+		return -EINVAL;
+
+	if (!mtd->ecclayout)
+		return -ENOTSUPP;
+
+	/*
+	 * This logic allows us to reuse the ->ecclayout information and
+	 * expose them as ECC regions (as done for the OOB free regions).
+	 *
+	 * TODO: this should be dropped as soon as we get rid of the
+	 * ->ecclayout field.
+	 */
+	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
+		eccpos = mtd->ecclayout->eccpos[eccbyte];
+
+		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
+			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
+
+			if (eccpos + 1 == neccpos) {
+				length++;
+				continue;
+			}
+		}
+
+		if (section == cursection)
+			break;
+
+		length = 0;
+		cursection++;
+	}
+
+	if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
+		return -ERANGE;
+
+	oobecc->length = length + 1;
+	oobecc->offset = eccpos - length;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
+
+/**
+ * mtd_ooblayout_free - Get the OOB region definition of a specific free
+ *			section
+ * @mtd: MTD device structure
+ * @section: Free section you are interested in. Depending on the layout
+ *	     you may have all the free bytes stored in a single contiguous
+ *	     section, or one section per ECC chunk plus an extra section
+ *	     for the remaining bytes (or other funky layout).
+ * @oobfree: OOB region struct filled with the appropriate free position
+ *	     information
+ *
+ * This functions return free bytes position in the OOB area. I you want
+ * to get all the free bytes information, then you should call
+ * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_free(struct mtd_info *mtd, int section,
+		       struct mtd_oob_region *oobfree)
+{
+	memset(oobfree, 0, sizeof(*oobfree));
+
+	if (!mtd || section < 0)
+		return -EINVAL;
+
+	if (!mtd->ecclayout)
+		return -ENOTSUPP;
+
+	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
+		return -ERANGE;
+
+	oobfree->offset = mtd->ecclayout->oobfree[section].offset;
+	oobfree->length = mtd->ecclayout->oobfree[section].length;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
+
+/**
+ * mtd_ooblayout_find_region - Find the region attached to a specific byte
+ * @mtd: mtd info structure
+ * @byte: the byte we are searching for
+ * @sectionp: pointer where the section id will be stored
+ * @oobregion: used to retrieve the ECC position
+ * @iter: iterator function. Should be either mtd_ooblayout_free or
+ *	  mtd_ooblayout_ecc depending on the region type you're searching for
+ *
+ * This functions returns the section id and oobregion information of a
+ * specific byte. For example, say you want to know where the 4th ECC byte is
+ * stored, you'll use:
+ *
+ * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
+				int *sectionp, struct mtd_oob_region *oobregion,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	int pos = 0, ret, section = 0;
+
+	memset(oobregion, 0, sizeof(*oobregion));
+
+	while (1) {
+		ret = iter(mtd, section, oobregion);
+		if (ret)
+			return ret;
+
+		if (pos + oobregion->length > byte)
+			break;
+
+		pos += oobregion->length;
+		section++;
+	}
+
+	/*
+	 * Adjust region info to make it start at the beginning at the
+	 * 'start' ECC byte.
+	 */
+	oobregion->offset += byte - pos;
+	oobregion->length -= byte - pos;
+	*sectionp = section;
+
+	return 0;
+}
+
+/**
+ * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
+ *				  ECC byte
+ * @mtd: mtd info structure
+ * @eccbyte: the byte we are searching for
+ * @sectionp: pointer where the section id will be stored
+ * @oobregion: OOB region information
+ *
+ * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
+ * byte.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
+				 int *section,
+				 struct mtd_oob_region *oobregion)
+{
+	return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
+					 mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
+
+/**
+ * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @buf: destination buffer to store OOB bytes
+ * @oobbuf: OOB buffer
+ * @start: first byte to retrieve
+ * @nbytes: number of bytes to retrieve
+ * @iter: section iterator
+ *
+ * Extract bytes attached to a specific category (ECC or free)
+ * from the OOB buffer and copy them into buf.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
+				const u8 *oobbuf, int start, int nbytes,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion = { };
+	int section = 0, ret;
+
+	ret = mtd_ooblayout_find_region(mtd, start, &section,
+					&oobregion, iter);
+
+	while (!ret) {
+		int cnt;
+
+		cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+		memcpy(buf, oobbuf + oobregion.offset, cnt);
+		buf += cnt;
+		nbytes -= cnt;
+
+		if (!nbytes)
+			break;
+
+		ret = iter(mtd, ++section, &oobregion);
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @buf: source buffer to get OOB bytes from
+ * @oobbuf: OOB buffer
+ * @start: first OOB byte to set
+ * @nbytes: number of OOB bytes to set
+ * @iter: section iterator
+ *
+ * Fill the OOB buffer with data provided in buf. The category (ECC or free)
+ * is selected by passing the appropriate iterator.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
+				u8 *oobbuf, int start, int nbytes,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion = { };
+	int section = 0, ret;
+
+	ret = mtd_ooblayout_find_region(mtd, start, &section,
+					&oobregion, iter);
+
+	while (!ret) {
+		int cnt;
+
+		cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+		memcpy(oobbuf + oobregion.offset, buf, cnt);
+		buf += cnt;
+		nbytes -= cnt;
+
+		if (!nbytes)
+			break;
+
+		ret = iter(mtd, ++section, &oobregion);
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
+ * @mtd: mtd info structure
+ * @iter: category iterator
+ *
+ * Count the number of bytes in a given category.
+ *
+ * Returns a positive value on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion = { };
+	int section = 0, ret, nbytes = 0;
+
+	while (1) {
+		ret = iter(mtd, section++, &oobregion);
+		if (ret) {
+			if (ret == -ERANGE)
+				ret = nbytes;
+			break;
+		}
+
+		nbytes += oobregion.length;
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: destination buffer to store ECC bytes
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to retrieve
+ * @nbytes: number of ECC bytes to retrieve
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
+			       const u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
+
+/**
+ * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: source buffer to get ECC bytes from
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to set
+ * @nbytes: number of ECC bytes to set
+ *
+ * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
+			       u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
+
+/**
+ * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @databuf: destination buffer to store ECC bytes
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to retrieve
+ * @nbytes: number of ECC bytes to retrieve
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
+				const u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
+
+/**
+ * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: source buffer to get data bytes from
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to set
+ * @nbytes: number of ECC bytes to set
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
+				u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
+
+/**
+ * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
+ * @mtd: mtd info structure
+ *
+ * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
+{
+	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
+
+/**
+ * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB
+ * @mtd: mtd info structure
+ *
+ * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
+{
+	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
+
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ef9fea4..117ca1f 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -108,6 +108,21 @@ struct nand_ecclayout {
 	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
 };
 
+/**
+ * struct mtd_oob_region - oob region definition
+ * @offset: region offset
+ * @length: region length
+ *
+ * This structure describes a region of the OOB area, and is used
+ * to retrieve ECC or free bytes sections.
+ * Each section is defined by an offset within the OOB area and a
+ * length.
+ */
+struct mtd_oob_region {
+	u32 offset;
+	u32 length;
+};
+
 struct module;	/* only needed for owner field in mtd_info */
 
 struct mtd_info {
@@ -253,6 +268,24 @@ struct mtd_info {
 	int usecount;
 };
 
+int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
+		      struct mtd_oob_region *oobecc);
+int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
+				 int *section,
+				 struct mtd_oob_region *oobregion);
+int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
+			       const u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
+			       u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_free(struct mtd_info *mtd, int section,
+		       struct mtd_oob_region *oobfree);
+int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
+				const u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
+				u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
+int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
+
 static inline void mtd_set_of_node(struct mtd_info *mtd,
 				   struct device_node *np)
 {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qx-0000rL-OE@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c2b78452a9db438d592bf72af7bb2ae3062cb922
Commit:     c2b78452a9db438d592bf72af7bb2ae3062cb922
Parent:     75eb2cec251fda33c9bb716ecc372819abb9278a
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:10:30 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:48 2016 +0200

    mtd: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/mtdchar.c | 107 +++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 6d19835..cd64ab7 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -472,28 +472,101 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
  * nand_ecclayout flexibly (i.e. the struct may change size in new
  * releases without requiring major rewrites).
  */
-static int shrink_ecclayout(const struct nand_ecclayout *from,
-		struct nand_ecclayout_user *to)
+static int shrink_ecclayout(struct mtd_info *mtd,
+			    struct nand_ecclayout_user *to)
 {
-	int i;
+	struct mtd_oob_region oobregion;
+	int i, section = 0, ret;
 
-	if (!from || !to)
+	if (!mtd || !to)
 		return -EINVAL;
 
 	memset(to, 0, sizeof(*to));
 
-	to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
-	for (i = 0; i < to->eccbytes; i++)
-		to->eccpos[i] = from->eccpos[i];
+	to->eccbytes = 0;
+	for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) {
+		u32 eccpos;
+
+		ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
+		if (ret < 0) {
+			if (ret != -ERANGE)
+				return ret;
+
+			break;
+		}
+
+		eccpos = oobregion.offset;
+		for (; i < MTD_MAX_ECCPOS_ENTRIES &&
+		       eccpos < oobregion.offset + oobregion.length; i++) {
+			to->eccpos[i] = eccpos++;
+			to->eccbytes++;
+		}
+	}
 
 	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
-		if (from->oobfree[i].length == 0 &&
-				from->oobfree[i].offset == 0)
+		ret = mtd_ooblayout_free(mtd, i, &oobregion);
+		if (ret < 0) {
+			if (ret != -ERANGE)
+				return ret;
+
+			break;
+		}
+
+		to->oobfree[i].offset = oobregion.offset;
+		to->oobfree[i].length = oobregion.length;
+		to->oobavail += to->oobfree[i].length;
+	}
+
+	return 0;
+}
+
+static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
+{
+	struct mtd_oob_region oobregion;
+	int i, section = 0, ret;
+
+	if (!mtd || !to)
+		return -EINVAL;
+
+	memset(to, 0, sizeof(*to));
+
+	to->eccbytes = 0;
+	for (i = 0; i < ARRAY_SIZE(to->eccpos);) {
+		u32 eccpos;
+
+		ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
+		if (ret < 0) {
+			if (ret != -ERANGE)
+				return ret;
+
 			break;
-		to->oobavail += from->oobfree[i].length;
-		to->oobfree[i] = from->oobfree[i];
+		}
+
+		if (oobregion.length + i > ARRAY_SIZE(to->eccpos))
+			return -EINVAL;
+
+		eccpos = oobregion.offset;
+		for (; eccpos < oobregion.offset + oobregion.length; i++) {
+			to->eccpos[i] = eccpos++;
+			to->eccbytes++;
+		}
 	}
 
+	for (i = 0; i < 8; i++) {
+		ret = mtd_ooblayout_free(mtd, i, &oobregion);
+		if (ret < 0) {
+			if (ret != -ERANGE)
+				return ret;
+
+			break;
+		}
+
+		to->oobfree[i][0] = oobregion.offset;
+		to->oobfree[i][1] = oobregion.length;
+	}
+
+	to->useecc = MTD_NANDECC_AUTOPLACE;
+
 	return 0;
 }
 
@@ -817,14 +890,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 
 		if (!mtd->ecclayout)
 			return -EOPNOTSUPP;
-		if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
-			return -EINVAL;
 
-		oi.useecc = MTD_NANDECC_AUTOPLACE;
-		memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
-		memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
-		       sizeof(oi.oobfree));
-		oi.eccbytes = mtd->ecclayout->eccbytes;
+		ret = get_oobinfo(mtd, &oi);
+		if (ret)
+			return ret;
 
 		if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
 			return -EFAULT;
@@ -920,7 +989,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 		if (!usrlay)
 			return -ENOMEM;
 
-		shrink_ecclayout(mtd->ecclayout, usrlay);
+		shrink_ecclayout(mtd, usrlay);
 
 		if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
 			ret = -EFAULT;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: atmel: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000sJ-2c@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=78d28e8ec4fbd4d1e0c375d7a28f4f23e9e7b15e
Commit:     78d28e8ec4fbd4d1e0c375d7a28f4f23e9e7b15e
Parent:     846031d3e1837b71e350bd8098f00995069859a8
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:11:14 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:49 2016 +0200

    mtd: nand: atmel: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Reviewed-by: Nicolas Ferre <nicolas.ferre at atmel.com>
---
 drivers/mtd/nand/atmel_nand.c | 50 +++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 5e716f2..b132c8f 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -833,13 +833,16 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
 			dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
 				pos, bit_pos, err_byte, *(buf + byte_pos));
 		} else {
+			struct mtd_oob_region oobregion;
+
 			/* Bit flip in OOB area */
 			tmp = sector_num * nand_chip->ecc.bytes
 					+ (byte_pos - sector_size);
 			err_byte = ecc[tmp];
 			ecc[tmp] ^= (1 << bit_pos);
 
-			pos = tmp + nand_chip->ecc.layout->eccpos[0];
+			mtd_ooblayout_ecc(mtd, 0, &oobregion);
+			pos = tmp + oobregion.offset;
 			dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
 				pos, bit_pos, err_byte, ecc[tmp]);
 		}
@@ -931,7 +934,6 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
 	int eccsize = chip->ecc.size * chip->ecc.steps;
 	uint8_t *oob = chip->oob_poi;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	uint32_t stat;
 	unsigned long end_time;
 	int bitflips = 0;
@@ -953,7 +955,11 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 
 	stat = pmecc_readl_relaxed(host->ecc, ISR);
 	if (stat != 0) {
-		bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
+		struct mtd_oob_region oobregion;
+
+		mtd_ooblayout_ecc(mtd, 0, &oobregion);
+		bitflips = pmecc_correction(mtd, stat, buf,
+					    &oob[oobregion.offset]);
 		if (bitflips < 0)
 			/* uncorrectable errors */
 			return 0;
@@ -967,8 +973,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 		int page)
 {
 	struct atmel_nand_host *host = nand_get_controller_data(chip);
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
-	int i, j;
+	struct mtd_oob_region oobregion = { };
+	int i, j, section = 0;
 	unsigned long end_time;
 
 	if (!host->nfc || !host->nfc->write_by_sram) {
@@ -987,11 +993,14 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 
 	for (i = 0; i < chip->ecc.steps; i++) {
 		for (j = 0; j < chip->ecc.bytes; j++) {
-			int pos;
+			if (!oobregion.length)
+				mtd_ooblayout_ecc(mtd, section, &oobregion);
 
-			pos = i * chip->ecc.bytes + j;
-			chip->oob_poi[eccpos[pos]] =
+			chip->oob_poi[oobregion.offset] =
 				pmecc_readb_ecc_relaxed(host->ecc, i, j);
+			oobregion.length--;
+			oobregion.offset++;
+			section++;
 		}
 	}
 	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1005,6 +1014,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
 	uint32_t val = 0;
 	struct nand_ecclayout *ecc_layout;
+	struct mtd_oob_region oobregion;
 
 	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
 	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
@@ -1056,9 +1066,10 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
 
 	ecc_layout = nand_chip->ecc.layout;
 	pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
-	pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	pmecc_writel(host->ecc, SADDR, oobregion.offset);
 	pmecc_writel(host->ecc, EADDR,
-			ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
+		     oobregion.offset + ecc_layout->eccbytes - 1);
 	/* See datasheet about PMECC Clock Control Register */
 	pmecc_writel(host->ecc, CLK, 2);
 	pmecc_writel(host->ecc, IDR, 0xff);
@@ -1359,12 +1370,12 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 {
 	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;
 	unsigned int max_bitflips = 0;
+	struct mtd_oob_region oobregion = {};
 
 	/*
 	 * Errata: ALE is incorrectly wired up to the ECC controller
@@ -1382,19 +1393,20 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 	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
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	if (oobregion.offset != 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 first ECC byte is at offset
+		 * 0 in the OOB area.
 		 */
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
-				mtd->writesize + eccpos[0], -1);
+			      mtd->writesize + oobregion.offset, -1);
 	}
 
 	/* the ECC controller needs to read the ECC just after the data */
-	ecc_pos = oob + eccpos[0];
+	ecc_pos = oob + oobregion.offset;
 	chip->read_buf(mtd, ecc_pos, eccbytes);
 
 	/* check if there's an error */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:11 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:11 +0000
Subject: mtd: nand: core: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qx-0000rp-Tx@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=846031d3e1837b71e350bd8098f00995069859a8
Commit:     846031d3e1837b71e350bd8098f00995069859a8
Parent:     c2b78452a9db438d592bf72af7bb2ae3062cb922
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:11:00 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:49 2016 +0200

    mtd: nand: core: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 200 +++++++++++++++++++------------------------
 drivers/mtd/nand/nand_bch.c  |  13 ++-
 2 files changed, 100 insertions(+), 113 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 13fcddc..24ed445 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1279,13 +1279,12 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
 static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 				uint8_t *buf, int oob_required, int page)
 {
-	int i, eccsize = chip->ecc.size;
+	int i, eccsize = chip->ecc.size, ret;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
 	uint8_t *p = buf;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	unsigned int max_bitflips = 0;
 
 	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
@@ -1293,8 +1292,10 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		ecc_code[i] = chip->oob_poi[eccpos[i]];
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	eccsteps = chip->ecc.steps;
 	p = buf;
@@ -1326,14 +1327,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
 			int page)
 {
-	int start_step, end_step, num_steps;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
+	int start_step, end_step, num_steps, ret;
 	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;
-	int index;
+	int index, section = 0;
 	unsigned int max_bitflips = 0;
+	struct mtd_oob_region oobregion = { };
 
 	/* Column address within the page aligned to ECC size (256bytes) */
 	start_step = data_offs / chip->ecc.size;
@@ -1361,12 +1362,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 	 * The performance is faster if we position offsets according to
 	 * ecc.pos. Let's make sure that there are no gaps in ECC positions.
 	 */
-	for (i = 0; i < eccfrag_len - 1; i++) {
-		if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
-			gaps = 1;
-			break;
-		}
-	}
+	ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
+	if (ret)
+		return ret;
+
+	if (oobregion.length < eccfrag_len)
+		gaps = 1;
+
 	if (gaps) {
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
 		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1375,20 +1377,23 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 		 * Send the command to read the particular ECC bytes take care
 		 * about buswidth alignment in read_buf.
 		 */
-		aligned_pos = eccpos[index] & ~(busw - 1);
+		aligned_pos = oobregion.offset & ~(busw - 1);
 		aligned_len = eccfrag_len;
-		if (eccpos[index] & (busw - 1))
+		if (oobregion.offset & (busw - 1))
 			aligned_len++;
-		if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
+		if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
+		    (busw - 1))
 			aligned_len++;
 
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
-					mtd->writesize + aligned_pos, -1);
+			      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 + index]];
+	ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
+					 chip->oob_poi, index, eccfrag_len);
+	if (ret)
+		return ret;
 
 	p = bufpoi + data_col_addr;
 	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
@@ -1429,13 +1434,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 				uint8_t *buf, int oob_required, int page)
 {
-	int i, eccsize = chip->ecc.size;
+	int i, eccsize = chip->ecc.size, ret;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
 	uint8_t *p = buf;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	unsigned int max_bitflips = 0;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
@@ -1445,8 +1449,10 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 	}
 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		ecc_code[i] = chip->oob_poi[eccpos[i]];
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	eccsteps = chip->ecc.steps;
 	p = buf;
@@ -1491,12 +1497,11 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 {
-	int i, eccsize = chip->ecc.size;
+	int i, eccsize = chip->ecc.size, ret;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
 	uint8_t *p = buf;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	unsigned int max_bitflips = 0;
 
@@ -1505,8 +1510,10 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		ecc_code[i] = chip->oob_poi[eccpos[i]];
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		int stat;
@@ -1607,14 +1614,17 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 
 /**
  * nand_transfer_oob - [INTERN] Transfer oob to client buffer
- * @chip: nand chip structure
+ * @mtd: mtd info structure
  * @oob: oob destination address
  * @ops: oob ops structure
  * @len: size of oob to transfer
  */
-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
+static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
 				  struct mtd_oob_ops *ops, size_t len)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
 	switch (ops->mode) {
 
 	case MTD_OPS_PLACE_OOB:
@@ -1622,31 +1632,12 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
 		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
 		return oob + len;
 
-	case MTD_OPS_AUTO_OOB: {
-		struct nand_oobfree *free = chip->ecc.layout->oobfree;
-		uint32_t boffs = 0, roffs = ops->ooboffs;
-		size_t bytes = 0;
-
-		for (; free->length && len; free++, len -= bytes) {
-			/* Read request not from offset 0? */
-			if (unlikely(roffs)) {
-				if (roffs >= free->length) {
-					roffs -= free->length;
-					continue;
-				}
-				boffs = free->offset + roffs;
-				bytes = min_t(size_t, len,
-					      (free->length - roffs));
-				roffs = 0;
-			} else {
-				bytes = min_t(size_t, len, free->length);
-				boffs = free->offset;
-			}
-			memcpy(oob, chip->oob_poi + boffs, bytes);
-			oob += bytes;
-		}
-		return oob;
-	}
+	case MTD_OPS_AUTO_OOB:
+		ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
+						  ops->ooboffs, len);
+		BUG_ON(ret);
+		return oob + len;
+
 	default:
 		BUG();
 	}
@@ -1780,7 +1771,7 @@ read_retry:
 				int toread = min(oobreadlen, max_oobsize);
 
 				if (toread) {
-					oob = nand_transfer_oob(chip,
+					oob = nand_transfer_oob(mtd,
 						oob, ops, toread);
 					oobreadlen -= toread;
 				}
@@ -2080,7 +2071,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			break;
 
 		len = min(len, readlen);
-		buf = nand_transfer_oob(chip, buf, ops, len);
+		buf = nand_transfer_oob(mtd, buf, ops, len);
 
 		if (chip->options & NAND_NEED_READRDY) {
 			/* Apply delay or wait for ready/busy pin */
@@ -2239,19 +2230,20 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 				 const uint8_t *buf, int oob_required,
 				 int page)
 {
-	int i, eccsize = chip->ecc.size;
+	int i, eccsize = chip->ecc.size, ret;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	const uint8_t *p = buf;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	/* Software ECC calculation */
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
 }
@@ -2268,12 +2260,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 				  const uint8_t *buf, int oob_required,
 				  int page)
 {
-	int i, eccsize = chip->ecc.size;
+	int i, eccsize = chip->ecc.size, ret;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	const uint8_t *p = buf;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
@@ -2281,8 +2272,10 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 	}
 
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
 
@@ -2310,11 +2303,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 	int ecc_size      = chip->ecc.size;
 	int ecc_bytes     = chip->ecc.bytes;
 	int ecc_steps     = chip->ecc.steps;
-	uint32_t *eccpos  = chip->ecc.layout->eccpos;
 	uint32_t start_step = offset / ecc_size;
 	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
 	int oob_bytes       = mtd->oobsize / ecc_steps;
-	int step, i;
+	int step, ret;
 
 	for (step = 0; step < ecc_steps; step++) {
 		/* configure controller for WRITE access */
@@ -2342,8 +2334,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 	/* copy calculated ECC for whole page to chip->buffer->oob */
 	/* this include masked-value(0xFF) for unwritten subpages */
 	ecc_calc = chip->buffers->ecccalc;
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	/* write OOB buffer to NAND device */
 	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -2480,6 +2474,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
 			      struct mtd_oob_ops *ops)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
 
 	/*
 	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
@@ -2494,31 +2489,12 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
 		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
 		return oob + len;
 
-	case MTD_OPS_AUTO_OOB: {
-		struct nand_oobfree *free = chip->ecc.layout->oobfree;
-		uint32_t boffs = 0, woffs = ops->ooboffs;
-		size_t bytes = 0;
-
-		for (; free->length && len; free++, len -= bytes) {
-			/* Write request not from offset 0? */
-			if (unlikely(woffs)) {
-				if (woffs >= free->length) {
-					woffs -= free->length;
-					continue;
-				}
-				boffs = free->offset + woffs;
-				bytes = min_t(size_t, len,
-					      (free->length - woffs));
-				woffs = 0;
-			} else {
-				bytes = min_t(size_t, len, free->length);
-				boffs = free->offset;
-			}
-			memcpy(chip->oob_poi + boffs, oob, bytes);
-			oob += bytes;
-		}
-		return oob;
-	}
+	case MTD_OPS_AUTO_OOB:
+		ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
+						  ops->ooboffs, len);
+		BUG_ON(ret);
+		return oob + len;
+
 	default:
 		BUG();
 	}
@@ -4105,7 +4081,6 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
  */
 int nand_scan_tail(struct mtd_info *mtd)
 {
-	int i;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct nand_buffers *nbuf;
@@ -4309,20 +4284,10 @@ int nand_scan_tail(struct mtd_info *mtd)
 	if (!ecc->write_oob_raw)
 		ecc->write_oob_raw = ecc->write_oob;
 
-	/*
-	 * The number of bytes available for a client to place data into
-	 * the out of band area.
-	 */
-	mtd->oobavail = 0;
-	if (ecc->layout) {
-		for (i = 0; ecc->layout->oobfree[i].length; i++)
-			mtd->oobavail += ecc->layout->oobfree[i].length;
-	}
-
-	/* ECC sanity check: warn if it's too weak */
-	if (!nand_ecc_strength_good(mtd))
-		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
-			mtd->name);
+	/* propagate ecc info to mtd_info */
+	mtd->ecclayout = ecc->layout;
+	mtd->ecc_strength = ecc->strength;
+	mtd->ecc_step_size = ecc->size;
 
 	/*
 	 * Set the number of read / write steps for one page depending on ECC
@@ -4336,6 +4301,21 @@ int nand_scan_tail(struct mtd_info *mtd)
 	}
 	ecc->total = ecc->steps * ecc->bytes;
 
+	/*
+	 * The number of bytes available for a client to place data into
+	 * the out of band area.
+	 */
+	ret = mtd_ooblayout_count_freebytes(mtd);
+	if (ret < 0)
+		ret = 0;
+
+	mtd->oobavail = ret;
+
+	/* ECC sanity check: warn if it's too weak */
+	if (!nand_ecc_strength_good(mtd))
+		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+			mtd->name);
+
 	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
 	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
 		switch (ecc->steps) {
@@ -4392,10 +4372,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->_block_markbad = nand_block_markbad;
 	mtd->writebufsize = mtd->writesize;
 
-	/* propagate ecc info to mtd_info */
-	mtd->ecclayout = ecc->layout;
-	mtd->ecc_strength = ecc->strength;
-	mtd->ecc_step_size = ecc->size;
 	/*
 	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
 	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index b585bae..d8c03eb 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -196,7 +196,18 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 		printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
 		goto fail;
 	}
-	if (layout->eccbytes != (eccsteps*eccbytes)) {
+
+	/*
+	 * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
+	 * which is called by mtd_ooblayout_count_eccbytes().
+	 * Make sure they are properly initialized before calling
+	 * mtd_ooblayout_count_eccbytes().
+	 * FIXME: we should probaly rework the sequencing in nand_scan_tail()
+	 * to avoid setting those fields twice.
+	 */
+	nand->ecc.steps = eccsteps;
+	nand->ecc.total = eccsteps * eccbytes;
+	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
 		printk(KERN_WARNING "invalid ecc layout\n");
 		goto fail;
 	}


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: fsl_ifc: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000si-8D@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=9ed92dd29015de67041cf45f364a46f1fa84bf79
Commit:     9ed92dd29015de67041cf45f364a46f1fa84bf79
Parent:     78d28e8ec4fbd4d1e0c375d7a28f4f23e9e7b15e
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:11:32 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:50 2016 +0200

    mtd: nand: fsl_ifc: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_ifc_nand.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index f8a016f..1d922a0 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -257,18 +257,22 @@ static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
 	u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
 	u32 __iomem *mainarea = (u32 __iomem *)addr;
 	u8 __iomem *oob = addr + mtd->writesize;
-	int i;
+	struct mtd_oob_region oobregion = { };
+	int i, section = 0;
 
 	for (i = 0; i < mtd->writesize / 4; i++) {
 		if (__raw_readl(&mainarea[i]) != 0xffffffff)
 			return 0;
 	}
 
-	for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
-		int pos = chip->ecc.layout->eccpos[i];
+	mtd_ooblayout_ecc(mtd, section++, &oobregion);
+	while (oobregion.length) {
+		for (i = 0; i < oobregion.length; i++) {
+			if (__raw_readb(&oob[oobregion.offset + i]) != 0xff)
+				return 0;
+		}
 
-		if (__raw_readb(&oob[pos]) != 0xff)
-			return 0;
+		mtd_ooblayout_ecc(mtd, section++, &oobregion);
 	}
 
 	return 1;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: gpmi: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000t8-CA@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=191a82946a99fe110814860873cdfe64170c660b
Commit:     191a82946a99fe110814860873cdfe64170c660b
Parent:     9ed92dd29015de67041cf45f364a46f1fa84bf79
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:11:44 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:50 2016 +0200

    mtd: nand: gpmi: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index dcb60b0..4721008 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1328,18 +1328,19 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 static int
 gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
 {
-	struct nand_oobfree *of = mtd->ecclayout->oobfree;
+	struct mtd_oob_region of = { };
 	int status = 0;
 
 	/* Do we have available oob area? */
-	if (!of->length)
+	mtd_ooblayout_free(mtd, 0, &of);
+	if (!of.length)
 		return -EPERM;
 
 	if (!nand_is_slc(chip))
 		return -EPERM;
 
-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of->offset, page);
-	chip->write_buf(mtd, chip->oob_poi + of->offset, of->length);
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page);
+	chip->write_buf(mtd, chip->oob_poi + of.offset, of.length);
 	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
 	status = chip->waitfunc(mtd, chip);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: lpc32xx: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000ta-HH@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=b9c0f65feab8a6dd4f37fdd8150cf5fe716304f5
Commit:     b9c0f65feab8a6dd4f37fdd8150cf5fe716304f5
Parent:     191a82946a99fe110814860873cdfe64170c660b
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:12:04 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:51 2016 +0200

    mtd: nand: lpc32xx: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/lpc32xx_slc.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 3b8f373..10cf8e62 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -604,7 +604,8 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
 					   int oob_required, int page)
 {
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	int stat, i, status;
+	struct mtd_oob_region oobregion = { };
+	int stat, i, status, error;
 	uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
 
 	/* Issue read command */
@@ -620,7 +621,11 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
 	lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
 
 	/* Pointer to ECC data retrieved from NAND spare area */
-	oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0];
+	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	if (error)
+		return error;
+
+	oobecc = chip->oob_poi + oobregion.offset;
 
 	for (i = 0; i < chip->ecc.steps; i++) {
 		stat = chip->ecc.correct(mtd, buf, oobecc,
@@ -666,7 +671,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
 					    int oob_required, int page)
 {
 	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
+	struct mtd_oob_region oobregion = { };
+	uint8_t *pb;
 	int error;
 
 	/* Write data, calculate ECC on outbound data */
@@ -678,6 +684,11 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
 	 * The calculated ECC needs some manual work done to it before
 	 * committing it to NAND. Process the calculated ECC and place
 	 * the resultant values directly into the OOB buffer. */
+	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	if (error)
+		return error;
+
+	pb = chip->oob_poi + oobregion.offset;
 	lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
 
 	/* Write ECC data to device */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: qcom: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000uQ-RK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=aa02fcf555c8d42836584783288b33a2a0d40481
Commit:     aa02fcf555c8d42836584783288b33a2a0d40481
Parent:     8cfc1e8b68f3e0b144f17a94709c757c6db05b82
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 18 17:53:31 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:52 2016 +0200

    mtd: nand: qcom: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to ecclayout fields, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Tested-by: Archit Taneja <architt at codeaurora.org>
---
 drivers/mtd/nand/qcom_nandc.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index f3de983..4ea2cb7 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -1436,7 +1436,6 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	u8 *oob = chip->oob_poi;
-	int free_boff;
 	int data_size, oob_size;
 	int ret, status = 0;
 
@@ -1450,12 +1449,11 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
 
 	/* calculate the data and oob size for the last codeword/step */
 	data_size = ecc->size - ((ecc->steps - 1) << 2);
-	oob_size = ecc->steps << 2;
-
-	free_boff = ecc->layout->oobfree[0].offset;
+	oob_size = mtd->oobavail;
 
 	/* override new oob content to last codeword */
-	memcpy(nandc->data_buffer + data_size, oob + free_boff, oob_size);
+	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
+				    0, mtd->oobavail);
 
 	set_address(host, host->cw_size * (ecc->steps - 1), page);
 	update_rw_regs(host, 1, false);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:12 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:12 +0000
Subject: mtd: nand: omap2: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qy-0000u1-MV@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=8cfc1e8b68f3e0b144f17a94709c757c6db05b82
Commit:     8cfc1e8b68f3e0b144f17a94709c757c6db05b82
Parent:     b9c0f65feab8a6dd4f37fdd8150cf5fe716304f5
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:12:19 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:51 2016 +0200

    mtd: nand: omap2: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index c59bc85..38fe6b8 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1498,9 +1498,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
 static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 			       const uint8_t *buf, int oob_required, int page)
 {
-	int i;
+	int ret;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	/* Enable GPMC ecc engine */
 	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
@@ -1511,8 +1510,10 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 	/* Update ecc vector from GPMC result registers */
 	chip->ecc.calculate(mtd, buf, &ecc_calc[0]);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	/* Write ecc vector to OOB area */
 	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1539,10 +1540,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 {
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	uint32_t *eccpos = chip->ecc.layout->eccpos;
-	uint8_t *oob = &chip->oob_poi[eccpos[0]];
-	uint32_t oob_pos = mtd->writesize + chip->ecc.layout->eccpos[0];
-	int stat;
+	int stat, ret;
 	unsigned int max_bitflips = 0;
 
 	/* Enable GPMC ecc engine */
@@ -1552,13 +1550,18 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 	chip->read_buf(mtd, buf, mtd->writesize);
 
 	/* Read oob bytes */
-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
-	chip->read_buf(mtd, oob, chip->ecc.total);
+	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+		      mtd->writesize + BADBLOCK_MARKER_LENGTH, -1);
+	chip->read_buf(mtd, chip->oob_poi + BADBLOCK_MARKER_LENGTH,
+		       chip->ecc.total);
 
 	/* Calculate ecc bytes */
 	chip->ecc.calculate(mtd, buf, ecc_calc);
 
-	memcpy(ecc_code, &chip->oob_poi[eccpos[0]], chip->ecc.total);
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
 
 	stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: onenand: use mtd_ooblayout_xxx() helpers where appropriate
Message-ID: <E1b54Qz-0000us-0n@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d30aae6d5630c27fa461f9da9ba2f40ae59e3287
Commit:     d30aae6d5630c27fa461f9da9ba2f40ae59e3287
Parent:     aa02fcf555c8d42836584783288b33a2a0d40481
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:12:31 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:52 2016 +0200

    mtd: onenand: use mtd_ooblayout_xxx() helpers where appropriate
    
    The mtd_ooblayout_xxx() helper functions have been added to avoid direct
    accesses to the ecclayout field, and thus ease for future reworks.
    Use these helpers in all places where the oobfree[] and eccpos[] arrays
    where directly accessed.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/onenand/onenand_base.c | 75 ++++++++------------------------------
 1 file changed, 15 insertions(+), 60 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index af28bb3..20fdf8c 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1024,34 +1024,15 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
 				int thislen)
 {
 	struct onenand_chip *this = mtd->priv;
-	struct nand_oobfree *free;
-	int readcol = column;
-	int readend = column + thislen;
-	int lastgap = 0;
-	unsigned int i;
-	uint8_t *oob_buf = this->oob_buf;
-
-	free = this->ecclayout->oobfree;
-	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-		if (readcol >= lastgap)
-			readcol += free->offset - lastgap;
-		if (readend >= lastgap)
-			readend += free->offset - lastgap;
-		lastgap = free->offset + free->length;
-	}
-	this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
-	free = this->ecclayout->oobfree;
-	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-		int free_end = free->offset + free->length;
-		if (free->offset < readend && free_end > readcol) {
-			int st = max_t(int,free->offset,readcol);
-			int ed = min_t(int,free_end,readend);
-			int n = ed - st;
-			memcpy(buf, oob_buf + st, n);
-			buf += n;
-		} else if (column == 0)
-			break;
-	}
+	int ret;
+
+	this->read_bufferram(mtd, ONENAND_SPARERAM, this->oob_buf, 0,
+			     mtd->oobsize);
+	ret = mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf,
+					  column, thislen);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -1808,34 +1789,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
 static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
 				  const u_char *buf, int column, int thislen)
 {
-	struct onenand_chip *this = mtd->priv;
-	struct nand_oobfree *free;
-	int writecol = column;
-	int writeend = column + thislen;
-	int lastgap = 0;
-	unsigned int i;
-
-	free = this->ecclayout->oobfree;
-	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-		if (writecol >= lastgap)
-			writecol += free->offset - lastgap;
-		if (writeend >= lastgap)
-			writeend += free->offset - lastgap;
-		lastgap = free->offset + free->length;
-	}
-	free = this->ecclayout->oobfree;
-	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-		int free_end = free->offset + free->length;
-		if (free->offset < writeend && free_end > writecol) {
-			int st = max_t(int,free->offset,writecol);
-			int ed = min_t(int,free_end,writeend);
-			int n = ed - st;
-			memcpy(oob_buf + st, buf, n);
-			buf += n;
-		} else if (column == 0)
-			break;
-	}
-	return 0;
+	return mtd_ooblayout_set_databytes(mtd, buf, oob_buf, column, thislen);
 }
 
 /**
@@ -4037,10 +3991,11 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 	 * The number of bytes available for a client to place data into
 	 * the out of band area
 	 */
-	mtd->oobavail = 0;
-	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
-	    this->ecclayout->oobfree[i].length; i++)
-		mtd->oobavail += this->ecclayout->oobfree[i].length;
+	ret = mtd_ooblayout_count_freebytes(mtd);
+	if (ret < 0)
+		ret = 0;
+
+	mtd->oobavail = ret;
 
 	mtd->ecclayout = this->ecclayout;
 	mtd->ecc_strength = 1;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: use mtd_set_ecclayout() where appropriate
Message-ID: <E1b54Qz-0000wA-An@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f6a6da179308356cac0f1dde979b67094437ef16
Commit:     f6a6da179308356cac0f1dde979b67094437ef16
Parent:     036d6543f85319ffe96afad6de73d3a220917a63
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:13:26 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:53 2016 +0200

    mtd: use mtd_set_ecclayout() where appropriate
    
    Use the mtd_set_ecclayout() helper instead of directly assigning the
    mtd->ecclayout field.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/mtdconcat.c | 2 +-
 drivers/mtd/mtdpart.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 239a8c8..481565e 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c
 
 	}
 
-	concat->mtd.ecclayout = subdev[0]->ecclayout;
+	mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout);
 
 	concat->num_subdev = num_devs;
 	concat->mtd.name = name;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 08de4b2..f53d9d7 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -533,7 +533,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 			part->name);
 	}
 
-	slave->mtd.ecclayout = master->ecclayout;
+	mtd_set_ecclayout(&slave->mtd, master->ecclayout);
 	slave->mtd.ecc_step_size = master->ecc_step_size;
 	slave->mtd.ecc_strength = master->ecc_strength;
 	slave->mtd.bitflip_threshold = master->bitflip_threshold;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: add mtd_set_ecclayout() helper function
Message-ID: <E1b54Qz-0000vg-4p@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=036d6543f85319ffe96afad6de73d3a220917a63
Commit:     036d6543f85319ffe96afad6de73d3a220917a63
Parent:     d30aae6d5630c27fa461f9da9ba2f40ae59e3287
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 18:53:44 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:53 2016 +0200

    mtd: add mtd_set_ecclayout() helper function
    
    Add an mtd_set_ecclayout() helper function to avoid direct accesses to the
    mtd->ecclayout field. This will ease future reworks of ECC layout
    definition.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 include/linux/mtd/mtd.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 117ca1f..e62da84 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -286,6 +286,12 @@ int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
 int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
 int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
 
+static inline void mtd_set_ecclayout(struct mtd_info *mtd,
+				     struct nand_ecclayout *ecclayout)
+{
+	mtd->ecclayout = ecclayout;
+}
+
 static inline void mtd_set_of_node(struct mtd_info *mtd,
 				   struct device_node *np)
 {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: nand: use mtd_set_ecclayout() where appropriate
Message-ID: <E1b54Qz-0000we-Fd@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=70d105e4eec233d8f8758d604bfe6c411b6ded5f
Commit:     70d105e4eec233d8f8758d604bfe6c411b6ded5f
Parent:     f6a6da179308356cac0f1dde979b67094437ef16
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:13:50 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:54 2016 +0200

    mtd: nand: use mtd_set_ecclayout() where appropriate
    
    Use the mtd_set_ecclayout() helper instead of directly assigning the
    mtd->ecclayout field.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 24ed445..feb1448 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4285,7 +4285,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 		ecc->write_oob_raw = ecc->write_oob;
 
 	/* propagate ecc info to mtd_info */
-	mtd->ecclayout = ecc->layout;
+	mtd_set_ecclayout(mtd, ecc->layout);
 	mtd->ecc_strength = ecc->strength;
 	mtd->ecc_step_size = ecc->size;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: onenand: use mtd_set_ecclayout() where appropriate
Message-ID: <E1b54Qz-0000x8-Lz@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=eb8c2be581e0f6c98830bc9eee09905f9fefed32
Commit:     eb8c2be581e0f6c98830bc9eee09905f9fefed32
Parent:     70d105e4eec233d8f8758d604bfe6c411b6ded5f
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:14:03 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:54 2016 +0200

    mtd: onenand: use mtd_set_ecclayout() where appropriate
    
    Use the mtd_set_ecclayout() helper instead of directly assigning the
    mtd->ecclayout field.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/onenand/onenand_base.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 20fdf8c..d0fa505 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -3997,7 +3997,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 
 	mtd->oobavail = ret;
 
-	mtd->ecclayout = this->ecclayout;
+	mtd_set_ecclayout(mtd, this->ecclayout);
 	mtd->ecc_strength = 1;
 
 	/* Fill in remaining MTD driver data */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: docg3: use mtd_set_ecclayout() where appropriate
Message-ID: <E1b54Qz-0000xc-Po@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=06af3b023c016bf97e39fbe22087b1d974f9e474
Commit:     06af3b023c016bf97e39fbe22087b1d974f9e474
Parent:     eb8c2be581e0f6c98830bc9eee09905f9fefed32
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:14:14 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:55 2016 +0200

    mtd: docg3: use mtd_set_ecclayout() where appropriate
    
    Use the mtd_set_ecclayout() helper instead of directly assigning the
    mtd->ecclayout field.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Robert Jarzmik <robert.jarzmik at free.fr>
---
 drivers/mtd/devices/docg3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index e7b2e43..6b516e1 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -1857,7 +1857,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
 	mtd->_read_oob = doc_read_oob;
 	mtd->_write_oob = doc_write_oob;
 	mtd->_block_isbad = doc_block_isbad;
-	mtd->ecclayout = &docg3_oobinfo;
+	mtd_set_ecclayout(mtd, &docg3_oobinfo);
 	mtd->oobavail = 8;
 	mtd->ecc_strength = DOC_ECC_BCH_T;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:13 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:13 +0000
Subject: mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition
Message-ID: <E1b54Qz-0000y6-TY@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=adbbc3bc827eb1f43a932d783f09ba55c8ec8379
Commit:     adbbc3bc827eb1f43a932d783f09ba55c8ec8379
Parent:     06af3b023c016bf97e39fbe22087b1d974f9e474
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:01:31 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:55 2016 +0200

    mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition
    
    ECC layout definitions are currently exposed using the nand_ecclayout
    struct which embeds oobfree and eccpos arrays with predefined size.
    This approach was acceptable when NAND chips were providing relatively
    small OOB regions, but MLC and TLC now provide OOB regions of several
    hundreds of bytes, which implies a non negligible overhead for everybody
    even those who only need to support legacy NANDs.
    
    Create an mtd_ooblayout_ops interface providing the same functionality
    (expose the ECC and oobfree layout) without the need for this huge
    structure.
    
    The mtd->ecclayout is now deprecated and should be replaced by the
    equivalent mtd_ooblayout_ops. In the meantime we provide a wrapper around
    the ->ecclayout field to ease migration to this new model.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/mtdchar.c   |   4 +-
 drivers/mtd/mtdconcat.c |   2 +-
 drivers/mtd/mtdcore.c   | 165 +++++++++++++++++++++++++++++++++++-------------
 drivers/mtd/mtdpart.c   |  23 ++++++-
 include/linux/mtd/mtd.h |  32 ++++++++--
 5 files changed, 174 insertions(+), 52 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index cd64ab7..3fad2c7 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -888,7 +888,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 	{
 		struct nand_oobinfo oi;
 
-		if (!mtd->ecclayout)
+		if (!mtd->ooblayout)
 			return -EOPNOTSUPP;
 
 		ret = get_oobinfo(mtd, &oi);
@@ -982,7 +982,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 	{
 		struct nand_ecclayout_user *usrlay;
 
-		if (!mtd->ecclayout)
+		if (!mtd->ooblayout)
 			return -EOPNOTSUPP;
 
 		usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 481565e..d573606 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c
 
 	}
 
-	mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout);
+	mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);
 
 	concat->num_subdev = num_devs;
 	concat->mtd.name = name;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 0290c41..134ed2f 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1035,49 +1035,15 @@ EXPORT_SYMBOL_GPL(mtd_write_oob);
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
 		      struct mtd_oob_region *oobecc)
 {
-	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
-
 	memset(oobecc, 0, sizeof(*oobecc));
 
 	if (!mtd || section < 0)
 		return -EINVAL;
 
-	if (!mtd->ecclayout)
+	if (!mtd->ooblayout || !mtd->ooblayout->ecc)
 		return -ENOTSUPP;
 
-	/*
-	 * This logic allows us to reuse the ->ecclayout information and
-	 * expose them as ECC regions (as done for the OOB free regions).
-	 *
-	 * TODO: this should be dropped as soon as we get rid of the
-	 * ->ecclayout field.
-	 */
-	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
-		eccpos = mtd->ecclayout->eccpos[eccbyte];
-
-		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
-			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
-
-			if (eccpos + 1 == neccpos) {
-				length++;
-				continue;
-			}
-		}
-
-		if (section == cursection)
-			break;
-
-		length = 0;
-		cursection++;
-	}
-
-	if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
-		return -ERANGE;
-
-	oobecc->length = length + 1;
-	oobecc->offset = eccpos - length;
-
-	return 0;
+	return mtd->ooblayout->ecc(mtd, section, oobecc);
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
 
@@ -1106,16 +1072,10 @@ int mtd_ooblayout_free(struct mtd_info *mtd, int section,
 	if (!mtd || section < 0)
 		return -EINVAL;
 
-	if (!mtd->ecclayout)
+	if (!mtd->ooblayout || !mtd->ooblayout->free)
 		return -ENOTSUPP;
 
-	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
-		return -ERANGE;
-
-	oobfree->offset = mtd->ecclayout->oobfree[section].offset;
-	oobfree->length = mtd->ecclayout->oobfree[section].length;
-
-	return 0;
+	return mtd->ooblayout->free(mtd, section, oobfree);
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
 
@@ -1416,6 +1376,123 @@ int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
 
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation
+ * @mtd: MTD device structure
+ * @section: ECC section. Depending on the layout you may have all the ECC
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobecc: OOB region struct filled with the appropriate ECC position
+ *	    information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->eccpos information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section,
+			     struct mtd_oob_region *oobecc)
+{
+	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
+
+	if (!mtd->ecclayout)
+		return -ENOTSUPP;
+
+	/*
+	 * This logic allows us to reuse the ->ecclayout information and
+	 * expose them as ECC regions (as done for the OOB free regions).
+	 *
+	 * TODO: this should be dropped as soon as we get rid of the
+	 * ->ecclayout field.
+	 */
+	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
+		eccpos = mtd->ecclayout->eccpos[eccbyte];
+
+		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
+			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
+
+			if (eccpos + 1 == neccpos) {
+				length++;
+				continue;
+			}
+		}
+
+		if (section == cursection)
+			break;
+
+		length = 0;
+		cursection++;
+	}
+
+	if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
+		return -ERANGE;
+
+	oobecc->length = length + 1;
+	oobecc->offset = eccpos - length;
+
+	return 0;
+}
+
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation
+ * @mtd: MTD device structure
+ * @section: Free section. Depending on the layout you may have all the free
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobfree: OOB region struct filled with the appropriate free position
+ *	     information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->oobfree information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_free(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobfree)
+{
+	struct nand_ecclayout *layout = mtd->ecclayout;
+
+	if (!layout)
+		return -ENOTSUPP;
+
+	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE ||
+	    !layout->oobfree[section].length)
+		return -ERANGE;
+
+	oobfree->offset = layout->oobfree[section].offset;
+	oobfree->length = layout->oobfree[section].length;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = {
+	.ecc = mtd_ecclayout_ecc,
+	.free = mtd_ecclayout_free,
+};
+
+/**
+ * mtd_set_ecclayout - Attach an ecclayout to an MTD device
+ * @mtd: MTD device structure
+ * @ecclayout: The ecclayout to attach to the device
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
+{
+	if (!mtd || !ecclayout)
+		return;
+
+	mtd->ecclayout = ecclayout;
+	mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops);
+}
+EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
+
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index f53d9d7..1f13e32 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -317,6 +317,27 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return res;
 }
 
+static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	return mtd_ooblayout_ecc(part->master, section, oobregion);
+}
+
+static int part_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	return mtd_ooblayout_free(part->master, section, oobregion);
+}
+
+static const struct mtd_ooblayout_ops part_ooblayout_ops = {
+	.ecc = part_ooblayout_ecc,
+	.free = part_ooblayout_free,
+};
+
 static inline void free_partition(struct mtd_part *p)
 {
 	kfree(p->mtd.name);
@@ -533,7 +554,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 			part->name);
 	}
 
-	mtd_set_ecclayout(&slave->mtd, master->ecclayout);
+	mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
 	slave->mtd.ecc_step_size = master->ecc_step_size;
 	slave->mtd.ecc_strength = master->ecc_strength;
 	slave->mtd.bitflip_threshold = master->bitflip_threshold;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index e62da84..177bf31 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -101,6 +101,9 @@ struct mtd_oob_ops {
  * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
  * for export to user-space via the ECCGETLAYOUT ioctl.
  * nand_ecclayout should be expandable in the future simply by the above macros.
+ *
+ * This structure is now deprecated, you should use struct nand_ecclayout_ops
+ * to describe your OOB layout.
  */
 struct nand_ecclayout {
 	__u32 eccbytes;
@@ -123,6 +126,22 @@ struct mtd_oob_region {
 	u32 length;
 };
 
+/*
+ * struct mtd_ooblayout_ops - NAND OOB layout operations
+ * @ecc: function returning an ECC region in the OOB area.
+ *	 Should return -ERANGE if %section exceeds the total number of
+ *	 ECC sections.
+ * @free: function returning a free region in the OOB area.
+ *	  Should return -ERANGE if %section exceeds the total number of
+ *	  free sections.
+ */
+struct mtd_ooblayout_ops {
+	int (*ecc)(struct mtd_info *mtd, int section,
+		   struct mtd_oob_region *oobecc);
+	int (*free)(struct mtd_info *mtd, int section,
+		    struct mtd_oob_region *oobfree);
+};
+
 struct module;	/* only needed for owner field in mtd_info */
 
 struct mtd_info {
@@ -181,9 +200,12 @@ struct mtd_info {
 	const char *name;
 	int index;
 
-	/* ECC layout structure pointer - read only! */
+	/* [Deprecated] ECC layout structure pointer - read only! */
 	struct nand_ecclayout *ecclayout;
 
+	/* OOB layout description */
+	const struct mtd_ooblayout_ops *ooblayout;
+
 	/* the ecc step size. */
 	unsigned int ecc_step_size;
 
@@ -286,10 +308,12 @@ int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
 int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
 int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
 
-static inline void mtd_set_ecclayout(struct mtd_info *mtd,
-				     struct nand_ecclayout *ecclayout)
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
+
+static inline void mtd_set_ooblayout(struct mtd_info *mtd,
+				     const struct mtd_ooblayout_ops *ooblayout)
 {
-	mtd->ecclayout = ecclayout;
+	mtd->ooblayout = ooblayout;
 }
 
 static inline void mtd_set_of_node(struct mtd_info *mtd,


From linux-mtd at lists.infradead.org  Mon May 23 21:59:14 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:14 +0000
Subject: mtd: docg3: switch to mtd_ooblayout_ops
Message-ID: <E1b54R0-0000yX-48@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=1bd0b24737710697e0a850fb1983dcdce1d01196
Commit:     1bd0b24737710697e0a850fb1983dcdce1d01196
Parent:     adbbc3bc827eb1f43a932d783f09ba55c8ec8379
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:05:04 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:56 2016 +0200

    mtd: docg3: switch to mtd_ooblayout_ops
    
    Replace the nand_ecclayout definition by the equivalent mtd_ooblayout_ops
    definition.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Robert Jarzmik <robert.jarzmik at free.fr>
---
 drivers/mtd/devices/docg3.c | 46 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 6b516e1..b833e6c 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -67,16 +67,40 @@ module_param(reliable_mode, uint, 0);
 MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
 		 "2=reliable) : MLC normal operations are in normal mode");
 
-/**
- * struct docg3_oobinfo - DiskOnChip G3 OOB layout
- * @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC)
- * @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC)
- * @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
- */
-static struct nand_ecclayout docg3_oobinfo = {
-	.eccbytes = 8,
-	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
-	.oobfree = {{0, 7}, {15, 1} },
+static int docg3_ooblayout_ecc(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	/* byte 7 is Hamming ECC, byte 8-14 are BCH ECC */
+	oobregion->offset = 7;
+	oobregion->length = 8;
+
+	return 0;
+}
+
+static int docg3_ooblayout_free(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	/* free bytes: byte 0 until byte 6, byte 15 */
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 7;
+	} else {
+		oobregion->offset = 15;
+		oobregion->length = 1;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_docg3_ops = {
+	.ecc = docg3_ooblayout_ecc,
+	.free = docg3_ooblayout_free,
 };
 
 static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
@@ -1857,7 +1881,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
 	mtd->_read_oob = doc_read_oob;
 	mtd->_write_oob = doc_write_oob;
 	mtd->_block_isbad = doc_block_isbad;
-	mtd_set_ecclayout(mtd, &docg3_oobinfo);
+	mtd_set_ooblayout(mtd, &nand_ooblayout_docg3_ops);
 	mtd->oobavail = 8;
 	mtd->ecc_strength = DOC_ECC_BCH_T;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:14 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:14 +0000
Subject: mtd: nand: implement the default mtd_ooblayout_ops
Message-ID: <E1b54R0-0000yz-9S@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=41b207a70d3a86b9e2eede155e87838234c7cbd5
Commit:     41b207a70d3a86b9e2eede155e87838234c7cbd5
Parent:     1bd0b24737710697e0a850fb1983dcdce1d01196
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:06:15 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:56 2016 +0200

    mtd: nand: implement the default mtd_ooblayout_ops
    
    Replace the default nand_ecclayout definitions for large and small page
    devices with the equivalent mtd_ooblayout_ops.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 142 ++++++++++++++++++++++++++++---------------
 include/linux/mtd/nand.h     |   3 +
 2 files changed, 96 insertions(+), 49 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index feb1448..e8332ea 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -47,54 +47,96 @@
 #include <linux/mtd/partitions.h>
 #include <linux/of_mtd.h>
 
+static int nand_get_device(struct mtd_info *mtd, int new_state);
+
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+			     struct mtd_oob_ops *ops);
+
 /* Define default oob placement schemes for large and small page devices */
-static struct nand_ecclayout nand_oob_8 = {
-	.eccbytes = 3,
-	.eccpos = {0, 1, 2},
-	.oobfree = {
-		{.offset = 3,
-		 .length = 2},
-		{.offset = 6,
-		 .length = 2} }
-};
+static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-static struct nand_ecclayout nand_oob_16 = {
-	.eccbytes = 6,
-	.eccpos = {0, 1, 2, 3, 6, 7},
-	.oobfree = {
-		{.offset = 8,
-		 . length = 8} }
-};
+	if (section > 1)
+		return -ERANGE;
 
-static struct nand_ecclayout nand_oob_64 = {
-	.eccbytes = 24,
-	.eccpos = {
-		   40, 41, 42, 43, 44, 45, 46, 47,
-		   48, 49, 50, 51, 52, 53, 54, 55,
-		   56, 57, 58, 59, 60, 61, 62, 63},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 38} }
-};
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 4;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = ecc->total - 4;
+	}
 
-static struct nand_ecclayout nand_oob_128 = {
-	.eccbytes = 48,
-	.eccpos = {
-		   80, 81, 82, 83, 84, 85, 86, 87,
-		   88, 89, 90, 91, 92, 93, 94, 95,
-		   96, 97, 98, 99, 100, 101, 102, 103,
-		   104, 105, 106, 107, 108, 109, 110, 111,
-		   112, 113, 114, 115, 116, 117, 118, 119,
-		   120, 121, 122, 123, 124, 125, 126, 127},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 78} }
+	return 0;
+}
+
+static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->oobsize == 16) {
+		if (section)
+			return -ERANGE;
+
+		oobregion->length = 8;
+		oobregion->offset = 8;
+	} else {
+		oobregion->length = 2;
+		if (!section)
+			oobregion->offset = 3;
+		else
+			oobregion->offset = 6;
+	}
+
+	return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+	.ecc = nand_ooblayout_ecc_sp,
+	.free = nand_ooblayout_free_sp,
 };
+EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
 
-static int nand_get_device(struct mtd_info *mtd, int new_state);
+static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
-			     struct mtd_oob_ops *ops);
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = ecc->total;
+	oobregion->offset = mtd->oobsize - oobregion->length;
+
+	return 0;
+}
+
+static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = mtd->oobsize - ecc->total - 2;
+	oobregion->offset = 2;
+
+	return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+	.ecc = nand_ooblayout_ecc_lp,
+	.free = nand_ooblayout_free_lp,
+};
+EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
 
 static int check_offs_len(struct mtd_info *mtd,
 					loff_t ofs, uint64_t len)
@@ -4110,21 +4152,24 @@ int nand_scan_tail(struct mtd_info *mtd)
 	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
 
 	/*
+	 * Set the provided ECC layout. If ecc->layout is NULL, the MTD core
+	 * will just leave mtd->ooblayout to NULL, if it's not NULL, it will
+	 * set ->ooblayout to the default ecclayout wrapper.
+	 */
+	mtd_set_ecclayout(mtd, ecc->layout);
+
+	/*
 	 * If no default placement scheme is given, select an appropriate one.
 	 */
-	if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
+	if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
 		switch (mtd->oobsize) {
 		case 8:
-			ecc->layout = &nand_oob_8;
-			break;
 		case 16:
-			ecc->layout = &nand_oob_16;
+			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
 			break;
 		case 64:
-			ecc->layout = &nand_oob_64;
-			break;
 		case 128:
-			ecc->layout = &nand_oob_128;
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 			break;
 		default:
 			WARN(1, "No oob scheme defined for oobsize %d\n",
@@ -4285,7 +4330,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 		ecc->write_oob_raw = ecc->write_oob;
 
 	/* propagate ecc info to mtd_info */
-	mtd_set_ecclayout(mtd, ecc->layout);
 	mtd->ecc_strength = ecc->strength;
 	mtd->ecc_step_size = ecc->size;
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7e06afb..f2ded7b 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -748,6 +748,9 @@ struct nand_chip {
 	void *priv;
 };
 
+extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
+extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
+
 static inline void nand_set_flash_node(struct nand_chip *chip,
 				       struct device_node *np)
 {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:14 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:14 +0000
Subject: mtd: nand: bch: switch to mtd_ooblayout_ops
Message-ID: <E1b54R0-0000zT-Dr@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=7cf9c19a836a79c60deef63714cb2880246d9a85
Commit:     7cf9c19a836a79c60deef63714cb2880246d9a85
Parent:     41b207a70d3a86b9e2eede155e87838234c7cbd5
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:53:40 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:26 2016 +0200

    mtd: nand: bch: switch to mtd_ooblayout_ops
    
    Replace the nand_ecclayout definition by the equivalent mtd_ooblayout_ops
    definition.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 15 +++++++++++++++
 drivers/mtd/nand/nand_bch.c  | 41 +++++++++++------------------------------
 2 files changed, 26 insertions(+), 30 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e8332ea..6c84a40 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4294,6 +4294,21 @@ int nand_scan_tail(struct mtd_info *mtd)
 			ecc->strength = 4;
 		}
 
+		/*
+		 * if no ecc placement scheme was provided pickup the default
+		 * large page one.
+		 */
+		if (!mtd->ooblayout) {
+			/* handle large page devices only */
+			if (mtd->oobsize < 64) {
+				WARN(1, "OOB layout is required when using software BCH on small pages\n");
+				ret = -EINVAL;
+				goto err_free;
+			}
+
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+		}
+
 		/* See nand_bch_init() for details. */
 		ecc->bytes = 0;
 		ecc->priv = nand_bch_init(mtd);
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index d8c03eb..1dbc418 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -32,13 +32,11 @@
 /**
  * struct nand_bch_control - private NAND BCH control structure
  * @bch:       BCH control structure
- * @ecclayout: private ecc layout for this BCH configuration
  * @errloc:    error location array
  * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
  */
 struct nand_bch_control {
 	struct bch_control   *bch;
-	struct nand_ecclayout ecclayout;
 	unsigned int         *errloc;
 	unsigned char        *eccmask;
 };
@@ -124,7 +122,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 {
 	struct nand_chip *nand = mtd_to_nand(mtd);
 	unsigned int m, t, eccsteps, i;
-	struct nand_ecclayout *layout = nand->ecc.layout;
 	struct nand_bch_control *nbc = NULL;
 	unsigned char *erased_page;
 	unsigned int eccsize = nand->ecc.size;
@@ -161,34 +158,18 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 
 	eccsteps = mtd->writesize/eccsize;
 
-	/* if no ecc placement scheme was provided, build one */
-	if (!layout) {
-
-		/* handle large page devices only */
-		if (mtd->oobsize < 64) {
-			printk(KERN_WARNING "must provide an oob scheme for "
-			       "oobsize %d\n", mtd->oobsize);
-			goto fail;
-		}
-
-		layout = &nbc->ecclayout;
-		layout->eccbytes = eccsteps*eccbytes;
-
-		/* reserve 2 bytes for bad block marker */
-		if (layout->eccbytes+2 > mtd->oobsize) {
-			printk(KERN_WARNING "no suitable oob scheme available "
-			       "for oobsize %d eccbytes %u\n", mtd->oobsize,
-			       eccbytes);
-			goto fail;
-		}
-		/* put ecc bytes at oob tail */
-		for (i = 0; i < layout->eccbytes; i++)
-			layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
-
-		layout->oobfree[0].offset = 2;
-		layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
+	/*
+	 * Rely on the default ecclayout to ooblayout wrapper provided by MTD
+	 * core if ecc.layout is not NULL.
+	 * FIXME: this should be removed when all callers have moved to the
+	 * mtd_ooblayout_ops approach.
+	 */
+	mtd_set_ecclayout(mtd, nand->ecc.layout);
 
-		nand->ecc.layout = layout;
+	/* Check that we have an oob layout description. */
+	if (!mtd->ooblayout) {
+		pr_warn("missing oob scheme");
+		goto fail;
 	}
 
 	/* sanity checks */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:06 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:06 +0000
Subject: mtd: nand: gpio: set ECC algorithm explicitly
Message-ID: <E1b54Qs-0000d7-Tu@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=050658c8f9bd8d7b2addf40f6a5b340d5d4ec21a
Commit:     050658c8f9bd8d7b2addf40f6a5b340d5d4ec21a
Parent:     e58dd3c33d3046c3ad3c849cb95365b45b9ecb5f
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:45 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:31 2016 +0200

    mtd: nand: gpio: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/gpio.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
index ded658f..6317f68 100644
--- a/drivers/mtd/nand/gpio.c
+++ b/drivers/mtd/nand/gpio.c
@@ -273,6 +273,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
 	nand_set_flash_node(chip, pdev->dev.of_node);
 	chip->IO_ADDR_W		= chip->IO_ADDR_R;
 	chip->ecc.mode		= NAND_ECC_SOFT;
+	chip->ecc.algo		= NAND_ECC_HAMMING;
 	chip->options		= gpiomtd->plat.options;
 	chip->chip_delay	= gpiomtd->plat.chip_delay;
 	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:07 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:07 +0000
Subject: mtd: nand: mxc: set ECC algorithm explicitly
Message-ID: <E1b54Qt-0000dY-3Z@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c1c7040e072caac6445a1e298bd1fc5e8da0a5f5
Commit:     c1c7040e072caac6445a1e298bd1fc5e8da0a5f5
Parent:     050658c8f9bd8d7b2addf40f6a5b340d5d4ec21a
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 8 12:23:46 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Apr 19 22:05:32 2016 +0200

    mtd: nand: mxc: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/mxc_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 854c832..57b1b74 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1585,6 +1585,7 @@ static int mxcnd_probe(struct platform_device *pdev)
 		this->ecc.mode = NAND_ECC_HW;
 	} else {
 		this->ecc.mode = NAND_ECC_SOFT;
+		this->ecc.algo = NAND_ECC_HAMMING;
 	}
 
 	/* NAND bus width determines access functions used by upper layer */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:14 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:14 +0000
Subject: mtd: nand: sharpsl: switch to mtd_ooblayout_ops
Message-ID: <E1b54R0-0000zw-JL@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e5b2d30e42e66122c9b1b17529df743bc938c041
Commit:     e5b2d30e42e66122c9b1b17529df743bc938c041
Parent:     7cf9c19a836a79c60deef63714cb2880246d9a85
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:58:11 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:36 2016 +0200

    mtd: nand: sharpsl: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 arch/arm/mach-pxa/spitz.c   | 55 ++++++++++++++++++++++++++++++++++++---------
 drivers/mtd/nand/sharpsl.c  |  2 +-
 include/linux/mtd/sharpsl.h |  2 +-
 3 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index d9578bc..bd7cd8b 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -763,14 +763,49 @@ static struct nand_bbt_descr spitz_nand_bbt = {
 	.pattern	= scan_ff_pattern
 };
 
-static struct nand_ecclayout akita_oobinfo = {
-	.oobfree	= { {0x08, 0x09} },
-	.eccbytes	= 24,
-	.eccpos		= {
-			0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
-			0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
-			0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
-	},
+static int akita_ooblayout_ecc(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section > 12)
+		return -ERANGE;
+
+	switch (section % 3) {
+	case 0:
+		oobregion->offset = 5;
+		oobregion->length = 1;
+		break;
+
+	case 1:
+		oobregion->offset = 1;
+		oobregion->length = 3;
+		break;
+
+	case 2:
+		oobregion->offset = 6;
+		oobregion->length = 2;
+		break;
+	}
+
+	oobregion->offset += (section / 3) * 0x10;
+
+	return 0;
+}
+
+static int akita_ooblayout_free(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = 9;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops akita_ooblayout_ops = {
+	.ecc = akita_ooblayout_ecc,
+	.free = akita_ooblayout_free,
 };
 
 static struct sharpsl_nand_platform_data spitz_nand_pdata = {
@@ -804,11 +839,11 @@ static void __init spitz_nand_init(void)
 	} else if (machine_is_akita()) {
 		spitz_nand_partitions[1].size = 58 * 1024 * 1024;
 		spitz_nand_bbt.len = 1;
-		spitz_nand_pdata.ecc_layout = &akita_oobinfo;
+		spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
 	} else if (machine_is_borzoi()) {
 		spitz_nand_partitions[1].size = 32 * 1024 * 1024;
 		spitz_nand_bbt.len = 1;
-		spitz_nand_pdata.ecc_layout = &akita_oobinfo;
+		spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
 	}
 
 	platform_device_register(&spitz_nand_device);
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index b7d1b55..064ca17 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -148,6 +148,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 	/* Link the private data with the MTD structure */
 	mtd = nand_to_mtd(this);
 	mtd->dev.parent = &pdev->dev;
+	mtd_set_ooblayout(mtd, data->ecc_layout);
 
 	platform_set_drvdata(pdev, sharpsl);
 
@@ -170,7 +171,6 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 	this->ecc.bytes = 3;
 	this->ecc.strength = 1;
 	this->badblock_pattern = data->badblock_pattern;
-	this->ecc.layout = data->ecc_layout;
 	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
 	this->ecc.calculate = sharpsl_nand_calculate_ecc;
 	this->ecc.correct = nand_correct_data;
diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h
index 25f4d2a..65e91d0 100644
--- a/include/linux/mtd/sharpsl.h
+++ b/include/linux/mtd/sharpsl.h
@@ -14,7 +14,7 @@
 
 struct sharpsl_nand_platform_data {
 	struct nand_bbt_descr	*badblock_pattern;
-	struct nand_ecclayout	*ecc_layout;
+	const struct mtd_ooblayout_ops *ecc_layout;
 	struct mtd_partition	*partitions;
 	unsigned int		nr_partitions;
 };


From linux-mtd at lists.infradead.org  Mon May 23 21:59:14 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:14 +0000
Subject: mtd: nand: jz4740: switch to mtd_ooblayout_ops
Message-ID: <E1b54R0-00010S-Pw@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=50533187eed5ace8d06e0e04aeea8fea1b70b8d7
Commit:     50533187eed5ace8d06e0e04aeea8fea1b70b8d7
Parent:     e5b2d30e42e66122c9b1b17529df743bc938c041
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:58:55 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:37 2016 +0200

    mtd: nand: jz4740: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Lars-Peter Clausen <lars at metafoo.de>
---
 arch/mips/include/asm/mach-jz4740/jz4740_nand.h |  2 +-
 arch/mips/jz4740/board-qi_lb60.c                | 87 +++++++++++++++----------
 drivers/mtd/nand/jz4740_nand.c                  |  2 +-
 3 files changed, 53 insertions(+), 38 deletions(-)

diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
index 398733e..7f7b0fc 100644
--- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -27,7 +27,7 @@ struct jz_nand_platform_data {
 
 	unsigned char banks[JZ_NAND_NUM_BANKS];
 
-	void (*ident_callback)(struct platform_device *, struct nand_chip *,
+	void (*ident_callback)(struct platform_device *, struct mtd_info *,
 				struct mtd_partition **, int *num_partitions);
 };
 
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 934b15b..a1c1afb 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -50,20 +50,6 @@ static bool is_avt2;
 #define QI_LB60_GPIO_KEYIN8		JZ_GPIO_PORTD(26)
 
 /* NAND */
-static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
-	.eccbytes = 36,
-	.eccpos = {
-		6,  7,	8,  9,	10, 11, 12, 13,
-		14, 15, 16, 17, 18, 19, 20, 21,
-		22, 23, 24, 25, 26, 27, 28, 29,
-		30, 31, 32, 33, 34, 35, 36, 37,
-		38, 39, 40, 41
-	},
-	.oobfree = {
-		{ .offset = 2, .length = 4 },
-		{ .offset = 42, .length = 22 }
-	},
-};
 
 /* Early prototypes of the QI LB60 had only 1GB of NAND.
  * In order to support these devices as well the partition and ecc layout is
@@ -86,25 +72,6 @@ static struct mtd_partition qi_lb60_partitions_1gb[] = {
 	},
 };
 
-static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
-	.eccbytes = 72,
-	.eccpos = {
-		12, 13, 14, 15, 16, 17, 18, 19,
-		20, 21, 22, 23, 24, 25, 26, 27,
-		28, 29, 30, 31, 32, 33, 34, 35,
-		36, 37, 38, 39, 40, 41, 42, 43,
-		44, 45, 46, 47, 48, 49, 50, 51,
-		52, 53, 54, 55, 56, 57, 58, 59,
-		60, 61, 62, 63, 64, 65, 66, 67,
-		68, 69, 70, 71, 72, 73, 74, 75,
-		76, 77, 78, 79, 80, 81, 82, 83
-	},
-	.oobfree = {
-		{ .offset = 2, .length = 10 },
-		{ .offset = 84, .length = 44 },
-	},
-};
-
 static struct mtd_partition qi_lb60_partitions_2gb[] = {
 	{
 		.name = "NAND BOOT partition",
@@ -123,19 +90,67 @@ static struct mtd_partition qi_lb60_partitions_2gb[] = {
 	},
 };
 
+static int qi_lb60_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 36;
+	oobregion->offset = 6;
+
+	if (mtd->oobsize == 128) {
+		oobregion->length *= 2;
+		oobregion->offset *= 2;
+	}
+
+	return 0;
+}
+
+static int qi_lb60_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	int eccbytes = 36, eccoff = 6;
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->oobsize == 128) {
+		eccbytes *= 2;
+		eccoff *= 2;
+	}
+
+	if (!section) {
+		oobregion->offset = 2;
+		oobregion->length = eccoff - 2;
+	} else {
+		oobregion->offset = eccoff + eccbytes;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = {
+	.ecc = qi_lb60_ooblayout_ecc,
+	.free = qi_lb60_ooblayout_free,
+};
+
 static void qi_lb60_nand_ident(struct platform_device *pdev,
-		struct nand_chip *chip, struct mtd_partition **partitions,
+		struct mtd_info *mtd, struct mtd_partition **partitions,
 		int *num_partitions)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
 	if (chip->page_shift == 12) {
-		chip->ecc.layout = &qi_lb60_ecclayout_2gb;
 		*partitions = qi_lb60_partitions_2gb;
 		*num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
 	} else {
-		chip->ecc.layout = &qi_lb60_ecclayout_1gb;
 		*partitions = qi_lb60_partitions_1gb;
 		*num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
 	}
+
+	mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
 }
 
 static struct jz_nand_platform_data qi_lb60_nand_pdata = {
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 673ceb2..df74408 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -476,7 +476,7 @@ static int jz_nand_probe(struct platform_device *pdev)
 	}
 
 	if (pdata && pdata->ident_callback) {
-		pdata->ident_callback(pdev, chip, &pdata->partitions,
+		pdata->ident_callback(pdev, mtd, &pdata->partitions,
 					&pdata->num_partitions);
 	}
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: atmel: switch to mtd_ooblayout_ops
Message-ID: <E1b54R0-00010w-VJ@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=cc00383722db7a4b75e005f5bb8b08b4d874ed00
Commit:     cc00383722db7a4b75e005f5bb8b08b4d874ed00
Parent:     50533187eed5ace8d06e0e04aeea8fea1b70b8d7
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:59:11 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:37 2016 +0200

    mtd: nand: atmel: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Reviewed-by: Nicolas Ferre <nicolas.ferre at atmel.com>
---
 drivers/mtd/nand/atmel_nand.c | 84 ++++++++++++++++++++-----------------------
 1 file changed, 38 insertions(+), 46 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index b132c8f..eec8ca7 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -71,30 +71,44 @@ struct atmel_nand_nfc_caps {
 	uint32_t rb_mask;
 };
 
-/* oob layout for large page size
+/*
+ * 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 atmel_oobinfo_large = {
-	.eccbytes = 4,
-	.eccpos = {60, 61, 62, 63},
-	.oobfree = {
-		{2, 58}
-	},
-};
-
-/* oob layout for small page size
+ *
+ * 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 atmel_oobinfo_small = {
-	.eccbytes = 4,
-	.eccpos = {0, 1, 2, 3},
-	.oobfree = {
-		{6, 10}
-	},
+static int atmel_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 4;
+	oobregion->offset = 0;
+
+	return 0;
+}
+
+static int atmel_ooblayout_free_sp(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 6;
+	oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops atmel_ooblayout_sp_ops = {
+	.ecc = atmel_ooblayout_ecc_sp,
+	.free = atmel_ooblayout_free_sp,
 };
 
 struct atmel_nfc {
@@ -162,8 +176,6 @@ struct atmel_nand_host {
 	int			*pmecc_delta;
 };
 
-static struct nand_ecclayout atmel_pmecc_oobinfo;
-
 /*
  * Enable NAND.
  */
@@ -480,22 +492,6 @@ static int pmecc_get_ecc_bytes(int cap, int sector_size)
 	return (m * cap + 7) / 8;
 }
 
-static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
-				    int oobsize, int ecc_len)
-{
-	int i;
-
-	layout->eccbytes = ecc_len;
-
-	/* ECC will occupy the last ecc_len bytes continuously */
-	for (i = 0; i < ecc_len; i++)
-		layout->eccpos[i] = oobsize - ecc_len + i;
-
-	layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES;
-	layout->oobfree[0].length =
-		oobsize - ecc_len - layout->oobfree[0].offset;
-}
-
 static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 {
 	int table_size;
@@ -1012,8 +1008,8 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
 {
 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
+	int eccbytes = mtd_ooblayout_count_eccbytes(mtd);
 	uint32_t val = 0;
-	struct nand_ecclayout *ecc_layout;
 	struct mtd_oob_region oobregion;
 
 	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
@@ -1064,12 +1060,11 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
 		| PMECC_CFG_AUTO_DISABLE);
 	pmecc_writel(host->ecc, CFG, val);
 
-	ecc_layout = nand_chip->ecc.layout;
 	pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
 	mtd_ooblayout_ecc(mtd, 0, &oobregion);
 	pmecc_writel(host->ecc, SADDR, oobregion.offset);
 	pmecc_writel(host->ecc, EADDR,
-		     oobregion.offset + ecc_layout->eccbytes - 1);
+		     oobregion.offset + eccbytes - 1);
 	/* See datasheet about PMECC Clock Control Register */
 	pmecc_writel(host->ecc, CLK, 2);
 	pmecc_writel(host->ecc, IDR, 0xff);
@@ -1291,11 +1286,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
 			err_no = -EINVAL;
 			goto err;
 		}
-		pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
-					mtd->oobsize,
-					nand_chip->ecc.total);
 
-		nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 		break;
 	default:
 		dev_warn(host->dev,
@@ -1650,19 +1642,19 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
 	/* set ECC page size and oob layout */
 	switch (mtd->writesize) {
 	case 512:
-		nand_chip->ecc.layout = &atmel_oobinfo_small;
+		mtd_set_ooblayout(mtd, &atmel_ooblayout_sp_ops);
 		ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
 		break;
 	case 1024:
-		nand_chip->ecc.layout = &atmel_oobinfo_large;
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 		ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
 		break;
 	case 2048:
-		nand_chip->ecc.layout = &atmel_oobinfo_large;
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 		ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
 		break;
 	case 4096:
-		nand_chip->ecc.layout = &atmel_oobinfo_large;
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 		ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
 		break;
 	default:


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: bf5xx: switch to mtd_ooblayout_ops
Message-ID: <E1b54R1-00011h-4j@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c8766e81ca3a224b092d087f6e1d77bf2c3d665d
Commit:     c8766e81ca3a224b092d087f6e1d77bf2c3d665d
Parent:     cc00383722db7a4b75e005f5bb8b08b4d874ed00
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:59:25 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:38 2016 +0200

    mtd: nand: bf5xx: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/bf5xx_nand.c | 51 ++++++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 7f6b30e..b38f414 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -109,28 +109,33 @@ static const unsigned short bfin_nfc_pin_req[] =
 	 0};
 
 #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-static struct nand_ecclayout bootrom_ecclayout = {
-	.eccbytes = 24,
-	.eccpos = {
-		0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2,
-		0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2,
-		0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2,
-		0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2,
-		0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2,
-		0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2,
-		0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2,
-		0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2
-	},
-	.oobfree = {
-		{ 0x8 * 0 + 3, 5 },
-		{ 0x8 * 1 + 3, 5 },
-		{ 0x8 * 2 + 3, 5 },
-		{ 0x8 * 3 + 3, 5 },
-		{ 0x8 * 4 + 3, 5 },
-		{ 0x8 * 5 + 3, 5 },
-		{ 0x8 * 6 + 3, 5 },
-		{ 0x8 * 7 + 3, 5 },
-	}
+static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = section * 8;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = (section * 8) + 3;
+	oobregion->length = 5;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
+	.ecc = bootrom_ooblayout_ecc,
+	.free = bootrom_ooblayout_free,
 };
 #endif
 
@@ -800,7 +805,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 	/* setup hardware ECC data struct */
 	if (hardware_ecc) {
 #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-		chip->ecc.layout = &bootrom_ecclayout;
+		mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
 #endif
 		chip->read_buf      = bf5xx_nand_dma_read_buf;
 		chip->write_buf     = bf5xx_nand_dma_write_buf;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: brcm: switch to mtd_ooblayout_ops
Message-ID: <E1b54R1-00012D-9W@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ef5eeea6e911540bbf51a283fe0ffb7389cbe66a
Commit:     ef5eeea6e911540bbf51a283fe0ffb7389cbe66a
Parent:     c8766e81ca3a224b092d087f6e1d77bf2c3d665d
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:59:36 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:38 2016 +0200

    mtd: nand: brcm: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/brcmnand/brcmnand.c | 258 +++++++++++++++++++++--------------
 1 file changed, 157 insertions(+), 101 deletions(-)

diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index e5f281f..c3331ff 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -780,127 +780,183 @@ static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
 }
 
 /*
- * Returns a nand_ecclayout strucutre for the given layout/configuration.
- * Returns NULL on failure.
+ * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
+ * the layout/configuration.
+ * Returns -ERRCODE on failure.
  */
-static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
-						     struct brcmnand_host *host)
+static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
 	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int i, j;
-	struct nand_ecclayout *layout;
-	int req;
-	int sectors;
-	int sas;
-	int idx1, idx2;
-
-	layout = devm_kzalloc(&host->pdev->dev, sizeof(*layout), GFP_KERNEL);
-	if (!layout)
-		return NULL;
-
-	sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-	sas = cfg->spare_area_size << cfg->sector_size_1k;
-
-	/* Hamming */
-	if (is_hamming_ecc(cfg)) {
-		for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
-			/* First sector of each page may have BBI */
-			if (i == 0) {
-				layout->oobfree[idx2].offset = i * sas + 1;
-				/* Small-page NAND use byte 6 for BBI */
-				if (cfg->page_size == 512)
-					layout->oobfree[idx2].offset--;
-				layout->oobfree[idx2].length = 5;
-			} else {
-				layout->oobfree[idx2].offset = i * sas;
-				layout->oobfree[idx2].length = 6;
-			}
-			idx2++;
-			layout->eccpos[idx1++] = i * sas + 6;
-			layout->eccpos[idx1++] = i * sas + 7;
-			layout->eccpos[idx1++] = i * sas + 8;
-			layout->oobfree[idx2].offset = i * sas + 9;
-			layout->oobfree[idx2].length = 7;
-			idx2++;
-			/* Leave zero-terminated entry for OOBFREE */
-			if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
-				    idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
-				break;
-		}
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
 
-		return layout;
-	}
+	if (section >= sectors)
+		return -ERANGE;
 
-	/*
-	 * CONTROLLER_VERSION:
-	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
-	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
-	 * But we will just be conservative.
-	 */
-	req = DIV_ROUND_UP(ecc_level * 14, 8);
-	if (req >= sas) {
-		dev_err(&host->pdev->dev,
-			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
-			req, sas);
-		return NULL;
-	}
+	oobregion->offset = (section * sas) + 6;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
+					   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors * 2)
+		return -ERANGE;
 
-	layout->eccbytes = req * sectors;
-	for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
-		for (j = sas - req; j < sas && idx1 <
-				MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++)
-			layout->eccpos[idx1] = i * sas + j;
+	oobregion->offset = (section / 2) * sas;
+
+	if (section & 1) {
+		oobregion->offset += 9;
+		oobregion->length = 7;
+	} else {
+		oobregion->length = 6;
 
 		/* First sector of each page may have BBI */
-		if (i == 0) {
-			if (cfg->page_size == 512 && (sas - req >= 6)) {
-				/* Small-page NAND use byte 6 for BBI */
-				layout->oobfree[idx2].offset = 0;
-				layout->oobfree[idx2].length = 5;
-				idx2++;
-				if (sas - req > 6) {
-					layout->oobfree[idx2].offset = 6;
-					layout->oobfree[idx2].length =
-						sas - req - 6;
-					idx2++;
-				}
-			} else if (sas > req + 1) {
-				layout->oobfree[idx2].offset = i * sas + 1;
-				layout->oobfree[idx2].length = sas - req - 1;
-				idx2++;
-			}
-		} else if (sas > req) {
-			layout->oobfree[idx2].offset = i * sas;
-			layout->oobfree[idx2].length = sas - req;
-			idx2++;
+		if (!section) {
+			/*
+			 * Small-page NAND use byte 6 for BBI while large-page
+			 * NAND use byte 0.
+			 */
+			if (cfg->page_size > 512)
+				oobregion->offset++;
+			oobregion->length--;
 		}
-		/* Leave zero-terminated entry for OOBFREE */
-		if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
-				idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
-			break;
 	}
 
-	return layout;
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
+	.ecc = brcmnand_hamming_ooblayout_ecc,
+	.free = brcmnand_hamming_ooblayout_free,
+};
+
+static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors)
+		return -ERANGE;
+
+	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
 }
 
-static struct nand_ecclayout *brcmstb_choose_ecc_layout(
-		struct brcmnand_host *host)
+static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors)
+		return -ERANGE;
+
+	if (sas <= chip->ecc.bytes)
+		return 0;
+
+	oobregion->offset = section * sas;
+	oobregion->length = sas - chip->ecc.bytes;
+
+	if (!section) {
+		oobregion->offset++;
+		oobregion->length--;
+	}
+
+	return 0;
+}
+
+static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+
+	if (section > 1 || sas - chip->ecc.bytes < 6 ||
+	    (section && sas - chip->ecc.bytes == 6))
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 5;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = sas - chip->ecc.bytes - 6;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
+	.ecc = brcmnand_bch_ooblayout_ecc,
+	.free = brcmnand_bch_ooblayout_free_lp,
+};
+
+static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
+	.ecc = brcmnand_bch_ooblayout_ecc,
+	.free = brcmnand_bch_ooblayout_free_sp,
+};
+
+static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
 {
-	struct nand_ecclayout *layout;
 	struct brcmnand_cfg *p = &host->hwcfg;
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct nand_ecc_ctrl *ecc = &host->chip.ecc;
 	unsigned int ecc_level = p->ecc_level;
+	int sas = p->spare_area_size << p->sector_size_1k;
+	int sectors = p->page_size / (512 << p->sector_size_1k);
 
 	if (p->sector_size_1k)
 		ecc_level <<= 1;
 
-	layout = brcmnand_create_layout(ecc_level, host);
-	if (!layout) {
+	if (is_hamming_ecc(p)) {
+		ecc->bytes = 3 * sectors;
+		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
+		return 0;
+	}
+
+	/*
+	 * CONTROLLER_VERSION:
+	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
+	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
+	 * But we will just be conservative.
+	 */
+	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
+	if (p->page_size == 512)
+		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
+	else
+		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
+
+	if (ecc->bytes >= sas) {
 		dev_err(&host->pdev->dev,
-				"no proper ecc_layout for this NAND cfg\n");
-		return NULL;
+			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
+			ecc->bytes, sas);
+		return -EINVAL;
 	}
 
-	return layout;
+	return 0;
 }
 
 static void brcmnand_wp(struct mtd_info *mtd, int wp)
@@ -2010,9 +2066,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
 	/* only use our internal HW threshold */
 	mtd->bitflip_threshold = 1;
 
-	chip->ecc.layout = brcmstb_choose_ecc_layout(host);
-	if (!chip->ecc.layout)
-		return -ENXIO;
+	ret = brcmstb_choose_ecc_layout(host);
+	if (ret)
+		return ret;
 
 	if (nand_scan_tail(mtd))
 		return -ENXIO;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: davinci: switch to mtd_ooblayout_ops
Message-ID: <E1b54R1-00013G-LK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e4aacaa1b175cd53db0c6c7f033bb0fe02df6ea5
Commit:     e4aacaa1b175cd53db0c6c7f033bb0fe02df6ea5
Parent:     a8ed6e66f3b04d804fae425023aa4e7615dadab7
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:59:58 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:39 2016 +0200

    mtd: nand: davinci: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/davinci_nand.c | 118 +++++++++++++++-------------------------
 1 file changed, 44 insertions(+), 74 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 8cb821b..fe3fd29 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -54,7 +54,6 @@
  */
 struct davinci_nand_info {
 	struct nand_chip	chip;
-	struct nand_ecclayout	ecclayout;
 
 	struct device		*dev;
 	struct clk		*clk;
@@ -480,63 +479,46 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
  * ten ECC bytes plus the manufacturer's bad block marker byte, and
  * and not overlapping the default BBT markers.
  */
-static struct nand_ecclayout hwecc4_small = {
-	.eccbytes = 10,
-	.eccpos = { 0, 1, 2, 3, 4,
-		/* offset 5 holds the badblock marker */
-		6, 7,
-		13, 14, 15, },
-	.oobfree = {
-		{.offset = 8, .length = 5, },
-		{.offset = 16, },
-	},
-};
+static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section > 2)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 5;
+	} else if (section == 1) {
+		oobregion->offset = 6;
+		oobregion->length = 2;
+	} else {
+		oobregion->offset = 13;
+		oobregion->length = 3;
+	}
 
-/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash,
- * storing ten ECC bytes plus the manufacturer's bad block marker byte,
- * and not overlapping the default BBT markers.
- */
-static struct nand_ecclayout hwecc4_2048 = {
-	.eccbytes = 40,
-	.eccpos = {
-		/* at the end of spare sector */
-		24, 25, 26, 27, 28, 29,	30, 31, 32, 33,
-		34, 35, 36, 37, 38, 39,	40, 41, 42, 43,
-		44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-		54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-		},
-	.oobfree = {
-		/* 2 bytes at offset 0 hold manufacturer badblock markers */
-		{.offset = 2, .length = 22, },
-		/* 5 bytes at offset 8 hold BBT markers */
-		/* 8 bytes at offset 16 hold JFFS2 clean markers */
-	},
-};
+	return 0;
+}
 
-/*
- * An ECC layout for using 4-bit ECC with large-page (4096bytes) flash,
- * storing ten ECC bytes plus the manufacturer's bad block marker byte,
- * and not overlapping the default BBT markers.
- */
-static struct nand_ecclayout hwecc4_4096 = {
-	.eccbytes = 80,
-	.eccpos = {
-		/* at the end of spare sector */
-		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
-		58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-		68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
-		78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
-		88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
-		98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
-		108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
-		118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
-	},
-	.oobfree = {
-		/* 2 bytes at offset 0 hold manufacturer badblock markers */
-		{.offset = 2, .length = 46, },
-		/* 5 bytes at offset 8 hold BBT markers */
-		/* 8 bytes at offset 16 hold JFFS2 clean markers */
-	},
+static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 8;
+		oobregion->length = 5;
+	} else {
+		oobregion->offset = 16;
+		oobregion->length = mtd->oobsize - 16;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
+	.ecc = hwecc4_ooblayout_small_ecc,
+	.free = hwecc4_ooblayout_small_free,
 };
 
 #if defined(CONFIG_OF)
@@ -805,26 +787,14 @@ static int nand_davinci_probe(struct platform_device *pdev)
 		 * table marker fits in the free bytes.
 		 */
 		if (chunks == 1) {
-			info->ecclayout = hwecc4_small;
-			info->ecclayout.oobfree[1].length = mtd->oobsize - 16;
-			goto syndrome_done;
-		}
-		if (chunks == 4) {
-			info->ecclayout = hwecc4_2048;
+			mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
+		} else if (chunks == 4 || chunks == 8) {
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
-			goto syndrome_done;
-		}
-		if (chunks == 8) {
-			info->ecclayout = hwecc4_4096;
-			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
-			goto syndrome_done;
+		} else {
+			ret = -EIO;
+			goto err;
 		}
-
-		ret = -EIO;
-		goto err;
-
-syndrome_done:
-		info->chip.ecc.layout = &info->ecclayout;
 	}
 
 	ret = nand_scan_tail(mtd);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: cafe: switch to mtd_ooblayout_ops
Message-ID: <E1b54R1-00012l-F9@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=a8ed6e66f3b04d804fae425023aa4e7615dadab7
Commit:     a8ed6e66f3b04d804fae425023aa4e7615dadab7
Parent:     ef5eeea6e911540bbf51a283fe0ffb7389cbe66a
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:59:47 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:39 2016 +0200

    mtd: nand: cafe: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/cafe_nand.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index e553aff..0b0c937 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -459,10 +459,37 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 	return max_bitflips;
 }
 
-static struct nand_ecclayout cafe_oobinfo_2048 = {
-	.eccbytes = 14,
-	.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
-	.oobfree = {{14, 50}}
+static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = chip->ecc.total;
+	oobregion->length = mtd->oobsize - chip->ecc.total;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
+	.ecc = cafe_ooblayout_ecc,
+	.free = cafe_ooblayout_free,
 };
 
 /* Ick. The BBT code really ought to be able to work this bit out
@@ -494,12 +521,6 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
 	.pattern = cafe_mirror_pattern_2048
 };
 
-static struct nand_ecclayout cafe_oobinfo_512 = {
-	.eccbytes = 14,
-	.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
-	.oobfree = {{14, 2}}
-};
-
 static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
 		| NAND_BBT_2BIT | NAND_BBT_VERSION,
@@ -743,12 +764,11 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 		cafe->ctl2 |= 1<<29; /* 2KiB page size */
 
 	/* Set up ECC according to the type of chip we found */
+	mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
 	if (mtd->writesize == 2048) {
-		cafe->nand.ecc.layout = &cafe_oobinfo_2048;
 		cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
 		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
 	} else if (mtd->writesize == 512) {
-		cafe->nand.ecc.layout = &cafe_oobinfo_512;
 		cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
 		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
 	} else {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:15 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:15 +0000
Subject: mtd: nand: denali: switch to mtd_ooblayout_ops
Message-ID: <E1b54R1-00013k-Py@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=14fad62b688fefd2dc032e98968d4f4a69adefe9
Commit:     14fad62b688fefd2dc032e98968d4f4a69adefe9
Parent:     e4aacaa1b175cd53db0c6c7f033bb0fe02df6ea5
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:00:11 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:40 2016 +0200

    mtd: nand: denali: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/denali.c | 50 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 30bf5f6..0476ae8 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1374,13 +1374,41 @@ static void denali_hw_init(struct denali_nand_info *denali)
  * correction
  */
 #define ECC_8BITS	14
-static struct nand_ecclayout nand_8bit_oob = {
-	.eccbytes = 14,
-};
-
 #define ECC_15BITS	26
-static struct nand_ecclayout nand_15bit_oob = {
-	.eccbytes = 26,
+
+static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = denali->bbtskipbytes;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int denali_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = chip->ecc.total + denali->bbtskipbytes;
+	oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
+	.ecc = denali_ooblayout_ecc,
+	.free = denali_ooblayout_free,
 };
 
 static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
@@ -1561,7 +1589,6 @@ int denali_init(struct denali_nand_info *denali)
 			ECC_SECTOR_SIZE)))) {
 		/* if MLC OOB size is large enough, use 15bit ECC*/
 		denali->nand.ecc.strength = 15;
-		denali->nand.ecc.layout = &nand_15bit_oob;
 		denali->nand.ecc.bytes = ECC_15BITS;
 		iowrite32(15, denali->flash_reg + ECC_CORRECTION);
 	} else if (mtd->oobsize < (denali->bbtskipbytes +
@@ -1571,20 +1598,13 @@ int denali_init(struct denali_nand_info *denali)
 		goto failed_req_irq;
 	} else {
 		denali->nand.ecc.strength = 8;
-		denali->nand.ecc.layout = &nand_8bit_oob;
 		denali->nand.ecc.bytes = ECC_8BITS;
 		iowrite32(8, denali->flash_reg + ECC_CORRECTION);
 	}
 
+	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
 	denali->nand.ecc.bytes *= denali->devnum;
 	denali->nand.ecc.strength *= denali->devnum;
-	denali->nand.ecc.layout->eccbytes *=
-		mtd->writesize / ECC_SECTOR_SIZE;
-	denali->nand.ecc.layout->oobfree[0].offset =
-		denali->bbtskipbytes + denali->nand.ecc.layout->eccbytes;
-	denali->nand.ecc.layout->oobfree[0].length =
-		mtd->oobsize - denali->nand.ecc.layout->eccbytes -
-		denali->bbtskipbytes;
 
 	/*
 	 * Let driver know the total blocks number and how many blocks


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: diskonchip: switch to mtd_ooblayout_ops
Message-ID: <E1b54R2-00014S-0E@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=68c1b754822b01153359d77bcee94b9a423d5bb8
Commit:     68c1b754822b01153359d77bcee94b9a423d5bb8
Parent:     14fad62b688fefd2dc032e98968d4f4a69adefe9
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:00:23 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:40 2016 +0200

    mtd: nand: diskonchip: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/diskonchip.c | 60 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 45 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 547c100..a023ab9 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -950,20 +950,50 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
 
 //u_char mydatabuf[528];
 
-/* The strange out-of-order .oobfree list below is a (possibly unneeded)
- * attempt to retain compatibility.  It used to read:
- * 	.oobfree = { {8, 8} }
- * Since that leaves two bytes unusable, it was changed.  But the following
- * scheme might affect existing jffs2 installs by moving the cleanmarker:
- * 	.oobfree = { {6, 10} }
- * jffs2 seems to handle the above gracefully, but the current scheme seems
- * safer.  The only problem with it is that any code that parses oobfree must
- * be able to handle out-of-order segments.
- */
-static struct nand_ecclayout doc200x_oobinfo = {
-	.eccbytes = 6,
-	.eccpos = {0, 1, 2, 3, 4, 5},
-	.oobfree = {{8, 8}, {6, 2}}
+static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	/*
+	 * The strange out-of-order free bytes definition is a (possibly
+	 * unneeded) attempt to retain compatibility.  It used to read:
+	 *	.oobfree = { {8, 8} }
+	 * Since that leaves two bytes unusable, it was changed.  But the
+	 * following scheme might affect existing jffs2 installs by moving the
+	 * cleanmarker:
+	 *	.oobfree = { {6, 10} }
+	 * jffs2 seems to handle the above gracefully, but the current scheme
+	 * seems safer. The only problem with it is that any code retrieving
+	 * free bytes position must be able to handle out-of-order segments.
+	 */
+	if (!section) {
+		oobregion->offset = 8;
+		oobregion->length = 8;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = 2;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
+	.ecc = doc200x_ooblayout_ecc,
+	.free = doc200x_ooblayout_free,
 };
 
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1537,6 +1567,7 @@ static int __init doc_probe(unsigned long physadr)
 	nand->bbt_md		= nand->bbt_td + 1;
 
 	mtd->owner		= THIS_MODULE;
+	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
 
 	nand_set_controller_data(nand, doc);
 	nand->select_chip	= doc200x_select_chip;
@@ -1548,7 +1579,6 @@ static int __init doc_probe(unsigned long physadr)
 	nand->ecc.calculate	= doc200x_calculate_ecc;
 	nand->ecc.correct	= doc200x_correct_data;
 
-	nand->ecc.layout	= &doc200x_oobinfo;
 	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
 	nand->ecc.size		= 512;
 	nand->ecc.bytes		= 6;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: fsl_elbc: switch to mtd_ooblayout_ops
Message-ID: <E1b54R2-00015e-Bu@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c2e197b0198c753e9a17557d16be79bf910525a2
Commit:     c2e197b0198c753e9a17557d16be79bf910525a2
Parent:     6b75065e0d8ca46f98984b5dc30e9a07e7c9a475
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:01:04 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:41 2016 +0200

    mtd: nand: fsl_elbc: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_elbc_nand.c | 83 +++++++++++++++++++++++-----------------
 1 file changed, 47 insertions(+), 36 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 059d5f7..487eae0 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -79,32 +79,53 @@ struct fsl_elbc_fcm_ctrl {
 
 /* These map to the positions used by the FCM hardware ECC generator */
 
-/* Small Page FLASH with FMR[ECCM] = 0 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
-	.eccbytes = 3,
-	.eccpos = {6, 7, 8},
-	.oobfree = { {0, 5}, {9, 7} },
-};
+static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
 
-/* Small Page FLASH with FMR[ECCM] = 1 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
-	.eccbytes = 3,
-	.eccpos = {8, 9, 10},
-	.oobfree = { {0, 5}, {6, 2}, {11, 5} },
-};
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
 
-/* Large Page FLASH with FMR[ECCM] = 0 */
-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} },
-};
+	oobregion->offset = (16 * section) + 6;
+	if (priv->fmr & FMR_ECCM)
+		oobregion->offset += 2;
 
-/* Large Page FLASH with FMR[ECCM] = 1 */
-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} },
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+
+	if (section > chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		if (mtd->writesize > 512)
+			oobregion->offset++;
+		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
+	} else {
+		oobregion->offset = (16 * section) -
+				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
+		if (section < chip->ecc.steps)
+			oobregion->length = 13;
+		else
+			oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
+	.ecc = fsl_elbc_ooblayout_ecc,
+	.free = fsl_elbc_ooblayout_free,
 };
 
 /*
@@ -657,8 +678,8 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 	        chip->ecc.bytes);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
 	        chip->ecc.total);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
-	        chip->ecc.layout);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
+		mtd->ooblayout);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
@@ -675,14 +696,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 	} else if (mtd->writesize == 2048) {
 		priv->page_size = 1;
 		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
-		/* adjust ecc setup if needed */
-		if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
-		    BR_DECC_CHK_GEN) {
-			chip->ecc.size = 512;
-			chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
-			                   &fsl_elbc_oob_lp_eccm1 :
-			                   &fsl_elbc_oob_lp_eccm0;
-		}
 	} else {
 		dev_err(priv->dev,
 		        "fsl_elbc_init: page size %d is not supported\n",
@@ -780,9 +793,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
 	    BR_DECC_CHK_GEN) {
 		chip->ecc.mode = NAND_ECC_HW;
-		/* put in small page settings and adjust later if needed */
-		chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
-				&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+		mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
 		chip->ecc.size = 512;
 		chip->ecc.bytes = 3;
 		chip->ecc.strength = 1;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: docg4: switch to mtd_ooblayout_ops
Message-ID: <E1b54R2-000159-6d@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=6b75065e0d8ca46f98984b5dc30e9a07e7c9a475
Commit:     6b75065e0d8ca46f98984b5dc30e9a07e7c9a475
Parent:     68c1b754822b01153359d77bcee94b9a423d5bb8
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:00:35 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:41 2016 +0200

    mtd: nand: docg4: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/docg4.c | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index d86a60e..4731699 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -222,10 +222,33 @@ struct docg4_priv {
  * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
  * Byte 15 (the last) is used by the driver as a "page written" flag.
  */
-static struct nand_ecclayout docg4_oobinfo = {
-	.eccbytes = 9,
-	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
-	.oobfree = { {.offset = 2, .length = 5} }
+static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 7;
+	oobregion->length = 9;
+
+	return 0;
+}
+
+static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 2;
+	oobregion->length = 5;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
+	.ecc = docg4_ooblayout_ecc,
+	.free = docg4_ooblayout_free,
 };
 
 /*
@@ -1209,6 +1232,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
 	mtd->writesize = DOCG4_PAGE_SIZE;
 	mtd->erasesize = DOCG4_BLOCK_SIZE;
 	mtd->oobsize = DOCG4_OOB_SIZE;
+	mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
 	nand->chipsize = DOCG4_CHIP_SIZE;
 	nand->chip_shift = DOCG4_CHIP_SHIFT;
 	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
@@ -1217,7 +1241,6 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
 	nand->pagemask = 0x3ffff;
 	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
 	nand->badblockbits = 8;
-	nand->ecc.layout = &docg4_oobinfo;
 	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
 	nand->ecc.size = DOCG4_PAGE_SIZE;
 	nand->ecc.prepad = 8;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: fsl_ifc: switch to mtd_ooblayout_ops
Message-ID: <E1b54R2-000168-Fl@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=caf5129e93c510d8f3306f894988e52a8369c766
Commit:     caf5129e93c510d8f3306f894988e52a8369c766
Parent:     c2e197b0198c753e9a17557d16be79bf910525a2
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Tue Feb 9 17:01:57 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:42 2016 +0200

    mtd: nand: fsl_ifc: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_ifc_nand.c | 230 ++++++++++++----------------------------
 1 file changed, 66 insertions(+), 164 deletions(-)

diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 1d922a0..864aa12 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -67,136 +67,6 @@ struct fsl_ifc_nand_ctrl {
 
 static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
 
-/* 512-byte page with 4-bit ECC, 8-bit */
-static struct nand_ecclayout oob_512_8bit_ecc4 = {
-	.eccbytes = 8,
-	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
-	.oobfree = { {0, 5}, {6, 2} },
-};
-
-/* 512-byte page with 4-bit ECC, 16-bit */
-static struct nand_ecclayout oob_512_16bit_ecc4 = {
-	.eccbytes = 8,
-	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
-	.oobfree = { {2, 6}, },
-};
-
-/* 2048-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_2048_ecc4 = {
-	.eccbytes = 32,
-	.eccpos = {
-		8, 9, 10, 11, 12, 13, 14, 15,
-		16, 17, 18, 19, 20, 21, 22, 23,
-		24, 25, 26, 27, 28, 29, 30, 31,
-		32, 33, 34, 35, 36, 37, 38, 39,
-	},
-	.oobfree = { {2, 6}, {40, 24} },
-};
-
-/* 4096-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_4096_ecc4 = {
-	.eccbytes = 64,
-	.eccpos = {
-		8, 9, 10, 11, 12, 13, 14, 15,
-		16, 17, 18, 19, 20, 21, 22, 23,
-		24, 25, 26, 27, 28, 29, 30, 31,
-		32, 33, 34, 35, 36, 37, 38, 39,
-		40, 41, 42, 43, 44, 45, 46, 47,
-		48, 49, 50, 51, 52, 53, 54, 55,
-		56, 57, 58, 59, 60, 61, 62, 63,
-		64, 65, 66, 67, 68, 69, 70, 71,
-	},
-	.oobfree = { {2, 6}, {72, 56} },
-};
-
-/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
-static struct nand_ecclayout oob_4096_ecc8 = {
-	.eccbytes = 128,
-	.eccpos = {
-		8, 9, 10, 11, 12, 13, 14, 15,
-		16, 17, 18, 19, 20, 21, 22, 23,
-		24, 25, 26, 27, 28, 29, 30, 31,
-		32, 33, 34, 35, 36, 37, 38, 39,
-		40, 41, 42, 43, 44, 45, 46, 47,
-		48, 49, 50, 51, 52, 53, 54, 55,
-		56, 57, 58, 59, 60, 61, 62, 63,
-		64, 65, 66, 67, 68, 69, 70, 71,
-		72, 73, 74, 75, 76, 77, 78, 79,
-		80, 81, 82, 83, 84, 85, 86, 87,
-		88, 89, 90, 91, 92, 93, 94, 95,
-		96, 97, 98, 99, 100, 101, 102, 103,
-		104, 105, 106, 107, 108, 109, 110, 111,
-		112, 113, 114, 115, 116, 117, 118, 119,
-		120, 121, 122, 123, 124, 125, 126, 127,
-		128, 129, 130, 131, 132, 133, 134, 135,
-	},
-	.oobfree = { {2, 6}, {136, 82} },
-};
-
-/* 8192-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_8192_ecc4 = {
-	.eccbytes = 128,
-	.eccpos = {
-		8, 9, 10, 11, 12, 13, 14, 15,
-		16, 17, 18, 19, 20, 21, 22, 23,
-		24, 25, 26, 27, 28, 29, 30, 31,
-		32, 33, 34, 35, 36, 37, 38, 39,
-		40, 41, 42, 43, 44, 45, 46, 47,
-		48, 49, 50, 51, 52, 53, 54, 55,
-		56, 57, 58, 59, 60, 61, 62, 63,
-		64, 65, 66, 67, 68, 69, 70, 71,
-		72, 73, 74, 75, 76, 77, 78, 79,
-		80, 81, 82, 83, 84, 85, 86, 87,
-		88, 89, 90, 91, 92, 93, 94, 95,
-		96, 97, 98, 99, 100, 101, 102, 103,
-		104, 105, 106, 107, 108, 109, 110, 111,
-		112, 113, 114, 115, 116, 117, 118, 119,
-		120, 121, 122, 123, 124, 125, 126, 127,
-		128, 129, 130, 131, 132, 133, 134, 135,
-	},
-	.oobfree = { {2, 6}, {136, 208} },
-};
-
-/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
-static struct nand_ecclayout oob_8192_ecc8 = {
-	.eccbytes = 256,
-	.eccpos = {
-		8, 9, 10, 11, 12, 13, 14, 15,
-		16, 17, 18, 19, 20, 21, 22, 23,
-		24, 25, 26, 27, 28, 29, 30, 31,
-		32, 33, 34, 35, 36, 37, 38, 39,
-		40, 41, 42, 43, 44, 45, 46, 47,
-		48, 49, 50, 51, 52, 53, 54, 55,
-		56, 57, 58, 59, 60, 61, 62, 63,
-		64, 65, 66, 67, 68, 69, 70, 71,
-		72, 73, 74, 75, 76, 77, 78, 79,
-		80, 81, 82, 83, 84, 85, 86, 87,
-		88, 89, 90, 91, 92, 93, 94, 95,
-		96, 97, 98, 99, 100, 101, 102, 103,
-		104, 105, 106, 107, 108, 109, 110, 111,
-		112, 113, 114, 115, 116, 117, 118, 119,
-		120, 121, 122, 123, 124, 125, 126, 127,
-		128, 129, 130, 131, 132, 133, 134, 135,
-		136, 137, 138, 139, 140, 141, 142, 143,
-		144, 145, 146, 147, 148, 149, 150, 151,
-		152, 153, 154, 155, 156, 157, 158, 159,
-		160, 161, 162, 163, 164, 165, 166, 167,
-		168, 169, 170, 171, 172, 173, 174, 175,
-		176, 177, 178, 179, 180, 181, 182, 183,
-		184, 185, 186, 187, 188, 189, 190, 191,
-		192, 193, 194, 195, 196, 197, 198, 199,
-		200, 201, 202, 203, 204, 205, 206, 207,
-		208, 209, 210, 211, 212, 213, 214, 215,
-		216, 217, 218, 219, 220, 221, 222, 223,
-		224, 225, 226, 227, 228, 229, 230, 231,
-		232, 233, 234, 235, 236, 237, 238, 239,
-		240, 241, 242, 243, 244, 245, 246, 247,
-		248, 249, 250, 251, 252, 253, 254, 255,
-		256, 257, 258, 259, 260, 261, 262, 263,
-	},
-	.oobfree = { {2, 6}, {264, 80} },
-};
-
 /*
  * Generic flash bbt descriptors
  */
@@ -223,6 +93,57 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 	.pattern = mirror_pattern,
 };
 
+static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int fsl_ifc_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->writesize == 512 &&
+	    !(chip->options & NAND_BUSWIDTH_16)) {
+		if (!section) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 6;
+			oobregion->length = 2;
+		}
+
+		return 0;
+	}
+
+	if (!section) {
+		oobregion->offset = 2;
+		oobregion->length = 6;
+	} else {
+		oobregion->offset = chip->ecc.total + 8;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
+	.ecc = fsl_ifc_ooblayout_ecc,
+	.free = fsl_ifc_ooblayout_free,
+};
+
 /*
  * Set up the IFC hardware block and page address fields, and the ifc nand
  * structure addr field to point to the correct IFC buffer in memory
@@ -812,8 +733,8 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
 							chip->ecc.bytes);
 	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
 							chip->ecc.total);
-	dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__,
-							chip->ecc.layout);
+	dev_dbg(priv->dev, "%s: mtd->ooblayout = %p\n", __func__,
+							mtd->ooblayout);
 	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
 	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
 	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
@@ -885,7 +806,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
 	struct nand_chip *chip = &priv->chip;
 	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
-	struct nand_ecclayout *layout;
 	u32 csor;
 
 	/* Fill in fsl_ifc_mtd structure */
@@ -931,18 +851,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
 	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
 
-	/* Hardware generates ECC per 512 Bytes */
-	chip->ecc.size = 512;
-	chip->ecc.bytes = 8;
-	chip->ecc.strength = 4;
-
 	switch (csor & CSOR_NAND_PGS_MASK) {
 	case CSOR_NAND_PGS_512:
-		if (chip->options & NAND_BUSWIDTH_16) {
-			layout = &oob_512_16bit_ecc4;
-		} else {
-			layout = &oob_512_8bit_ecc4;
-
+		if (!(chip->options & NAND_BUSWIDTH_16)) {
 			/* Avoid conflict with bad block marker */
 			bbt_main_descr.offs = 0;
 			bbt_mirror_descr.offs = 0;
@@ -952,35 +863,16 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 		break;
 
 	case CSOR_NAND_PGS_2K:
-		layout = &oob_2048_ecc4;
 		priv->bufnum_mask = 3;
 		break;
 
 	case CSOR_NAND_PGS_4K:
-		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
-		    CSOR_NAND_ECC_MODE_4) {
-			layout = &oob_4096_ecc4;
-		} else {
-			layout = &oob_4096_ecc8;
-			chip->ecc.bytes = 16;
-			chip->ecc.strength = 8;
-		}
-
 		priv->bufnum_mask = 1;
 		break;
 
 	case CSOR_NAND_PGS_8K:
-		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
-		    CSOR_NAND_ECC_MODE_4) {
-			layout = &oob_8192_ecc4;
-		} else {
-			layout = &oob_8192_ecc8;
-			chip->ecc.bytes = 16;
-			chip->ecc.strength = 8;
-		}
-
 		priv->bufnum_mask = 0;
-	break;
+		break;
 
 	default:
 		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
@@ -990,7 +882,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
 	if (csor & CSOR_NAND_ECC_DEC_EN) {
 		chip->ecc.mode = NAND_ECC_HW;
-		chip->ecc.layout = layout;
+		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
+
+		/* Hardware generates ECC per 512 Bytes */
+		chip->ecc.size = 512;
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
+			chip->ecc.bytes = 8;
+			chip->ecc.strength = 4;
+		} else {
+			chip->ecc.bytes = 16;
+			chip->ecc.strength = 8;
+		}
 	} else {
 		chip->ecc.mode = NAND_ECC_SOFT;
 	}


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: fsmc: switch to mtd_ooblayout_ops
Message-ID: <E1b54R2-00016t-Mv@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=22b469577625056e76b7ddb670eea3dc69210eb6
Commit:     22b469577625056e76b7ddb670eea3dc69210eb6
Parent:     caf5129e93c510d8f3306f894988e52a8369c766
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:01:42 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:42 2016 +0200

    mtd: nand: fsmc: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c | 298 ++++++++++++-------------------------------
 1 file changed, 82 insertions(+), 216 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 1bdcd4f..275a98c 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -39,212 +39,6 @@
 #include <linux/amba/bus.h>
 #include <mtd/mtd-abi.h>
 
-static struct nand_ecclayout fsmc_ecc1_128_layout = {
-	.eccbytes = 24,
-	.eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
-		66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
-	.oobfree = {
-		{.offset = 8, .length = 8},
-		{.offset = 24, .length = 8},
-		{.offset = 40, .length = 8},
-		{.offset = 56, .length = 8},
-		{.offset = 72, .length = 8},
-		{.offset = 88, .length = 8},
-		{.offset = 104, .length = 8},
-		{.offset = 120, .length = 8}
-	}
-};
-
-static struct nand_ecclayout fsmc_ecc1_64_layout = {
-	.eccbytes = 12,
-	.eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52},
-	.oobfree = {
-		{.offset = 8, .length = 8},
-		{.offset = 24, .length = 8},
-		{.offset = 40, .length = 8},
-		{.offset = 56, .length = 8},
-	}
-};
-
-static struct nand_ecclayout fsmc_ecc1_16_layout = {
-	.eccbytes = 3,
-	.eccpos = {2, 3, 4},
-	.oobfree = {
-		{.offset = 8, .length = 8},
-	}
-};
-
-/*
- * ECC4 layout for NAND of pagesize 8192 bytes & OOBsize 256 bytes. 13*16 bytes
- * of OB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 46
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_256_layout = {
-	.eccbytes = 208,
-	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
-		9,  10,  11,  12,  13,  14,
-		18,  19,  20,  21,  22,  23,  24,
-		25,  26,  27,  28,  29,  30,
-		34,  35,  36,  37,  38,  39,  40,
-		41,  42,  43,  44,  45,  46,
-		50,  51,  52,  53,  54,  55,  56,
-		57,  58,  59,  60,  61,  62,
-		66,  67,  68,  69,  70,  71,  72,
-		73,  74,  75,  76,  77,  78,
-		82,  83,  84,  85,  86,  87,  88,
-		89,  90,  91,  92,  93,  94,
-		98,  99, 100, 101, 102, 103, 104,
-		105, 106, 107, 108, 109, 110,
-		114, 115, 116, 117, 118, 119, 120,
-		121, 122, 123, 124, 125, 126,
-		130, 131, 132, 133, 134, 135, 136,
-		137, 138, 139, 140, 141, 142,
-		146, 147, 148, 149, 150, 151, 152,
-		153, 154, 155, 156, 157, 158,
-		162, 163, 164, 165, 166, 167, 168,
-		169, 170, 171, 172, 173, 174,
-		178, 179, 180, 181, 182, 183, 184,
-		185, 186, 187, 188, 189, 190,
-		194, 195, 196, 197, 198, 199, 200,
-		201, 202, 203, 204, 205, 206,
-		210, 211, 212, 213, 214, 215, 216,
-		217, 218, 219, 220, 221, 222,
-		226, 227, 228, 229, 230, 231, 232,
-		233, 234, 235, 236, 237, 238,
-		242, 243, 244, 245, 246, 247, 248,
-		249, 250, 251, 252, 253, 254
-	},
-	.oobfree = {
-		{.offset = 15, .length = 3},
-		{.offset = 31, .length = 3},
-		{.offset = 47, .length = 3},
-		{.offset = 63, .length = 3},
-		{.offset = 79, .length = 3},
-		{.offset = 95, .length = 3},
-		{.offset = 111, .length = 3},
-		{.offset = 127, .length = 3},
-		{.offset = 143, .length = 3},
-		{.offset = 159, .length = 3},
-		{.offset = 175, .length = 3},
-		{.offset = 191, .length = 3},
-		{.offset = 207, .length = 3},
-		{.offset = 223, .length = 3},
-		{.offset = 239, .length = 3},
-		{.offset = 255, .length = 1}
-	}
-};
-
-/*
- * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes
- * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_224_layout = {
-	.eccbytes = 104,
-	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
-		9,  10,  11,  12,  13,  14,
-		18,  19,  20,  21,  22,  23,  24,
-		25,  26,  27,  28,  29,  30,
-		34,  35,  36,  37,  38,  39,  40,
-		41,  42,  43,  44,  45,  46,
-		50,  51,  52,  53,  54,  55,  56,
-		57,  58,  59,  60,  61,  62,
-		66,  67,  68,  69,  70,  71,  72,
-		73,  74,  75,  76,  77,  78,
-		82,  83,  84,  85,  86,  87,  88,
-		89,  90,  91,  92,  93,  94,
-		98,  99, 100, 101, 102, 103, 104,
-		105, 106, 107, 108, 109, 110,
-		114, 115, 116, 117, 118, 119, 120,
-		121, 122, 123, 124, 125, 126
-	},
-	.oobfree = {
-		{.offset = 15, .length = 3},
-		{.offset = 31, .length = 3},
-		{.offset = 47, .length = 3},
-		{.offset = 63, .length = 3},
-		{.offset = 79, .length = 3},
-		{.offset = 95, .length = 3},
-		{.offset = 111, .length = 3},
-		{.offset = 127, .length = 97}
-	}
-};
-
-/*
- * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 128 bytes. 13*8 bytes
- * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 22
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_128_layout = {
-	.eccbytes = 104,
-	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
-		9,  10,  11,  12,  13,  14,
-		18,  19,  20,  21,  22,  23,  24,
-		25,  26,  27,  28,  29,  30,
-		34,  35,  36,  37,  38,  39,  40,
-		41,  42,  43,  44,  45,  46,
-		50,  51,  52,  53,  54,  55,  56,
-		57,  58,  59,  60,  61,  62,
-		66,  67,  68,  69,  70,  71,  72,
-		73,  74,  75,  76,  77,  78,
-		82,  83,  84,  85,  86,  87,  88,
-		89,  90,  91,  92,  93,  94,
-		98,  99, 100, 101, 102, 103, 104,
-		105, 106, 107, 108, 109, 110,
-		114, 115, 116, 117, 118, 119, 120,
-		121, 122, 123, 124, 125, 126
-	},
-	.oobfree = {
-		{.offset = 15, .length = 3},
-		{.offset = 31, .length = 3},
-		{.offset = 47, .length = 3},
-		{.offset = 63, .length = 3},
-		{.offset = 79, .length = 3},
-		{.offset = 95, .length = 3},
-		{.offset = 111, .length = 3},
-		{.offset = 127, .length = 1}
-	}
-};
-
-/*
- * ECC4 layout for NAND of pagesize 2048 bytes & OOBsize 64 bytes. 13*4 bytes of
- * OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 10
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_64_layout = {
-	.eccbytes = 52,
-	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
-		9,  10,  11,  12,  13,  14,
-		18,  19,  20,  21,  22,  23,  24,
-		25,  26,  27,  28,  29,  30,
-		34,  35,  36,  37,  38,  39,  40,
-		41,  42,  43,  44,  45,  46,
-		50,  51,  52,  53,  54,  55,  56,
-		57,  58,  59,  60,  61,  62,
-	},
-	.oobfree = {
-		{.offset = 15, .length = 3},
-		{.offset = 31, .length = 3},
-		{.offset = 47, .length = 3},
-		{.offset = 63, .length = 1},
-	}
-};
-
-/*
- * ECC4 layout for NAND of pagesize 512 bytes & OOBsize 16 bytes. 13 bytes of
- * OOB size is reserved for ECC, Byte no. 4 & 5 reserved for bad block and One
- * byte is free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_16_layout = {
-	.eccbytes = 13,
-	.eccpos = { 0,  1,  2,  3,  6,  7, 8,
-		9, 10, 11, 12, 13, 14
-	},
-	.oobfree = {
-		{.offset = 15, .length = 1},
-	}
-};
-
 /*
  * ECC placement definitions in oobfree type format.
  * There are 13 bytes of ecc for every 512 byte block and it has to be read
@@ -274,6 +68,84 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
 	}
 };
 
+static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 2;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int fsmc_ecc1_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 8;
+
+	if (section < chip->ecc.steps - 1)
+		oobregion->length = 8;
+	else
+		oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
+	.ecc = fsmc_ecc1_ooblayout_ecc,
+	.free = fsmc_ecc1_ooblayout_free,
+};
+
+static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->length = chip->ecc.bytes;
+
+	if (!section && mtd->writesize <= 512)
+		oobregion->offset = 0;
+	else
+		oobregion->offset = (section * 16) + 2;
+
+	return 0;
+}
+
+static int fsmc_ecc4_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 15;
+
+	if (section < chip->ecc.steps - 1)
+		oobregion->length = 3;
+	else
+		oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
+	.ecc = fsmc_ecc4_ooblayout_ecc,
+	.free = fsmc_ecc4_ooblayout_free,
+};
+
 /**
  * struct fsmc_nand_data - structure for FSMC NAND device state
  *
@@ -1084,23 +956,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 	if (AMBA_REV_BITS(host->pid) >= 8) {
 		switch (mtd->oobsize) {
 		case 16:
-			nand->ecc.layout = &fsmc_ecc4_16_layout;
 			host->ecc_place = &fsmc_ecc4_sp_place;
 			break;
 		case 64:
-			nand->ecc.layout = &fsmc_ecc4_64_layout;
 			host->ecc_place = &fsmc_ecc4_lp_place;
 			break;
 		case 128:
-			nand->ecc.layout = &fsmc_ecc4_128_layout;
 			host->ecc_place = &fsmc_ecc4_lp_place;
 			break;
 		case 224:
-			nand->ecc.layout = &fsmc_ecc4_224_layout;
 			host->ecc_place = &fsmc_ecc4_lp_place;
 			break;
 		case 256:
-			nand->ecc.layout = &fsmc_ecc4_256_layout;
 			host->ecc_place = &fsmc_ecc4_lp_place;
 			break;
 		default:
@@ -1109,6 +976,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 			ret = -EINVAL;
 			goto err_probe;
 		}
+
+		mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
 	} else {
 		switch (nand->ecc.mode) {
 		case NAND_ECC_HW:
@@ -1135,13 +1004,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 		if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
 			switch (mtd->oobsize) {
 			case 16:
-				nand->ecc.layout = &fsmc_ecc1_16_layout;
-				break;
 			case 64:
-				nand->ecc.layout = &fsmc_ecc1_64_layout;
-				break;
 			case 128:
-				nand->ecc.layout = &fsmc_ecc1_128_layout;
+				mtd_set_ooblayout(mtd,
+						  &fsmc_ecc1_ooblayout_ops);
 				break;
 			default:
 				dev_warn(&pdev->dev,


From linux-mtd at lists.infradead.org  Mon May 23 21:59:16 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:16 +0000
Subject: mtd: nand: fsmc: get rid of the fsmc_nand_eccplace struct
Message-ID: <E1b54R2-00017W-Rk@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=04a123a99f089773fc6ee6e21af5f831d87fe362
Commit:     04a123a99f089773fc6ee6e21af5f831d87fe362
Parent:     22b469577625056e76b7ddb670eea3dc69210eb6
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Tue Feb 9 15:01:21 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:43 2016 +0200

    mtd: nand: fsmc: get rid of the fsmc_nand_eccplace struct
    
    Now that mtd_ooblayout_ecc() returns the ECC byte position using the
    OOB free method, we can get rid of the fsmc_nand_eccplace struct.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c | 60 +++++++++++---------------------------------
 include/linux/mtd/fsmc.h     | 18 -------------
 2 files changed, 15 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 275a98c..1372040 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -39,35 +39,6 @@
 #include <linux/amba/bus.h>
 #include <mtd/mtd-abi.h>
 
-/*
- * ECC placement definitions in oobfree type format.
- * There are 13 bytes of ecc for every 512 byte block and it has to be read
- * consecutively and immediately after the 512 byte data block for hardware to
- * generate the error bit offsets in 512 byte data.
- * Managing the ecc bytes in the following way makes it easier for software to
- * read ecc bytes consecutive to data bytes. This way is similar to
- * oobfree structure maintained already in generic nand driver
- */
-static struct fsmc_eccplace fsmc_ecc4_lp_place = {
-	.eccplace = {
-		{.offset = 2, .length = 13},
-		{.offset = 18, .length = 13},
-		{.offset = 34, .length = 13},
-		{.offset = 50, .length = 13},
-		{.offset = 66, .length = 13},
-		{.offset = 82, .length = 13},
-		{.offset = 98, .length = 13},
-		{.offset = 114, .length = 13}
-	}
-};
-
-static struct fsmc_eccplace fsmc_ecc4_sp_place = {
-	.eccplace = {
-		{.offset = 0, .length = 4},
-		{.offset = 6, .length = 9}
-	}
-};
-
 static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
@@ -105,6 +76,12 @@ static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
 	.free = fsmc_ecc1_ooblayout_free,
 };
 
+/*
+ * ECC placement definitions in oobfree type format.
+ * There are 13 bytes of ecc for every 512 byte block and it has to be read
+ * consecutively and immediately after the 512 byte data block for hardware to
+ * generate the error bit offsets in 512 byte data.
+ */
 static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
 				   struct mtd_oob_region *oobregion)
 {
@@ -155,7 +132,6 @@ static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
  * @partitions:		Partition info for a NAND Flash.
  * @nr_partitions:	Total number of partition of a NAND flash.
  *
- * @ecc_place:		ECC placing locations in oobfree type format.
  * @bank:		Bank number for probed device.
  * @clk:		Clock structure for FSMC.
  *
@@ -175,7 +151,6 @@ struct fsmc_nand_data {
 	struct mtd_partition	*partitions;
 	unsigned int		nr_partitions;
 
-	struct fsmc_eccplace	*ecc_place;
 	unsigned int		bank;
 	struct device		*dev;
 	enum access_mode	mode;
@@ -582,8 +557,6 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
 static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 				 uint8_t *buf, int oob_required, int page)
 {
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	struct fsmc_eccplace *ecc_place = host->ecc_place;
 	int i, j, s, stat, eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
 	int eccsteps = chip->ecc.steps;
@@ -606,9 +579,15 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->read_buf(mtd, p, eccsize);
 
 		for (j = 0; j < eccbytes;) {
-			off = ecc_place->eccplace[group].offset;
-			len = ecc_place->eccplace[group].length;
-			group++;
+			struct mtd_oob_region oobregion;
+			int ret;
+
+			ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
+			if (ret)
+				return ret;
+
+			off = oobregion.offset;
+			len = oobregion.length;
 
 			/*
 			 * length is intentionally kept a higher multiple of 2
@@ -956,19 +935,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 	if (AMBA_REV_BITS(host->pid) >= 8) {
 		switch (mtd->oobsize) {
 		case 16:
-			host->ecc_place = &fsmc_ecc4_sp_place;
-			break;
 		case 64:
-			host->ecc_place = &fsmc_ecc4_lp_place;
-			break;
 		case 128:
-			host->ecc_place = &fsmc_ecc4_lp_place;
-			break;
 		case 224:
-			host->ecc_place = &fsmc_ecc4_lp_place;
-			break;
 		case 256:
-			host->ecc_place = &fsmc_ecc4_lp_place;
 			break;
 		default:
 			dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
index c8be32e..ad3c348 100644
--- a/include/linux/mtd/fsmc.h
+++ b/include/linux/mtd/fsmc.h
@@ -103,24 +103,6 @@
 
 #define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
 
-/*
- * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
- * and it has to be read consecutively and immediately after the 512
- * byte data block for hardware to generate the error bit offsets
- * Managing the ecc bytes in the following way is easier. This way is
- * similar to oobfree structure maintained already in u-boot nand driver
- */
-#define MAX_ECCPLACE_ENTRIES	32
-
-struct fsmc_nand_eccplace {
-	uint8_t offset;
-	uint8_t length;
-};
-
-struct fsmc_eccplace {
-	struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES];
-};
-
 struct fsmc_nand_timings {
 	uint8_t tclr;
 	uint8_t tar;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: gpmi: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-000185-3Z@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=3f158e47dfe92ee53f1e09c5fa76a07116100f02
Commit:     3f158e47dfe92ee53f1e09c5fa76a07116100f02
Parent:     04a123a99f089773fc6ee6e21af5f831d87fe362
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:01:54 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:43 2016 +0200

    mtd: nand: gpmi: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Han Xu <han.xu at nxp.com>
    Tested-by: Han Xu <han.xu at nxp.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 52 ++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 4721008..c50523b 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -47,10 +47,44 @@ static struct nand_bbt_descr gpmi_bbt_descr = {
  * We may change the layout if we can get the ECC info from the datasheet,
  * else we will use all the (page + OOB).
  */
-static struct nand_ecclayout gpmi_hw_ecclayout = {
-	.eccbytes = 0,
-	.eccpos = { 0, },
-	.oobfree = { {.offset = 0, .length = 0} }
+static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *geo = &this->bch_geometry;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = geo->page_size - mtd->writesize;
+
+	return 0;
+}
+
+static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *geo = &this->bch_geometry;
+
+	if (section)
+		return -ERANGE;
+
+	/* The available oob size we have. */
+	if (geo->page_size < mtd->writesize + mtd->oobsize) {
+		oobregion->offset = geo->page_size - mtd->writesize;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+	.ecc = gpmi_ooblayout_ecc,
+	.free = gpmi_ooblayout_free,
 };
 
 static const struct gpmi_devdata gpmi_devdata_imx23 = {
@@ -141,7 +175,6 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 	struct bch_geometry *geo = &this->bch_geometry;
 	struct nand_chip *chip = &this->nand;
 	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
 	unsigned int block_mark_bit_offset;
 
 	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
@@ -229,12 +262,6 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 	geo->page_size = mtd->writesize + geo->metadata_size +
 		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
 
-	/* The available oob size we have. */
-	if (geo->page_size < mtd->writesize + mtd->oobsize) {
-		of->offset = geo->page_size - mtd->writesize;
-		of->length = mtd->oobsize - of->offset;
-	}
-
 	geo->payload_size = mtd->writesize;
 
 	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
@@ -1842,6 +1869,7 @@ static void gpmi_nand_exit(struct gpmi_nand_data *this)
 static int gpmi_init_last(struct gpmi_nand_data *this)
 {
 	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	struct bch_geometry *bch_geo = &this->bch_geometry;
 	int ret;
@@ -1863,7 +1891,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
 	ecc->mode	= NAND_ECC_HW;
 	ecc->size	= bch_geo->ecc_chunk_size;
 	ecc->strength	= bch_geo->ecc_strength;
-	ecc->layout	= &gpmi_hw_ecclayout;
+	mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
 
 	/*
 	 * We only enable the subpage read when:


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: hisi504: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-00018Y-86@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ca9ec9acd3bea9f3160e0e0975c06914da3ae4e
Commit:     2ca9ec9acd3bea9f3160e0e0975c06914da3ae4e
Parent:     3f158e47dfe92ee53f1e09c5fa76a07116100f02
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:02:09 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:44 2016 +0200

    mtd: nand: hisi504: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/hisi504_nand.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 96502b6..7bf844c 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -631,8 +631,28 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
 	hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
 }
 
-static struct nand_ecclayout nand_ecc_2K_16bits = {
-	.oobfree = { {2, 6} },
+static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	/* FIXME: add ECC bytes position */
+	return -ENOTSUPP;
+}
+
+static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 2;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
+	.ecc = hisi_ooblayout_ecc,
+	.free = hisi_ooblayout_free,
 };
 
 static int hisi_nfc_ecc_probe(struct hinfc_host *host)
@@ -668,7 +688,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
 	case 16:
 		ecc_bits = 6;
 		if (mtd->writesize == 2048)
-			chip->ecc.layout = &nand_ecc_2K_16bits;
+			mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
 
 		/* TODO: add more page size support */
 		break;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: jz4780: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-000195-EK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=36886be7dd3b48f593d9da21c631d06d5bfae55d
Commit:     36886be7dd3b48f593d9da21c631d06d5bfae55d
Parent:     2ca9ec9acd3bea9f3160e0e0975c06914da3ae4e
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:02:22 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:44 2016 +0200

    mtd: nand: jz4780: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Tested-by: Harvey Hunt <harvey.hunt at imgtec.com>
---
 drivers/mtd/nand/jz4780_nand.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
index 23a1999..10f249a 100644
--- a/drivers/mtd/nand/jz4780_nand.c
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -55,8 +55,6 @@ struct jz4780_nand_chip {
 	struct nand_chip chip;
 	struct list_head chip_list;
 
-	struct nand_ecclayout ecclayout;
-
 	struct gpio_desc *busy_gpio;
 	struct gpio_desc *wp_gpio;
 	unsigned int reading: 1;
@@ -164,8 +162,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
-	struct nand_ecclayout *layout = &nand->ecclayout;
-	u32 start, i;
+	int eccbytes;
 
 	chip->ecc.bytes = fls((1 + 8) * chip->ecc.size)	*
 				(chip->ecc.strength / 8);
@@ -200,23 +197,17 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
 		return 0;
 
 	/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
-	layout->eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
+	eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
 
-	if (layout->eccbytes > mtd->oobsize - 2) {
+	if (eccbytes > mtd->oobsize - 2) {
 		dev_err(dev,
 			"invalid ECC config: required %d ECC bytes, but only %d are available",
-			layout->eccbytes, mtd->oobsize - 2);
+			eccbytes, mtd->oobsize - 2);
 		return -EINVAL;
 	}
 
-	start = mtd->oobsize - layout->eccbytes;
-	for (i = 0; i < layout->eccbytes; i++)
-		layout->eccpos[i] = start + i;
-
-	layout->oobfree[0].offset = 2;
-	layout->oobfree[0].length = mtd->oobsize - layout->eccbytes - 2;
+	mtd->ooblayout = &nand_ooblayout_lp_ops;
 
-	chip->ecc.layout = layout;
 	return 0;
 }
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: lpc32xx: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-00019c-JO@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d50b5239867f02627fc24c4450a87bd9c3267c0a
Commit:     d50b5239867f02627fc24c4450a87bd9c3267c0a
Parent:     36886be7dd3b48f593d9da21c631d06d5bfae55d
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:02:41 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:45 2016 +0200

    mtd: nand: lpc32xx: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/lpc32xx_mlc.c | 50 ++++++++++++++++++++++++++++--------------
 drivers/mtd/nand/lpc32xx_slc.c | 41 +++++++++++++++++++++++++++-------
 2 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 8e43978..8523881 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -138,22 +138,37 @@ struct lpc32xx_nand_cfg_mlc {
 	unsigned num_parts;
 };
 
-static struct nand_ecclayout lpc32xx_nand_oob = {
-	.eccbytes = 40,
-	.eccpos = { 6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-		   22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-		   38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-		   54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
-	.oobfree = {
-		{ .offset = 0,
-		  .length = 6, },
-		{ .offset = 16,
-		  .length = 6, },
-		{ .offset = 32,
-		  .length = 6, },
-		{ .offset = 48,
-		  .length = 6, },
-		},
+static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
+	oobregion->length = nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = 16 * section;
+	oobregion->length = 16 - nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+	.ecc = lpc32xx_ooblayout_ecc,
+	.free = lpc32xx_ooblayout_free,
 };
 
 static struct nand_bbt_descr lpc32xx_nand_bbt = {
@@ -712,6 +727,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	nand_chip->ecc.write_oob = lpc32xx_write_oob;
 	nand_chip->ecc.read_oob = lpc32xx_read_oob;
 	nand_chip->ecc.strength = 4;
+	nand_chip->ecc.bytes = 10;
 	nand_chip->waitfunc = lpc32xx_waitfunc;
 
 	nand_chip->options = NAND_NO_SUBPAGE_WRITE;
@@ -750,7 +766,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
 	nand_chip->ecc.mode = NAND_ECC_HW;
 	nand_chip->ecc.size = 512;
-	nand_chip->ecc.layout = &lpc32xx_nand_oob;
+	mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
 	host->mlcsubpages = mtd->writesize / 512;
 
 	/* initially clear interrupt status */
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 10cf8e62..219dd67 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -146,13 +146,38 @@
  * NAND ECC Layout for small page NAND devices
  * Note: For large and huge page devices, the default layouts are used
  */
-static struct nand_ecclayout lpc32xx_nand_oob_16 = {
-	.eccbytes = 6,
-	.eccpos = {10, 11, 12, 13, 14, 15},
-	.oobfree = {
-		{ .offset = 0, .length = 4 },
-		{ .offset = 6, .length = 4 },
-	},
+static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 6;
+	oobregion->offset = 10;
+
+	return 0;
+}
+
+static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 4;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = 4;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+	.ecc = lpc32xx_ooblayout_ecc,
+	.free = lpc32xx_ooblayout_free,
 };
 
 static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
@@ -886,7 +911,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	 * custom BBT marker layout.
 	 */
 	if (mtd->writesize <= 512)
-		chip->ecc.layout = &lpc32xx_nand_oob_16;
+		mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
 
 	/* These sizes remain the same regardless of page size */
 	chip->ecc.size = 256;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: s3c2410: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001Bf-9G@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=bf01e06b32c6cb4b1a08d03434b4559974656669
Commit:     bf01e06b32c6cb4b1a08d03434b4559974656669
Parent:     39980c5616d6a4723143e258550f2844e0138d36
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:03:30 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:47 2016 +0200

    mtd: nand: s3c2410: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/s3c2410.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 86ffb73..4c043db 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -84,11 +84,33 @@
 
 /* new oob placement block for use with hardware ecc generation
  */
+static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = 8;
+
+	return 0;
+}
 
-static struct nand_ecclayout nand_hw_eccoob = {
-	.eccbytes = 3,
-	.eccpos = {0, 1, 2},
-	.oobfree = {{8, 8}}
+static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
+	.ecc = s3c2410_ooblayout_ecc,
+	.free = s3c2410_ooblayout_free,
 };
 
 /* controller and mtd information */
@@ -920,7 +942,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 	} else {
 		chip->ecc.size	    = 512;
 		chip->ecc.bytes	    = 3;
-		chip->ecc.layout    = &nand_hw_eccoob;
+		mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
 	}
 }
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: sh_flctl: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001CI-F5@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e7049f298ecc39f6917d72542effabab64c2bce8
Commit:     e7049f298ecc39f6917d72542effabab64c2bce8
Parent:     bf01e06b32c6cb4b1a08d03434b4559974656669
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:03:47 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:47 2016 +0200

    mtd: nand: sh_flctl: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sh_flctl.c | 87 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 67 insertions(+), 20 deletions(-)

diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 4814402..fa46610 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -43,26 +43,73 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/sh_flctl.h>
 
-static struct nand_ecclayout flctl_4secc_oob_16 = {
-	.eccbytes = 10,
-	.eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
-	.oobfree = {
-		{.offset = 12,
-		. length = 4} },
+static int flctl_4secc_ooblayout_sp_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int flctl_4secc_ooblayout_sp_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 12;
+	oobregion->length = 4;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
+	.ecc = flctl_4secc_ooblayout_sp_ecc,
+	.free = flctl_4secc_ooblayout_sp_free,
 };
 
-static struct nand_ecclayout flctl_4secc_oob_64 = {
-	.eccbytes = 4 * 10,
-	.eccpos = {
-		 6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-		38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-		54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
-	.oobfree = {
-		{.offset =  2, .length = 4},
-		{.offset = 16, .length = 6},
-		{.offset = 32, .length = 6},
-		{.offset = 48, .length = 6} },
+static int flctl_4secc_ooblayout_lp_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 6;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int flctl_4secc_ooblayout_lp_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = section * 16;
+	oobregion->length = 6;
+
+	if (!section) {
+		oobregion->offset += 2;
+		oobregion->length -= 2;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
+	.ecc = flctl_4secc_ooblayout_lp_ecc,
+	.free = flctl_4secc_ooblayout_lp_free,
 };
 
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -987,10 +1034,10 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
 
 	if (flctl->hwecc) {
 		if (mtd->writesize == 512) {
-			chip->ecc.layout = &flctl_4secc_oob_16;
+			mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
 			chip->badblock_pattern = &flctl_4secc_smallpage;
 		} else {
-			chip->ecc.layout = &flctl_4secc_oob_64;
+			mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
 			chip->badblock_pattern = &flctl_4secc_largepage;
 		}
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: sm_common: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001Cq-L7@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=987b913c2b7e440e9784724d138cdaf8440f34c6
Commit:     987b913c2b7e440e9784724d138cdaf8440f34c6
Parent:     e7049f298ecc39f6917d72542effabab64c2bce8
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:04:59 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:48 2016 +0200

    mtd: nand: sm_common: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sm_common.c | 93 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 77 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
index c514740..5939dff 100644
--- a/drivers/mtd/nand/sm_common.c
+++ b/drivers/mtd/nand/sm_common.c
@@ -12,14 +12,47 @@
 #include <linux/sizes.h>
 #include "sm_common.h"
 
-static struct nand_ecclayout nand_oob_sm = {
-	.eccbytes = 6,
-	.eccpos = {8, 9, 10, 13, 14, 15},
-	.oobfree = {
-		{.offset = 0 , .length = 4}, /* reserved */
-		{.offset = 6 , .length = 2}, /* LBA1 */
-		{.offset = 11, .length = 2}  /* LBA2 */
+static int oob_sm_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	oobregion->length = 3;
+	oobregion->offset = ((section + 1) * 8) - 3;
+
+	return 0;
+}
+
+static int oob_sm_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	switch (section) {
+	case 0:
+		/* reserved */
+		oobregion->offset = 0;
+		oobregion->length = 4;
+		break;
+	case 1:
+		/* LBA1 */
+		oobregion->offset = 6;
+		oobregion->length = 2;
+		break;
+	case 2:
+		/* LBA2 */
+		oobregion->offset = 11;
+		oobregion->length = 2;
+		break;
+	default:
+		return -ERANGE;
 	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops oob_sm_ops = {
+	.ecc = oob_sm_ooblayout_ecc,
+	.free = oob_sm_ooblayout_free,
 };
 
 /* NOTE: This layout is is not compatabable with SmartMedia, */
@@ -28,15 +61,43 @@ static struct nand_ecclayout nand_oob_sm = {
 /* If you use smftl, it will bypass this and work correctly */
 /* If you not, then you break SmartMedia compliance anyway */
 
-static struct nand_ecclayout nand_oob_sm_small = {
-	.eccbytes = 3,
-	.eccpos = {0, 1, 2},
-	.oobfree = {
-		{.offset = 3 , .length = 2}, /* reserved */
-		{.offset = 6 , .length = 2}, /* LBA1 */
+static int oob_sm_small_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 3;
+	oobregion->offset = 0;
+
+	return 0;
+}
+
+static int oob_sm_small_ooblayout_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	switch (section) {
+	case 0:
+		/* reserved */
+		oobregion->offset = 3;
+		oobregion->length = 2;
+		break;
+	case 1:
+		/* LBA1 */
+		oobregion->offset = 6;
+		oobregion->length = 2;
+		break;
+	default:
+		return -ERANGE;
 	}
-};
 
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops oob_sm_small_ops = {
+	.ecc = oob_sm_small_ooblayout_ecc,
+	.free = oob_sm_small_ooblayout_free,
+};
 
 static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
@@ -121,9 +182,9 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
 
 	/* ECC layout */
 	if (mtd->writesize == SM_SECTOR_SIZE)
-		chip->ecc.layout = &nand_oob_sm;
+		mtd_set_ooblayout(mtd, &oob_sm_ops);
 	else if (mtd->writesize == SM_SMALL_PAGE)
-		chip->ecc.layout = &nand_oob_sm_small;
+		mtd_set_ooblayout(mtd, &oob_sm_small_ops);
 	else
 		return -ENODEV;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: sunxi: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001DM-QP@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c66811e6d350dda53624d1bb4a15698a375b9e79
Commit:     c66811e6d350dda53624d1bb4a15698a375b9e79
Parent:     987b913c2b7e440e9784724d138cdaf8440f34c6
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:05:13 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:48 2016 +0200

    mtd: nand: sunxi: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sunxi_nand.c | 114 +++++++++++++++++++-----------------------
 1 file changed, 52 insertions(+), 62 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index b12ed83..1baf8983 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -211,12 +211,9 @@ struct sunxi_nand_chip_sel {
  * sunxi HW ECC infos: stores information related to HW ECC support
  *
  * @mode:	the sunxi ECC mode field deduced from ECC requirements
- * @layout:	the OOB layout depending on the ECC requirements and the
- *		selected ECC mode
  */
 struct sunxi_nand_hw_ecc {
 	int mode;
-	struct nand_ecclayout layout;
 };
 
 /*
@@ -1436,6 +1433,57 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
 	return sunxi_nand_chip_set_timings(chip, timings);
 }
 
+static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+	if (section >= ecc->steps)
+		return -ERANGE;
+
+	oobregion->offset = section * (ecc->bytes + 4) + 4;
+	oobregion->length = ecc->bytes;
+
+	return 0;
+}
+
+static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+	if (section > ecc->steps)
+		return -ERANGE;
+
+	/*
+	 * The first 2 bytes are used for BB markers, hence we
+	 * only have 2 bytes available in the first user data
+	 * section.
+	 */
+	if (!section && ecc->mode == NAND_ECC_HW) {
+		oobregion->offset = 2;
+		oobregion->length = 2;
+
+		return 0;
+	}
+
+	oobregion->offset = section * (ecc->bytes + 4);
+
+	if (section < ecc->steps)
+		oobregion->length = 4;
+	else
+		oobregion->offset = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
+	.ecc = sunxi_nand_ooblayout_ecc,
+	.free = sunxi_nand_ooblayout_free,
+};
+
 static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 					      struct nand_ecc_ctrl *ecc,
 					      struct device_node *np)
@@ -1445,7 +1493,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
 	struct sunxi_nand_hw_ecc *data;
-	struct nand_ecclayout *layout;
 	int nsectors;
 	int ret;
 	int i;
@@ -1474,7 +1521,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 	/* HW ECC always work with even numbers of ECC bytes */
 	ecc->bytes = ALIGN(ecc->bytes, 2);
 
-	layout = &data->layout;
 	nsectors = mtd->writesize / ecc->size;
 
 	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
@@ -1482,11 +1528,9 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 		goto err;
 	}
 
-	layout->eccbytes = (ecc->bytes * nsectors);
-
 	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
 	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
-	ecc->layout = layout;
+	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
 	ecc->priv = data;
 
 	return 0;
@@ -1506,9 +1550,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
 				       struct nand_ecc_ctrl *ecc,
 				       struct device_node *np)
 {
-	struct nand_ecclayout *layout;
-	int nsectors;
-	int i, j;
 	int ret;
 
 	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1520,40 +1561,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
 	ecc->read_oob_raw = nand_read_oob_std;
 	ecc->write_oob_raw = nand_write_oob_std;
 	ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
-	layout = ecc->layout;
-	nsectors = mtd->writesize / ecc->size;
-
-	for (i = 0; i < nsectors; i++) {
-		if (i) {
-			layout->oobfree[i].offset =
-				layout->oobfree[i - 1].offset +
-				layout->oobfree[i - 1].length +
-				ecc->bytes;
-			layout->oobfree[i].length = 4;
-		} else {
-			/*
-			 * The first 2 bytes are used for BB markers, hence we
-			 * only have 2 bytes available in the first user data
-			 * section.
-			 */
-			layout->oobfree[i].length = 2;
-			layout->oobfree[i].offset = 2;
-		}
-
-		for (j = 0; j < ecc->bytes; j++)
-			layout->eccpos[(ecc->bytes * i) + j] =
-					layout->oobfree[i].offset +
-					layout->oobfree[i].length + j;
-	}
-
-	if (mtd->oobsize > (ecc->bytes + 4) * nsectors) {
-		layout->oobfree[nsectors].offset =
-				layout->oobfree[nsectors - 1].offset +
-				layout->oobfree[nsectors - 1].length +
-				ecc->bytes;
-		layout->oobfree[nsectors].length = mtd->oobsize -
-				((ecc->bytes + 4) * nsectors);
-	}
 
 	return 0;
 }
@@ -1562,9 +1569,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
 						struct nand_ecc_ctrl *ecc,
 						struct device_node *np)
 {
-	struct nand_ecclayout *layout;
-	int nsectors;
-	int i;
 	int ret;
 
 	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1577,15 +1581,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
 	ecc->read_oob_raw = nand_read_oob_syndrome;
 	ecc->write_oob_raw = nand_write_oob_syndrome;
 
-	layout = ecc->layout;
-	nsectors = mtd->writesize / ecc->size;
-
-	for (i = 0; i < (ecc->bytes * nsectors); i++)
-		layout->eccpos[i] = i;
-
-	layout->oobfree[0].length = mtd->oobsize - i;
-	layout->oobfree[0].offset = i;
-
 	return 0;
 }
 
@@ -1597,7 +1592,6 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
 		sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
 		break;
 	case NAND_ECC_NONE:
-		kfree(ecc->layout);
 	default:
 		break;
 	}
@@ -1631,10 +1625,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
 			return ret;
 		break;
 	case NAND_ECC_NONE:
-		ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL);
-		if (!ecc->layout)
-			return -ENOMEM;
-		ecc->layout->oobfree[0].length = mtd->oobsize;
 	case NAND_ECC_SOFT:
 		break;
 	default:


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: vf610: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001Dp-Tb@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=3cf32d180227c1a1f5e017c997085d52a10a106f
Commit:     3cf32d180227c1a1f5e017c997085d52a10a106f
Parent:     c66811e6d350dda53624d1bb4a15698a375b9e79
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:05:45 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:48 2016 +0200

    mtd: nand: vf610: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Tested-by: Stefan Agner <stefan at agner.ch>
    Acked-by: Stefan Agner <stefan at agner.ch>
---
 drivers/mtd/nand/vf610_nfc.c | 34 ++++------------------------------
 1 file changed, 4 insertions(+), 30 deletions(-)

diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index a7f2756..3ad514c 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -174,34 +174,6 @@ static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
 	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
 }
 
-static struct nand_ecclayout vf610_nfc_ecc45 = {
-	.eccbytes = 45,
-	.eccpos = {19, 20, 21, 22, 23,
-		   24, 25, 26, 27, 28, 29, 30, 31,
-		   32, 33, 34, 35, 36, 37, 38, 39,
-		   40, 41, 42, 43, 44, 45, 46, 47,
-		   48, 49, 50, 51, 52, 53, 54, 55,
-		   56, 57, 58, 59, 60, 61, 62, 63},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 17} }
-};
-
-static struct nand_ecclayout vf610_nfc_ecc60 = {
-	.eccbytes = 60,
-	.eccpos = { 4,  5,  6,  7,  8,  9, 10, 11,
-		   12, 13, 14, 15, 16, 17, 18, 19,
-		   20, 21, 22, 23, 24, 25, 26, 27,
-		   28, 29, 30, 31, 32, 33, 34, 35,
-		   36, 37, 38, 39, 40, 41, 42, 43,
-		   44, 45, 46, 47, 48, 49, 50, 51,
-		   52, 53, 54, 55, 56, 57, 58, 59,
-		   60, 61, 62, 63 },
-	.oobfree = {
-		{.offset = 2,
-		 .length = 2} }
-};
-
 static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
 {
 	return readl(nfc->regs + reg);
@@ -780,14 +752,16 @@ static int vf610_nfc_probe(struct platform_device *pdev)
 		if (mtd->oobsize > 64)
 			mtd->oobsize = 64;
 
+		/*
+		 * mtd->ecclayout is not specified here because we're using the
+		 * default large page ECC layout defined in NAND core.
+		 */
 		if (chip->ecc.strength == 32) {
 			nfc->ecc_mode = ECC_60_BYTE;
 			chip->ecc.bytes = 60;
-			chip->ecc.layout = &vf610_nfc_ecc60;
 		} else if (chip->ecc.strength == 24) {
 			nfc->ecc_mode = ECC_45_BYTE;
 			chip->ecc.bytes = 45;
-			chip->ecc.layout = &vf610_nfc_ecc45;
 		} else {
 			dev_err(nfc->dev, "Unsupported ECC strength\n");
 			err = -ENXIO;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: mtd: nand: qcom: switch to mtd_ooblayout_ops
Message-ID: <E1b54R5-0001EJ-1v@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=421e81c4c6c03a5f6cbc40ea208fb07ad5797e09
Commit:     421e81c4c6c03a5f6cbc40ea208fb07ad5797e09
Parent:     3cf32d180227c1a1f5e017c997085d52a10a106f
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Mar 18 17:54:27 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:49 2016 +0200

    mtd: nand: qcom: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Tested-by: Archit Taneja <architt at codeaurora.org>
---
 drivers/mtd/nand/qcom_nandc.c | 79 +++++++++++++++++++------------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index 4ea2cb7..de7d28e 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -1707,61 +1707,52 @@ static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
  * This layout is read as is when ECC is disabled. When ECC is enabled, the
  * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
  * and assumed as 0xffs when we read a page/oob. The ECC, unused and
- * dummy/real bad block bytes are grouped as ecc bytes in nand_ecclayout (i.e,
- * ecc->bytes is the sum of the three).
+ * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
+ * the sum of the three).
  */
-
-static struct nand_ecclayout *
-qcom_nand_create_layout(struct qcom_nand_host *host)
+static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
 {
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct nand_ecclayout *layout;
-	int i, j, steps, pos = 0, shift = 0;
 
-	layout = devm_kzalloc(nandc->dev, sizeof(*layout), GFP_KERNEL);
-	if (!layout)
-		return NULL;
+	if (section > 1)
+		return -ERANGE;
 
-	steps = mtd->writesize / ecc->size;
-	layout->eccbytes = steps * ecc->bytes;
-
-	layout->oobfree[0].offset = (steps - 1) * ecc->bytes + host->bbm_size;
-	layout->oobfree[0].length = steps << 2;
-
-	/*
-	 * the oob bytes in the first n - 1 codewords are all grouped together
-	 * in the format:
-	 * DUMMY_BBM + UNUSED + ECC
-	 */
-	for (i = 0; i < steps - 1; i++) {
-		for (j = 0; j < ecc->bytes; j++)
-			layout->eccpos[pos++] = i * ecc->bytes + j;
+	if (!section) {
+		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
+				    host->bbm_size;
+		oobregion->offset = 0;
+	} else {
+		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
+		oobregion->offset = mtd->oobsize - oobregion->length;
 	}
 
-	/*
-	 * the oob bytes in the last codeword are grouped in the format:
-	 * BBM + FREE OOB + UNUSED + ECC
-	 */
+	return 0;
+}
 
-	/* fill up the bbm positions */
-	for (j = 0; j < host->bbm_size; j++)
-		layout->eccpos[pos++] = i * ecc->bytes + j;
+static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-	/*
-	 * fill up the ecc and reserved positions, their indices are offseted
-	 * by the free oob region
-	 */
-	shift = layout->oobfree[0].length + host->bbm_size;
+	if (section)
+		return -ERANGE;
 
-	for (j = 0; j < (host->ecc_bytes_hw + host->spare_bytes); j++)
-		layout->eccpos[pos++] = i * ecc->bytes + shift + j;
+	oobregion->length = ecc->steps * 4;
+	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
 
-	return layout;
+	return 0;
 }
 
+static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
+	.ecc = qcom_nand_ooblayout_ecc,
+	.free = qcom_nand_ooblayout_free,
+};
+
 static int qcom_nand_host_setup(struct qcom_nand_host *host)
 {
 	struct nand_chip *chip = &host->chip;
@@ -1848,9 +1839,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
 
 	ecc->mode = NAND_ECC_HW;
 
-	ecc->layout = qcom_nand_create_layout(host);
-	if (!ecc->layout)
-		return -ENOMEM;
+	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
 
 	cwperpage = mtd->writesize / ecc->size;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: mtd: onenand: switch to mtd_ooblayout_ops
Message-ID: <E1b54R5-0001Er-7y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=a411679fb5fd7ee2df64a55c23c81538ceeb6d06
Commit:     a411679fb5fd7ee2df64a55c23c81538ceeb6d06
Parent:     421e81c4c6c03a5f6cbc40ea208fb07ad5797e09
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Mon Dec 7 22:46:45 2015 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:49 2016 +0200

    mtd: onenand: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users. Modify the onenand drivers to switch to this
    approach.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/onenand/onenand_base.c | 162 ++++++++++++++++++++++---------------
 include/linux/mtd/onenand.h        |   2 -
 2 files changed, 97 insertions(+), 67 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index d0fa505..a4b029a 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -68,21 +68,33 @@ MODULE_PARM_DESC(otp,	"Corresponding behaviour of OneNAND in OTP"
  * flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page
  * For now, we expose only 64 out of 80 ecc bytes
  */
-static struct nand_ecclayout flexonenand_oob_128 = {
-	.eccbytes	= 64,
-	.eccpos		= {
-		6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-		38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-		54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-		70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-		86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
-		102, 103, 104, 105
-		},
-	.oobfree	= {
-		{2, 4}, {18, 4}, {34, 4}, {50, 4},
-		{66, 4}, {82, 4}, {98, 4}, {114, 4}
-	}
+static int flexonenand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 6;
+	oobregion->length = 10;
+
+	return 0;
+}
+
+static int flexonenand_ooblayout_free(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 2;
+	oobregion->length = 4;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops flexonenand_ooblayout_ops = {
+	.ecc = flexonenand_ooblayout_ecc,
+	.free = flexonenand_ooblayout_free,
 };
 
 /*
@@ -91,56 +103,77 @@ static struct nand_ecclayout flexonenand_oob_128 = {
  * Based on specification:
  * 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010
  *
- * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout)
- *
- * oobfree uses the spare area fields marked as
- * "Managed by internal ECC logic for Logical Sector Number area"
- */
-static struct nand_ecclayout onenand_oob_128 = {
-	.eccbytes	= 64,
-	.eccpos		= {
-		7, 8, 9, 10, 11, 12, 13, 14, 15,
-		23, 24, 25, 26, 27, 28, 29, 30, 31,
-		39, 40, 41, 42, 43, 44, 45, 46, 47,
-		55, 56, 57, 58, 59, 60, 61, 62, 63,
-		71, 72, 73, 74, 75, 76, 77, 78, 79,
-		87, 88, 89, 90, 91, 92, 93, 94, 95,
-		103, 104, 105, 106, 107, 108, 109, 110, 111,
-		119
-	},
-	.oobfree	= {
-		{2, 3}, {18, 3}, {34, 3}, {50, 3},
-		{66, 3}, {82, 3}, {98, 3}, {114, 3}
-	}
+ */
+static int onenand_ooblayout_128_ecc(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 7;
+	oobregion->length = 9;
+
+	return 0;
+}
+
+static int onenand_ooblayout_128_free(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section >= 8)
+		return -ERANGE;
+
+	/*
+	 * free bytes are using the spare area fields marked as
+	 * "Managed by internal ECC logic for Logical Sector Number area"
+	 */
+	oobregion->offset = (section * 16) + 2;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops onenand_oob_128_ooblayout_ops = {
+	.ecc = onenand_ooblayout_128_ecc,
+	.free = onenand_ooblayout_128_free,
 };
 
 /**
- * onenand_oob_64 - oob info for large (2KB) page
+ * onenand_oob_32_64 - oob info for large (2KB) page
  */
-static struct nand_ecclayout onenand_oob_64 = {
-	.eccbytes	= 20,
-	.eccpos		= {
-		8, 9, 10, 11, 12,
-		24, 25, 26, 27, 28,
-		40, 41, 42, 43, 44,
-		56, 57, 58, 59, 60,
-		},
-	.oobfree	= {
-		{2, 3}, {14, 2}, {18, 3}, {30, 2},
-		{34, 3}, {46, 2}, {50, 3}, {62, 2}
+static int onenand_ooblayout_32_64_ecc(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 8;
+	oobregion->length = 5;
+
+	return 0;
+}
+
+static int onenand_ooblayout_32_64_free(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	int sections = (mtd->oobsize / 32) * 2;
+
+	if (section >= sections)
+		return -ERANGE;
+
+	if (section & 1) {
+		oobregion->offset = ((section - 1) * 16) + 14;
+		oobregion->length = 2;
+	} else  {
+		oobregion->offset = (section * 16) + 2;
+		oobregion->length = 3;
 	}
-};
 
-/**
- * onenand_oob_32 - oob info for middle (1KB) page
- */
-static struct nand_ecclayout onenand_oob_32 = {
-	.eccbytes	= 10,
-	.eccpos		= {
-		8, 9, 10, 11, 12,
-		24, 25, 26, 27, 28,
-		},
-	.oobfree	= { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops onenand_oob_32_64_ooblayout_ops = {
+	.ecc = onenand_ooblayout_32_64_ecc,
+	.free = onenand_ooblayout_32_64_free,
 };
 
 static const unsigned char ffchars[] = {
@@ -3957,22 +3990,22 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 	switch (mtd->oobsize) {
 	case 128:
 		if (FLEXONENAND(this)) {
-			this->ecclayout = &flexonenand_oob_128;
+			mtd_set_ooblayout(mtd, &flexonenand_ooblayout_ops);
 			mtd->subpage_sft = 0;
 		} else {
-			this->ecclayout = &onenand_oob_128;
+			mtd_set_ooblayout(mtd, &onenand_oob_128_ooblayout_ops);
 			mtd->subpage_sft = 2;
 		}
 		if (ONENAND_IS_NOP_1(this))
 			mtd->subpage_sft = 0;
 		break;
 	case 64:
-		this->ecclayout = &onenand_oob_64;
+		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
 		mtd->subpage_sft = 2;
 		break;
 
 	case 32:
-		this->ecclayout = &onenand_oob_32;
+		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
 		mtd->subpage_sft = 1;
 		break;
 
@@ -3981,7 +4014,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 			__func__, mtd->oobsize);
 		mtd->subpage_sft = 0;
 		/* To prevent kernel oops */
-		this->ecclayout = &onenand_oob_32;
+		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
 		break;
 	}
 
@@ -3997,7 +4030,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 
 	mtd->oobavail = ret;
 
-	mtd_set_ecclayout(mtd, this->ecclayout);
 	mtd->ecc_strength = 1;
 
 	/* Fill in remaining MTD driver data */
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4596503..0aaa98b 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -80,7 +80,6 @@ struct onenand_bufferram {
  * @page_buf:		[INTERN] page main data buffer
  * @oob_buf:		[INTERN] page oob data buffer
  * @subpagesize:	[INTERN] holds the subpagesize
- * @ecclayout:		[REPLACEABLE] the default ecc placement scheme
  * @bbm:		[REPLACEABLE] pointer to Bad Block Management
  * @priv:		[OPTIONAL] pointer to private chip date
  */
@@ -134,7 +133,6 @@ struct onenand_chip {
 #endif
 
 	int			subpagesize;
-	struct nand_ecclayout	*ecclayout;
 
 	void			*bbm;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: staging: mt29f_spinand: switch to mtd_ooblayout_ops
Message-ID: <E1b54R5-0001FP-DS@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e1d132b4ae3b5dfc897cf117419404b22caf6892
Commit:     e1d132b4ae3b5dfc897cf117419404b22caf6892
Parent:     a411679fb5fd7ee2df64a55c23c81538ceeb6d06
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:13:39 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:50 2016 +0200

    staging: mt29f_spinand: switch to mtd_ooblayout_ops
    
    Replace the nand_ecclayout definition by the equivalent mtd_ooblayout_ops
    definition.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/staging/mt29f_spinand/mt29f_spinand.c | 48 +++++++++++++++++----------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 163f21a..f503699 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -42,23 +42,33 @@ static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
 static int enable_hw_ecc;
 static int enable_read_hw_ecc;
 
-static struct nand_ecclayout spinand_oob_64 = {
-	.eccbytes = 24,
-	.eccpos = {
-		1, 2, 3, 4, 5, 6,
-		17, 18, 19, 20, 21, 22,
-		33, 34, 35, 36, 37, 38,
-		49, 50, 51, 52, 53, 54, },
-	.oobfree = {
-		{.offset = 8,
-			.length = 8},
-		{.offset = 24,
-			.length = 8},
-		{.offset = 40,
-			.length = 8},
-		{.offset = 56,
-			.length = 8},
-	}
+static int spinand_ooblayout_64_ecc(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 1;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static int spinand_ooblayout_64_free(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 8;
+	oobregion->length = 8;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops spinand_oob_64_ops = {
+	.ecc = spinand_ooblayout_64_ecc,
+	.free = spinand_ooblayout_64_free,
 };
 #endif
 
@@ -886,7 +896,6 @@ static int spinand_probe(struct spi_device *spi_nand)
 
 	chip->ecc.strength = 1;
 	chip->ecc.total	= chip->ecc.steps * chip->ecc.bytes;
-	chip->ecc.layout = &spinand_oob_64;
 	chip->ecc.read_page = spinand_read_page_hwecc;
 	chip->ecc.write_page = spinand_write_page_hwecc;
 #else
@@ -912,6 +921,9 @@ static int spinand_probe(struct spi_device *spi_nand)
 
 	mtd->dev.parent = &spi_nand->dev;
 	mtd->oobsize = 64;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
+#endif
 
 	if (nand_scan(mtd, 1))
 		return -ENXIO;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: mtd: nand: kill the ecc->layout field
Message-ID: <E1b54R5-0001G4-Ip@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=7f2b092c9eeda055ae60af194a8edacaea5f7a10
Commit:     7f2b092c9eeda055ae60af194a8edacaea5f7a10
Parent:     e1d132b4ae3b5dfc897cf117419404b22caf6892
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 19:24:10 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:50 2016 +0200

    mtd: nand: kill the ecc->layout field
    
    Now that all NAND drivers have switched to mtd_ooblayout_ops, we can kill
    the ecc->layout field.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 7 -------
 drivers/mtd/nand/nand_bch.c  | 8 --------
 include/linux/mtd/nand.h     | 2 --
 3 files changed, 17 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6c84a40..0001be1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4152,13 +4152,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
 
 	/*
-	 * Set the provided ECC layout. If ecc->layout is NULL, the MTD core
-	 * will just leave mtd->ooblayout to NULL, if it's not NULL, it will
-	 * set ->ooblayout to the default ecclayout wrapper.
-	 */
-	mtd_set_ecclayout(mtd, ecc->layout);
-
-	/*
 	 * If no default placement scheme is given, select an appropriate one.
 	 */
 	if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 1dbc418..28ef7b1 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -158,14 +158,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 
 	eccsteps = mtd->writesize/eccsize;
 
-	/*
-	 * Rely on the default ecclayout to ooblayout wrapper provided by MTD
-	 * core if ecc.layout is not NULL.
-	 * FIXME: this should be removed when all callers have moved to the
-	 * mtd_ooblayout_ops approach.
-	 */
-	mtd_set_ecclayout(mtd, nand->ecc.layout);
-
 	/* Check that we have an oob layout description. */
 	if (!mtd->ooblayout) {
 		pr_warn("missing oob scheme");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index f2ded7b..e851839 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -473,7 +473,6 @@ struct nand_hw_control {
  * @prepad:	padding information for syndrome based ECC generators
  * @postpad:	padding information for syndrome based ECC generators
  * @options:	ECC specific options (see NAND_ECC_XXX flags defined above)
- * @layout:	ECC layout control struct pointer
  * @priv:	pointer to private ECC control data
  * @hwctl:	function to control hardware ECC generator. Must only
  *		be provided if an hardware ECC is available
@@ -524,7 +523,6 @@ struct nand_ecc_ctrl {
 	int prepad;
 	int postpad;
 	unsigned int options;
-	struct nand_ecclayout	*layout;
 	void *priv;
 	void (*hwctl)(struct mtd_info *mtd, int mode);
 	int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: mtd: kill the nand_ecclayout struct
Message-ID: <E1b54R5-0001Gl-QB@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=aab616e31d1c7ec3726f7f5cbdaaec98759ebe93
Commit:     aab616e31d1c7ec3726f7f5cbdaaec98759ebe93
Parent:     7f2b092c9eeda055ae60af194a8edacaea5f7a10
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Thu Feb 4 10:16:18 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:51 2016 +0200

    mtd: kill the nand_ecclayout struct
    
    Now that all MTD drivers have moved to the mtd_ooblayout_ops model we can
    safely remove the struct nand_ecclayout definition, and all the remaining
    places where it was still used.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/mtdchar.c      |  12 ++---
 drivers/mtd/mtdcore.c      | 117 ---------------------------------------------
 include/linux/mtd/mtd.h    |  20 --------
 include/uapi/mtd/mtd-abi.h |   2 +-
 4 files changed, 7 insertions(+), 144 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 3fad2c7..2a47a3f 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -465,12 +465,12 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
 }
 
 /*
- * Copies (and truncates, if necessary) data from the larger struct,
- * nand_ecclayout, to the smaller, deprecated layout struct,
- * nand_ecclayout_user. This is necessary only to support the deprecated
- * API ioctl ECCGETLAYOUT while allowing all new functionality to use
- * nand_ecclayout flexibly (i.e. the struct may change size in new
- * releases without requiring major rewrites).
+ * Copies (and truncates, if necessary) OOB layout information to the
+ * deprecated layout struct, nand_ecclayout_user. This is necessary only to
+ * support the deprecated API ioctl ECCGETLAYOUT while allowing all new
+ * functionality to use mtd_ooblayout_ops flexibly (i.e. mtd_ooblayout_ops
+ * can describe any kind of OOB layout with almost zero overhead from a
+ * memory usage point of view).
  */
 static int shrink_ecclayout(struct mtd_info *mtd,
 			    struct nand_ecclayout_user *to)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 134ed2f..e3936b8 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1376,123 +1376,6 @@ int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
 
-/**
- * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation
- * @mtd: MTD device structure
- * @section: ECC section. Depending on the layout you may have all the ECC
- *	     bytes stored in a single contiguous section, or one section
- *	     per ECC chunk (and sometime several sections for a single ECC
- *	     ECC chunk)
- * @oobecc: OOB region struct filled with the appropriate ECC position
- *	    information
- *
- * This function is just a wrapper around the mtd->ecclayout field and is
- * here to ease the transition to the mtd_ooblayout_ops approach.
- * All it does is convert the layout->eccpos information into proper oob
- * region definitions.
- *
- * Returns zero on success, a negative error code otherwise.
- */
-static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section,
-			     struct mtd_oob_region *oobecc)
-{
-	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
-
-	if (!mtd->ecclayout)
-		return -ENOTSUPP;
-
-	/*
-	 * This logic allows us to reuse the ->ecclayout information and
-	 * expose them as ECC regions (as done for the OOB free regions).
-	 *
-	 * TODO: this should be dropped as soon as we get rid of the
-	 * ->ecclayout field.
-	 */
-	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
-		eccpos = mtd->ecclayout->eccpos[eccbyte];
-
-		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
-			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
-
-			if (eccpos + 1 == neccpos) {
-				length++;
-				continue;
-			}
-		}
-
-		if (section == cursection)
-			break;
-
-		length = 0;
-		cursection++;
-	}
-
-	if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
-		return -ERANGE;
-
-	oobecc->length = length + 1;
-	oobecc->offset = eccpos - length;
-
-	return 0;
-}
-
-/**
- * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation
- * @mtd: MTD device structure
- * @section: Free section. Depending on the layout you may have all the free
- *	     bytes stored in a single contiguous section, or one section
- *	     per ECC chunk (and sometime several sections for a single ECC
- *	     ECC chunk)
- * @oobfree: OOB region struct filled with the appropriate free position
- *	     information
- *
- * This function is just a wrapper around the mtd->ecclayout field and is
- * here to ease the transition to the mtd_ooblayout_ops approach.
- * All it does is convert the layout->oobfree information into proper oob
- * region definitions.
- *
- * Returns zero on success, a negative error code otherwise.
- */
-static int mtd_ecclayout_free(struct mtd_info *mtd, int section,
-			      struct mtd_oob_region *oobfree)
-{
-	struct nand_ecclayout *layout = mtd->ecclayout;
-
-	if (!layout)
-		return -ENOTSUPP;
-
-	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE ||
-	    !layout->oobfree[section].length)
-		return -ERANGE;
-
-	oobfree->offset = layout->oobfree[section].offset;
-	oobfree->length = layout->oobfree[section].length;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = {
-	.ecc = mtd_ecclayout_ecc,
-	.free = mtd_ecclayout_free,
-};
-
-/**
- * mtd_set_ecclayout - Attach an ecclayout to an MTD device
- * @mtd: MTD device structure
- * @ecclayout: The ecclayout to attach to the device
- *
- * Returns zero on success, a negative error code otherwise.
- */
-void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
-{
-	if (!mtd || !ecclayout)
-		return;
-
-	mtd->ecclayout = ecclayout;
-	mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops);
-}
-EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
-
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 177bf31..29a1706 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -96,21 +96,6 @@ struct mtd_oob_ops {
 
 #define MTD_MAX_OOBFREE_ENTRIES_LARGE	32
 #define MTD_MAX_ECCPOS_ENTRIES_LARGE	640
-/*
- * Internal ECC layout control structure. For historical reasons, there is a
- * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
- * for export to user-space via the ECCGETLAYOUT ioctl.
- * nand_ecclayout should be expandable in the future simply by the above macros.
- *
- * This structure is now deprecated, you should use struct nand_ecclayout_ops
- * to describe your OOB layout.
- */
-struct nand_ecclayout {
-	__u32 eccbytes;
-	__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
-	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
-};
-
 /**
  * struct mtd_oob_region - oob region definition
  * @offset: region offset
@@ -200,9 +185,6 @@ struct mtd_info {
 	const char *name;
 	int index;
 
-	/* [Deprecated] ECC layout structure pointer - read only! */
-	struct nand_ecclayout *ecclayout;
-
 	/* OOB layout description */
 	const struct mtd_ooblayout_ops *ooblayout;
 
@@ -308,8 +290,6 @@ int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
 int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
 int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
 
-void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
-
 static inline void mtd_set_ooblayout(struct mtd_info *mtd,
 				     const struct mtd_ooblayout_ops *ooblayout)
 {
diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index 763bb69..0ec1da2 100644
--- a/include/uapi/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
@@ -228,7 +228,7 @@ struct nand_oobfree {
  * complete set of ECC information. The ioctl truncates the larger internal
  * structure to retain binary compatibility with the static declaration of the
  * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
- * the user struct, not the MAX size of the internal struct nand_ecclayout.
+ * the user struct, not the MAX size of the internal OOB layout representation.
  */
 struct nand_ecclayout_user {
 	__u32 eccbytes;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:19 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:19 +0000
Subject: mtd: nand: omap2: set ECC algorithm explicitly
Message-ID: <E1b54R5-0001HG-UE@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d7b83b8a6dda3edada04f9395e2ef6463e099277
Commit:     d7b83b8a6dda3edada04f9395e2ef6463e099277
Parent:     aab616e31d1c7ec3726f7f5cbdaaec98759ebe93
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:54 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:52 2016 +0200

    mtd: nand: omap2: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 55916786d..16da65b 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -2012,6 +2012,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 */
 	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
 		goto scan_tail;
 	}
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: s3c2410: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001Hl-4O@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c4fe72a733c7749ab2c05e51bd37393525a86e2c
Commit:     c4fe72a733c7749ab2c05e51bd37393525a86e2c
Parent:     d7b83b8a6dda3edada04f9395e2ef6463e099277
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:55 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:52 2016 +0200

    mtd: nand: s3c2410: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/s3c2410.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 4c043db..d9309cf 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -882,6 +882,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 	}
 #else
 	chip->ecc.mode	    = NAND_ECC_SOFT;
+	chip->ecc.algo	= NAND_ECC_HAMMING;
 #endif
 
 	if (set->disable_ecc)


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: sh_flctl: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001IE-8t@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e020cc05915e11bad3a923b52458baa2daac53cc
Commit:     e020cc05915e11bad3a923b52458baa2daac53cc
Parent:     c4fe72a733c7749ab2c05e51bd37393525a86e2c
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:56 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:52 2016 +0200

    mtd: nand: sh_flctl: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sh_flctl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index fa46610..a5abf6f 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -1052,6 +1052,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
 		flctl->flcmncr_base |= _4ECCEN;
 	} else {
 		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
 	}
 
 	return 0;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: au1550nd: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001Ij-Df@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=c2ec6b30a521691b752ac61ee05267133a389834
Commit:     c2ec6b30a521691b752ac61ee05267133a389834
Parent:     e020cc05915e11bad3a923b52458baa2daac53cc
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:57 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:53 2016 +0200

    mtd: nand: au1550nd: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/au1550nd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 341ea49..9bf6d99 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -459,6 +459,7 @@ static int au1550nd_probe(struct platform_device *pdev)
 	/* 30 us command delay time */
 	this->chip_delay = 30;
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	if (pd->devwidth)
 		this->options |= NAND_BUSWIDTH_16;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: mpc5121_nfc: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001JB-J7@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=7079e7ed4a4e8b74a7dc3feafc0e70cc027cab32
Commit:     7079e7ed4a4e8b74a7dc3feafc0e70cc027cab32
Parent:     c2ec6b30a521691b752ac61ee05267133a389834
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:58 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:53 2016 +0200

    mtd: nand: mpc5121_nfc: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/mpc5121_nfc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 5d7843f..7eacb2f 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -710,6 +710,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 	chip->select_chip = mpc5121_nfc_select_chip;
 	chip->bbt_options = NAND_BBT_USE_FLASH;
 	chip->ecc.mode = NAND_ECC_SOFT;
+	chip->ecc.algo = NAND_ECC_HAMMING;
 
 	/* Support external chip-select logic on ADS5121 board */
 	if (of_machine_is_compatible("fsl,mpc5121ads")) {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: cmx270: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001K3-OK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d9944e1fdcd6c363a24577ac64c6d1128152ff6d
Commit:     d9944e1fdcd6c363a24577ac64c6d1128152ff6d
Parent:     7079e7ed4a4e8b74a7dc3feafc0e70cc027cab32
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:06:59 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:54 2016 +0200

    mtd: nand: cmx270: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/cmx270_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 6f97ebb..4913378 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -187,6 +187,7 @@ static int __init cmx270_init(void)
 	/* 15 us command delay time */
 	this->chip_delay = 20;
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	/* read/write functions */
 	this->read_byte = cmx270_read_byte;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: mxc: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-0001A7-O0@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=a894cf6c5a82c7ddcb1bad82d1e0af3d0ead9a41
Commit:     a894cf6c5a82c7ddcb1bad82d1e0af3d0ead9a41
Parent:     d50b5239867f02627fc24c4450a87bd9c3267c0a
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:02:54 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:45 2016 +0200

    mtd: nand: mxc: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/mxc_nand.c | 212 ++++++++++++++++++++++----------------------
 1 file changed, 105 insertions(+), 107 deletions(-)

diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 57b1b74..c4e84e1 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -149,7 +149,7 @@ struct mxc_nand_devtype_data {
 	int (*check_int)(struct mxc_nand_host *);
 	void (*irq_control)(struct mxc_nand_host *, int);
 	u32 (*get_ecc_status)(struct mxc_nand_host *);
-	struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k;
+	const struct mtd_ooblayout_ops *ooblayout;
 	void (*select_chip)(struct mtd_info *mtd, int chip);
 	int (*correct_data)(struct mtd_info *mtd, u_char *dat,
 			u_char *read_ecc, u_char *calc_ecc);
@@ -200,73 +200,6 @@ struct mxc_nand_host {
 	struct mxc_nand_platform_data pdata;
 };
 
-/* OOB placement block for use with hardware ecc generation */
-static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
-	.eccbytes = 5,
-	.eccpos = {6, 7, 8, 9, 10},
-	.oobfree = {{0, 5}, {12, 4}, }
-};
-
-static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
-	.eccbytes = 20,
-	.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
-		   38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
-	.oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
-};
-
-/* OOB description for 512 byte pages with 16 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
-	.eccbytes = 1 * 9,
-	.eccpos = {
-		 7,  8,  9, 10, 11, 12, 13, 14, 15
-	},
-	.oobfree = {
-		{.offset = 0, .length = 5}
-	}
-};
-
-/* OOB description for 2048 byte pages with 64 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
-	.eccbytes = 4 * 9,
-	.eccpos = {
-		 7,  8,  9, 10, 11, 12, 13, 14, 15,
-		23, 24, 25, 26, 27, 28, 29, 30, 31,
-		39, 40, 41, 42, 43, 44, 45, 46, 47,
-		55, 56, 57, 58, 59, 60, 61, 62, 63
-	},
-	.oobfree = {
-		{.offset = 2, .length = 4},
-		{.offset = 16, .length = 7},
-		{.offset = 32, .length = 7},
-		{.offset = 48, .length = 7}
-	}
-};
-
-/* OOB description for 4096 byte pages with 128 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_4k = {
-	.eccbytes = 8 * 9,
-	.eccpos = {
-		7,  8,  9, 10, 11, 12, 13, 14, 15,
-		23, 24, 25, 26, 27, 28, 29, 30, 31,
-		39, 40, 41, 42, 43, 44, 45, 46, 47,
-		55, 56, 57, 58, 59, 60, 61, 62, 63,
-		71, 72, 73, 74, 75, 76, 77, 78, 79,
-		87, 88, 89, 90, 91, 92, 93, 94, 95,
-		103, 104, 105, 106, 107, 108, 109, 110, 111,
-		119, 120, 121, 122, 123, 124, 125, 126, 127,
-	},
-	.oobfree = {
-		{.offset = 2, .length = 4},
-		{.offset = 16, .length = 7},
-		{.offset = 32, .length = 7},
-		{.offset = 48, .length = 7},
-		{.offset = 64, .length = 7},
-		{.offset = 80, .length = 7},
-		{.offset = 96, .length = 7},
-		{.offset = 112, .length = 7},
-	}
-};
-
 static const char * const part_probes[] = {
 	"cmdlinepart", "RedBoot", "ofpart", NULL };
 
@@ -942,6 +875,99 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
 	}
 }
 
+static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 6;
+	oobregion->length = nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section > nand_chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		if (mtd->writesize <= 512) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 2;
+			oobregion->length = 4;
+		}
+	} else {
+		oobregion->offset = ((section - 1) * 16) +
+				    nand_chip->ecc.bytes + 6;
+		if (section < nand_chip->ecc.steps)
+			oobregion->length = (section * 16) + 6 -
+					    oobregion->offset;
+		else
+			oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
+	.ecc = mxc_v1_ooblayout_ecc,
+	.free = mxc_v1_ooblayout_free,
+};
+
+static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * stepsize) + 7;
+	oobregion->length = nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+	if (section > nand_chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		if (mtd->writesize <= 512) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 2;
+			oobregion->length = 4;
+		}
+	} else {
+		oobregion->offset = section * stepsize;
+		oobregion->length = 7;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
+	.ecc = mxc_v2_ooblayout_ecc,
+	.free = mxc_v2_ooblayout_free,
+};
+
 /*
  * v2 and v3 type controllers can do 4bit or 8bit ecc depending
  * on how much oob the nand chip has. For 8bit ecc we need at least
@@ -959,23 +985,6 @@ static int get_eccsize(struct mtd_info *mtd)
 		return 8;
 }
 
-static void ecc_8bit_layout_4k(struct nand_ecclayout *layout)
-{
-	int i, j;
-
-	layout->eccbytes = 8*18;
-	for (i = 0; i < 8; i++)
-		for (j = 0; j < 18; j++)
-			layout->eccpos[i*18 + j] = i*26 + j + 7;
-
-	layout->oobfree[0].offset = 2;
-	layout->oobfree[0].length = 4;
-	for (i = 1; i < 8; i++) {
-		layout->oobfree[i].offset = i*26;
-		layout->oobfree[i].length = 7;
-	}
-}
-
 static void preset_v1(struct mtd_info *mtd)
 {
 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
@@ -1269,9 +1278,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
 	.check_int = check_int_v1_v2,
 	.irq_control = irq_control_v1_v2,
 	.get_ecc_status = get_ecc_status_v1,
-	.ecclayout_512 = &nandv1_hw_eccoob_smallpage,
-	.ecclayout_2k = &nandv1_hw_eccoob_largepage,
-	.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
+	.ooblayout = &mxc_v1_ooblayout_ops,
 	.select_chip = mxc_nand_select_chip_v1_v3,
 	.correct_data = mxc_nand_correct_data_v1,
 	.irqpending_quirk = 1,
@@ -1294,9 +1301,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
 	.check_int = check_int_v1_v2,
 	.irq_control = irq_control_v1_v2,
 	.get_ecc_status = get_ecc_status_v1,
-	.ecclayout_512 = &nandv1_hw_eccoob_smallpage,
-	.ecclayout_2k = &nandv1_hw_eccoob_largepage,
-	.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
+	.ooblayout = &mxc_v1_ooblayout_ops,
 	.select_chip = mxc_nand_select_chip_v1_v3,
 	.correct_data = mxc_nand_correct_data_v1,
 	.irqpending_quirk = 0,
@@ -1320,9 +1325,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
 	.check_int = check_int_v1_v2,
 	.irq_control = irq_control_v1_v2,
 	.get_ecc_status = get_ecc_status_v2,
-	.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
-	.ecclayout_2k = &nandv2_hw_eccoob_largepage,
-	.ecclayout_4k = &nandv2_hw_eccoob_4k,
+	.ooblayout = &mxc_v2_ooblayout_ops,
 	.select_chip = mxc_nand_select_chip_v2,
 	.correct_data = mxc_nand_correct_data_v2_v3,
 	.irqpending_quirk = 0,
@@ -1346,9 +1349,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
 	.check_int = check_int_v3,
 	.irq_control = irq_control_v3,
 	.get_ecc_status = get_ecc_status_v3,
-	.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
-	.ecclayout_2k = &nandv2_hw_eccoob_largepage,
-	.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+	.ooblayout = &mxc_v2_ooblayout_ops,
 	.select_chip = mxc_nand_select_chip_v1_v3,
 	.correct_data = mxc_nand_correct_data_v2_v3,
 	.irqpending_quirk = 0,
@@ -1373,9 +1374,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
 	.check_int = check_int_v3,
 	.irq_control = irq_control_v3,
 	.get_ecc_status = get_ecc_status_v3,
-	.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
-	.ecclayout_2k = &nandv2_hw_eccoob_largepage,
-	.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+	.ooblayout = &mxc_v2_ooblayout_ops,
 	.select_chip = mxc_nand_select_chip_v1_v3,
 	.correct_data = mxc_nand_correct_data_v2_v3,
 	.irqpending_quirk = 0,
@@ -1576,7 +1575,7 @@ static int mxcnd_probe(struct platform_device *pdev)
 
 	this->select_chip = host->devtype_data->select_chip;
 	this->ecc.size = 512;
-	this->ecc.layout = host->devtype_data->ecclayout_512;
+	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
 
 	if (host->pdata.hw_ecc) {
 		this->ecc.calculate = mxc_nand_calculate_ecc;
@@ -1650,12 +1649,11 @@ static int mxcnd_probe(struct platform_device *pdev)
 	/* Call preset again, with correct writesize this time */
 	host->devtype_data->preset(mtd);
 
-	if (mtd->writesize == 2048)
-		this->ecc.layout = host->devtype_data->ecclayout_2k;
-	else if (mtd->writesize == 4096) {
-		this->ecc.layout = host->devtype_data->ecclayout_4k;
-		if (get_eccsize(mtd) == 8)
-			ecc_8bit_layout_4k(this->ecc.layout);
+	if (!this->ecc.bytes) {
+		if (host->eccsize == 8)
+			this->ecc.bytes = 18;
+		else if (host->eccsize == 4)
+			this->ecc.bytes = 9;
 	}
 
 	/*


From linux-mtd at lists.infradead.org  Mon May 23 21:59:17 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:17 +0000
Subject: mtd: nand: omap2: switch to mtd_ooblayout_ops
Message-ID: <E1b54R3-0001Aa-SK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e04dbf352820245b54f74200ac97327959f02c56
Commit:     e04dbf352820245b54f74200ac97327959f02c56
Parent:     a894cf6c5a82c7ddcb1bad82d1e0af3d0ead9a41
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:03:04 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:46 2016 +0200

    mtd: nand: omap2: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 202 ++++++++++++++++++++++++++++-------------------
 1 file changed, 121 insertions(+), 81 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 38fe6b8..55916786d 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -178,8 +178,6 @@ struct omap_nand_info {
 	struct gpmc_nand_regs		reg;
 	struct gpmc_nand_ops		*ops;
 	bool				flash_bbt;
-	/* generated at runtime depending on ECC algorithm and layout selected */
-	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
 	struct device			*elm_dev;
 	/* NAND ready gpio */
@@ -1714,20 +1712,115 @@ static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
 	return 0;
 }
 
+static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_chip *chip = &info->nand;
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+	    !(chip->options & NAND_BUSWIDTH_16))
+		off = 1;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int omap_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_chip *chip = &info->nand;
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+	    !(chip->options & NAND_BUSWIDTH_16))
+		off = 1;
+
+	if (section)
+		return -ERANGE;
+
+	off += chip->ecc.total;
+	if (off >= mtd->oobsize)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = mtd->oobsize - off;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
+	.ecc = omap_ooblayout_ecc,
+	.free = omap_ooblayout_free,
+};
+
+static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	/*
+	 * When SW correction is employed, one OMAP specific marker byte is
+	 * reserved after each ECC step.
+	 */
+	oobregion->offset = off + (section * (chip->ecc.bytes + 1));
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (section)
+		return -ERANGE;
+
+	/*
+	 * When SW correction is employed, one OMAP specific marker byte is
+	 * reserved after each ECC step.
+	 */
+	off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+	if (off >= mtd->oobsize)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = mtd->oobsize - off;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
+	.ecc = omap_sw_ooblayout_ecc,
+	.free = omap_sw_ooblayout_free,
+};
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info		*info;
 	struct omap_nand_platform_data	*pdata = NULL;
 	struct mtd_info			*mtd;
 	struct nand_chip		*nand_chip;
-	struct nand_ecclayout		*ecclayout;
 	int				err;
-	int				i;
 	dma_cap_mask_t			mask;
 	unsigned			sig;
-	unsigned			oob_index;
 	struct resource			*res;
 	struct device			*dev = &pdev->dev;
+	int				min_oobbytes = BADBLOCK_MARKER_LENGTH;
+	int				oobbytes_per_step;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
@@ -1915,7 +2008,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	/*
 	 * Bail out earlier to let NAND_ECC_SOFT code create its own
-	 * ecclayout instead of using ours.
+	 * ooblayout instead of using ours.
 	 */
 	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
@@ -1923,8 +2016,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* populate MTD interface based on ECC scheme */
-	ecclayout		= &info->oobinfo;
-	nand_chip->ecc.layout	= ecclayout;
 	switch (info->ecc_opt) {
 	case OMAP_ECC_HAM1_CODE_HW:
 		pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
@@ -1935,19 +2026,12 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.calculate        = omap_calculate_ecc;
 		nand_chip->ecc.hwctl            = omap_enable_hwecc;
 		nand_chip->ecc.correct          = omap_correct_data;
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		if (nand_chip->options & NAND_BUSWIDTH_16)
-			oob_index		= BADBLOCK_MARKER_LENGTH;
-		else
-			oob_index		= 1;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-			ecclayout->eccpos[i]	= oob_index;
-		/* no reserved-marker in ecclayout for this ecc-scheme */
-		ecclayout->oobfree->offset	=
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
+
+		if (!(nand_chip->options & NAND_BUSWIDTH_16))
+			min_oobbytes		= 1;
+
 		break;
 
 	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1959,19 +2043,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
 		nand_chip->ecc.correct		= nand_bch_correct_data;
 		nand_chip->ecc.calculate	= omap_calculate_ecc_bch;
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		oob_index			= BADBLOCK_MARKER_LENGTH;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
-			ecclayout->eccpos[i] = oob_index;
-			if (((i + 1) % nand_chip->ecc.bytes) == 0)
-				oob_index++;
-		}
-		/* include reserved-marker in ecclayout->oobfree calculation */
-		ecclayout->oobfree->offset	= 1 +
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+		/* Reserve one byte for the OMAP marker */
+		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
 		/* software bch library is used for locating errors */
 		nand_chip->ecc.priv		= nand_bch_init(mtd);
 		if (!nand_chip->ecc.priv) {
@@ -1993,16 +2067,8 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.calculate	= omap_calculate_ecc_bch;
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		oob_index			= BADBLOCK_MARKER_LENGTH;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-			ecclayout->eccpos[i]	= oob_index;
-		/* reserved marker already included in ecclayout->eccbytes */
-		ecclayout->oobfree->offset	=
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
 
 		err = elm_config(info->elm_dev, BCH4_ECC,
 				 mtd->writesize / nand_chip->ecc.size,
@@ -2020,19 +2086,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
 		nand_chip->ecc.correct		= nand_bch_correct_data;
 		nand_chip->ecc.calculate	= omap_calculate_ecc_bch;
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		oob_index			= BADBLOCK_MARKER_LENGTH;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
-			ecclayout->eccpos[i] = oob_index;
-			if (((i + 1) % nand_chip->ecc.bytes) == 0)
-				oob_index++;
-		}
-		/* include reserved-marker in ecclayout->oobfree calculation */
-		ecclayout->oobfree->offset	= 1 +
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+		/* Reserve one byte for the OMAP marker */
+		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
 		/* software bch library is used for locating errors */
 		nand_chip->ecc.priv		= nand_bch_init(mtd);
 		if (!nand_chip->ecc.priv) {
@@ -2054,6 +2110,8 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.calculate	= omap_calculate_ecc_bch;
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
 
 		err = elm_config(info->elm_dev, BCH8_ECC,
 				 mtd->writesize / nand_chip->ecc.size,
@@ -2061,16 +2119,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 		if (err < 0)
 			goto return_error;
 
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		oob_index			= BADBLOCK_MARKER_LENGTH;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-			ecclayout->eccpos[i]	= oob_index;
-		/* reserved marker already included in ecclayout->eccbytes */
-		ecclayout->oobfree->offset	=
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
 		break;
 
 	case OMAP_ECC_BCH16_CODE_HW:
@@ -2084,6 +2132,8 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.calculate	= omap_calculate_ecc_bch;
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
 
 		err = elm_config(info->elm_dev, BCH16_ECC,
 				 mtd->writesize / nand_chip->ecc.size,
@@ -2091,16 +2141,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 		if (err < 0)
 			goto return_error;
 
-		/* define ECC layout */
-		ecclayout->eccbytes		= nand_chip->ecc.bytes *
-							(mtd->writesize /
-							nand_chip->ecc.size);
-		oob_index			= BADBLOCK_MARKER_LENGTH;
-		for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-			ecclayout->eccpos[i]	= oob_index;
-		/* reserved marker already included in ecclayout->eccbytes */
-		ecclayout->oobfree->offset	=
-				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
 		break;
 	default:
 		dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
@@ -2108,13 +2148,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
-	/* all OOB bytes from oobfree->offset till end off OOB are free */
-	ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
 	/* check if NAND device's OOB is enough to store ECC signatures */
-	if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
+	min_oobbytes += (oobbytes_per_step *
+			 (mtd->writesize / nand_chip->ecc.size));
+	if (mtd->oobsize < min_oobbytes) {
 		dev_err(&info->pdev->dev,
 			"not enough OOB bytes required = %d, available=%d\n",
-			ecclayout->eccbytes, mtd->oobsize);
+			min_oobbytes, mtd->oobsize);
 		err = -EINVAL;
 		goto return_error;
 	}


From linux-mtd at lists.infradead.org  Mon May 23 21:59:18 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:18 +0000
Subject: mtd: nand: pxa3xx: switch to mtd_ooblayout_ops
Message-ID: <E1b54R4-0001B7-3J@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=39980c5616d6a4723143e258550f2844e0138d36
Commit:     39980c5616d6a4723143e258550f2844e0138d36
Parent:     e04dbf352820245b54f74200ac97327959f02c56
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Wed Feb 3 20:03:18 2016 +0100
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:46 2016 +0200

    mtd: nand: pxa3xx: switch to mtd_ooblayout_ops
    
    Implementing the mtd_ooblayout_ops interface is the new way of exposing
    ECC/OOB layout to MTD users.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 104 +++++++++++++++++++++++++----------------
 1 file changed, 64 insertions(+), 40 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 38d26ab..436dd6d 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -323,6 +323,62 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 	{ 0xba20, 16, 16, &timing[3] },
 };
 
+static int pxa3xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int nchunks = mtd->writesize / info->chunk_size;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	oobregion->offset = ((info->ecc_size + info->spare_size) * section) +
+			    info->spare_size;
+	oobregion->length = info->ecc_size;
+
+	return 0;
+}
+
+static int pxa3xx_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int nchunks = mtd->writesize / info->chunk_size;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	if (!info->spare_size)
+		return 0;
+
+	oobregion->offset = section * (info->ecc_size + info->spare_size);
+	oobregion->length = info->spare_size;
+	if (!section) {
+		/*
+		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
+		 * 4KB page / 4bit BCH combination.
+		 */
+		if (mtd->writesize == 4096 && info->chunk_size == 2048) {
+			oobregion->offset += 6;
+			oobregion->length -= 6;
+		} else {
+			oobregion->offset += 2;
+			oobregion->length -= 2;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
+	.ecc = pxa3xx_ooblayout_ecc,
+	.free = pxa3xx_ooblayout_free,
+};
+
 static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
 static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
 
@@ -346,41 +402,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 	.pattern = bbt_mirror_pattern
 };
 
-static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
-	.eccbytes = 32,
-	.eccpos = {
-		32, 33, 34, 35, 36, 37, 38, 39,
-		40, 41, 42, 43, 44, 45, 46, 47,
-		48, 49, 50, 51, 52, 53, 54, 55,
-		56, 57, 58, 59, 60, 61, 62, 63},
-	.oobfree = { {2, 30} }
-};
-
-static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
-	.eccbytes = 64,
-	.eccpos = {
-		32,  33,  34,  35,  36,  37,  38,  39,
-		40,  41,  42,  43,  44,  45,  46,  47,
-		48,  49,  50,  51,  52,  53,  54,  55,
-		56,  57,  58,  59,  60,  61,  62,  63,
-		96,  97,  98,  99,  100, 101, 102, 103,
-		104, 105, 106, 107, 108, 109, 110, 111,
-		112, 113, 114, 115, 116, 117, 118, 119,
-		120, 121, 122, 123, 124, 125, 126, 127},
-	/* Bootrom looks in bytes 0 & 5 for bad blocks */
-	.oobfree = { {6, 26}, { 64, 32} }
-};
-
-static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
-	.eccbytes = 128,
-	.eccpos = {
-		32,  33,  34,  35,  36,  37,  38,  39,
-		40,  41,  42,  43,  44,  45,  46,  47,
-		48,  49,  50,  51,  52,  53,  54,  55,
-		56,  57,  58,  59,  60,  61,  62,  63},
-	.oobfree = { }
-};
-
 #define NDTR0_tCH(c)	(min((c), 7) << 19)
 #define NDTR0_tCS(c)	(min((c), 7) << 16)
 #define NDTR0_tWH(c)	(min((c), 7) << 11)
@@ -1545,9 +1566,12 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
 }
 
 static int pxa_ecc_init(struct pxa3xx_nand_info *info,
-			struct nand_ecc_ctrl *ecc,
+			struct mtd_info *mtd,
 			int strength, int ecc_stepsize, int page_size)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
 	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
 		info->nfullchunks = 1;
 		info->ntotalchunks = 1;
@@ -1581,7 +1605,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 		info->ecc_size = 32;
 		ecc->mode = NAND_ECC_HW;
 		ecc->size = info->chunk_size;
-		ecc->layout = &ecc_layout_2KB_bch4bit;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
 		ecc->strength = 16;
 
 	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
@@ -1593,7 +1617,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 		info->ecc_size = 32;
 		ecc->mode = NAND_ECC_HW;
 		ecc->size = info->chunk_size;
-		ecc->layout = &ecc_layout_4KB_bch4bit;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
 		ecc->strength = 16;
 
 	/*
@@ -1611,7 +1635,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 		info->ecc_size = 32;
 		ecc->mode = NAND_ECC_HW;
 		ecc->size = info->chunk_size;
-		ecc->layout = &ecc_layout_4KB_bch8bit;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
 		ecc->strength = 16;
 	} else {
 		dev_err(&info->pdev->dev,
@@ -1706,7 +1730,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 		ecc_step = 512;
 	}
 
-	ret = pxa_ecc_init(info, &chip->ecc, ecc_strength,
+	ret = pxa_ecc_init(info, mtd, ecc_strength,
 			   ecc_step, mtd->writesize);
 	if (ret)
 		return ret;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:20 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:20 +0000
Subject: mtd: nand: fsl_upm: set ECC algorithm explicitly
Message-ID: <E1b54R6-0001Ka-TB@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ab2f5a809871dead7237a86c962d83e2f7b12e8d
Commit:     ab2f5a809871dead7237a86c962d83e2f7b12e8d
Parent:     d9944e1fdcd6c363a24577ac64c6d1128152ff6d
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:07:00 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:54 2016 +0200

    mtd: nand: fsl_upm: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_upm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index cafd12d..d85fa25 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -170,6 +170,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
 	fun->chip.read_buf = fun_read_buf;
 	fun->chip.write_buf = fun_write_buf;
 	fun->chip.ecc.mode = NAND_ECC_SOFT;
+	fun->chip.ecc.algo = NAND_ECC_HAMMING;
 	if (fun->mchip_count > 1)
 		fun->chip.select_chip = fun_select_chip;
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: fsl_ifc: set ECC algorithm explicitly
Message-ID: <E1b54R7-0001L5-2h@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ff1ef3501fae2fd92f4f1132fd27182507a749ec
Commit:     ff1ef3501fae2fd92f4f1132fd27182507a749ec
Parent:     ab2f5a809871dead7237a86c962d83e2f7b12e8d
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:07:01 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:55 2016 +0200

    mtd: nand: fsl_ifc: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_ifc_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 864aa12..4e9e5fd 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -895,6 +895,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 		}
 	} else {
 		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
 	}
 
 	if (ctrl->version == FSL_IFC_VERSION_1_1_0)


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: fsl_elbc: set ECC algorithm explicitly
Message-ID: <E1b54R7-0001Le-7x@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e99b0d9865949e1bb41d1462427e200a6f9eb973
Commit:     e99b0d9865949e1bb41d1462427e200a6f9eb973
Parent:     ff1ef3501fae2fd92f4f1132fd27182507a749ec
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Wed Apr 13 14:07:02 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:55 2016 +0200

    mtd: nand: fsl_elbc: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsl_elbc_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 487eae0..60a88f2 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -800,6 +800,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 	} else {
 		/* otherwise fall back to default software ECC */
 		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
 	}
 
 	return 0;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: jz4740: Remove unused local variable
Message-ID: <E1b54R7-0001MA-CX@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=99fec60aad7a5520effbaadd3bbbe8001e9242eb
Commit:     99fec60aad7a5520effbaadd3bbbe8001e9242eb
Parent:     e99b0d9865949e1bb41d1462427e200a6f9eb973
Author:     Maarten ter Huurne <maarten at treewalker.org>
AuthorDate: Mon Apr 18 18:04:56 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:56 2016 +0200

    mtd: nand: jz4740: Remove unused local variable
    
    Signed-off-by: Maarten ter Huurne <maarten at treewalker.org>
    Acked-by: Harvey Hunt <harvey.hunt at imgtec.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/jz4740_nand.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index df74408..5551c36 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -221,7 +221,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
 	struct jz_nand *nand = mtd_to_jz_nand(mtd);
 	int i, error_count, index;
 	uint32_t reg, status, error;
-	uint32_t t;
 	unsigned int timeout = 1000;
 
 	for (i = 0; i < 9; ++i)


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: omap2: fix compare_const_fl.cocci warnings
Message-ID: <E1b54R7-0001Mf-Gf@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=57a605b101bbdff6a388e8dcb4853db9ffe947f7
Commit:     57a605b101bbdff6a388e8dcb4853db9ffe947f7
Parent:     99fec60aad7a5520effbaadd3bbbe8001e9242eb
Author:     Julia Lawall <julia.lawall at lip6.fr>
AuthorDate: Thu Apr 14 08:54:30 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:56 2016 +0200

    mtd: nand: omap2: fix compare_const_fl.cocci warnings
    
    Move constants to the right of binary operators.
    
    Generated by: scripts/coccinelle/misc/compare_const_fl.cocci
    
    CC: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Fengguang Wu <fengguang.wu at intel.com>
    Signed-off-by: Julia Lawall <julia.lawall at lip6.fr>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 16da65b..141852f 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -216,7 +216,7 @@ static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
 	 */
 	val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
 		PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
-		(dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write));
+		(dma_mode << DMA_MPU_MODE_SHIFT) | (is_write & 0x1));
 	writel(val, info->reg.gpmc_prefetch_config1);
 
 	/*  Start the prefetch engine */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: gpmi: rely on generic DT parsing done in nand_scan_ident()
Message-ID: <E1b54R7-0001NE-Nt@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f05f6a10fb2ef4aa7ebec75696a162f3110861a0
Commit:     f05f6a10fb2ef4aa7ebec75696a162f3110861a0
Parent:     57a605b101bbdff6a388e8dcb4853db9ffe947f7
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:26 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:57 2016 +0200

    mtd: nand: gpmi: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Acked-by: Han xu <han.xu at nxp.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index c50523b..798ed59 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -25,7 +25,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 #include "gpmi-nand.h"
 #include "bch-regs.h"
 
@@ -1944,16 +1943,6 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
 	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
 	this->swap_block_mark = !GPMI_IS_MX23(this);
 
-	if (of_get_nand_on_flash_bbt(this->dev->of_node)) {
-		chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-
-		if (of_property_read_bool(this->dev->of_node,
-						"fsl,no-blockmark-swap"))
-			this->swap_block_mark = false;
-	}
-	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
-		this->swap_block_mark ? "en" : "dis");
-
 	/*
 	 * Allocate a temporary DMA buffer for reading ID in the
 	 * nand_scan_ident().
@@ -1968,6 +1957,16 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
 	if (ret)
 		goto err_out;
 
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+		chip->bbt_options |= NAND_BBT_NO_OOB;
+
+		if (of_property_read_bool(this->dev->of_node,
+						"fsl,no-blockmark-swap"))
+			this->swap_block_mark = false;
+	}
+	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+		this->swap_block_mark ? "en" : "dis");
+
 	ret = gpmi_init_last(this);
 	if (ret)
 		goto err_out;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:21 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:21 +0000
Subject: mtd: nand: davinci: rely on generic DT parsing done in
 nand_scan_ident()
Message-ID: <E1b54R7-0001Nn-Ts@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=363b5db21284b3f44866eaee5d2d34c3c9963f7d
Commit:     363b5db21284b3f44866eaee5d2d34c3c9963f7d
Parent:     f05f6a10fb2ef4aa7ebec75696a162f3110861a0
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:25 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:57 2016 +0200

    mtd: nand: davinci: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/davinci_nand.c | 83 +++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 45 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index fe3fd29..0198536 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -34,7 +34,6 @@
 #include <linux/slab.h>
 #include <linux/of_device.h>
 #include <linux/of.h>
-#include <linux/of_mtd.h>
 
 #include <linux/platform_data/mtd-davinci.h>
 #include <linux/platform_data/mtd-davinci-aemif.h>
@@ -559,8 +558,6 @@ static struct davinci_nand_pdata
 			"ti,davinci-mask-chipsel", &prop))
 			pdata->mask_chipsel = prop;
 		if (!of_property_read_string(pdev->dev.of_node,
-			"nand-ecc-mode", &mode) ||
-		    !of_property_read_string(pdev->dev.of_node,
 			"ti,davinci-ecc-mode", &mode)) {
 			if (!strncmp("none", mode, 4))
 				pdata->ecc_mode = NAND_ECC_NONE;
@@ -573,14 +570,11 @@ static struct davinci_nand_pdata
 			"ti,davinci-ecc-bits", &prop))
 			pdata->ecc_bits = prop;
 
-		prop = of_get_nand_bus_width(pdev->dev.of_node);
-		if (0 < prop || !of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-nand-buswidth", &prop))
-			if (prop == 16)
-				pdata->options |= NAND_BUSWIDTH_16;
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-nand-buswidth", &prop) && prop == 16)
+			pdata->options |= NAND_BUSWIDTH_16;
+
 		if (of_property_read_bool(pdev->dev.of_node,
-			"nand-on-flash-bbt") ||
-		    of_property_read_bool(pdev->dev.of_node,
 			"ti,davinci-nand-use-bbt"))
 			pdata->bbt_options = NAND_BBT_USE_FLASH;
 
@@ -610,7 +604,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
 	void __iomem			*base;
 	int				ret;
 	uint32_t			val;
-	nand_ecc_modes_t		ecc_mode;
 	struct mtd_info			*mtd;
 
 	pdata = nand_davinci_get_pdata(pdev);
@@ -694,10 +687,41 @@ static int nand_davinci_probe(struct platform_device *pdev)
 	info->chip.write_buf    = nand_davinci_write_buf;
 
 	/* Use board-specific ECC config */
-	ecc_mode		= pdata->ecc_mode;
+	info->chip.ecc.mode	= pdata->ecc_mode;
 
 	ret = -EINVAL;
-	switch (ecc_mode) {
+
+	info->clk = devm_clk_get(&pdev->dev, "aemif");
+	if (IS_ERR(info->clk)) {
+		ret = PTR_ERR(info->clk);
+		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(info->clk);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
+			ret);
+		goto err_clk_enable;
+	}
+
+	spin_lock_irq(&davinci_nand_lock);
+
+	/* put CSxNAND into NAND mode */
+	val = davinci_nand_readl(info, NANDFCR_OFFSET);
+	val |= BIT(info->core_chipsel);
+	davinci_nand_writel(info, NANDFCR_OFFSET, val);
+
+	spin_unlock_irq(&davinci_nand_lock);
+
+	/* Scan to find existence of the device(s) */
+	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
+		goto err;
+	}
+
+	switch (info->chip.ecc.mode) {
 	case NAND_ECC_NONE:
 	case NAND_ECC_SOFT:
 		pdata->ecc_bits = 0;
@@ -736,37 +760,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
 	default:
 		return -EINVAL;
 	}
-	info->chip.ecc.mode = ecc_mode;
-
-	info->clk = devm_clk_get(&pdev->dev, "aemif");
-	if (IS_ERR(info->clk)) {
-		ret = PTR_ERR(info->clk);
-		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
-		return ret;
-	}
-
-	ret = clk_prepare_enable(info->clk);
-	if (ret < 0) {
-		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
-			ret);
-		goto err_clk_enable;
-	}
-
-	spin_lock_irq(&davinci_nand_lock);
-
-	/* put CSxNAND into NAND mode */
-	val = davinci_nand_readl(info, NANDFCR_OFFSET);
-	val |= BIT(info->core_chipsel);
-	davinci_nand_writel(info, NANDFCR_OFFSET, val);
-
-	spin_unlock_irq(&davinci_nand_lock);
-
-	/* Scan to find existence of the device(s) */
-	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
-	if (ret < 0) {
-		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
-		goto err;
-	}
 
 	/* Update ECC layout if needed ... for 1-bit HW ECC, the default
 	 * is OK, but it allocates 6 bytes when only 3 are needed (for
@@ -820,7 +813,7 @@ err:
 
 err_clk_enable:
 	spin_lock_irq(&davinci_nand_lock);
-	if (ecc_mode == NAND_ECC_HW_SYNDROME)
+	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
 		ecc4_busy = false;
 	spin_unlock_irq(&davinci_nand_lock);
 	return ret;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nand: hisi504: rely on generic DT parsing done in
 nand_scan_ident()
Message-ID: <E1b54R8-0001OM-2m@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2d01922c11601bed642e5a3d1c7051685218d0fc
Commit:     2d01922c11601bed642e5a3d1c7051685218d0fc
Parent:     363b5db21284b3f44866eaee5d2d34c3c9963f7d
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:27 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:58 2016 +0200

    mtd: nand: hisi504: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/hisi504_nand.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 7bf844c..9432546 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -19,7 +19,6 @@
  * GNU General Public License for more details.
  */
 #include <linux/of.h>
-#include <linux/of_mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/sizes.h>
 #include <linux/clk.h>
@@ -662,10 +661,9 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
 	struct device *dev = host->dev;
 	struct nand_chip *chip = &host->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct device_node *np = host->dev->of_node;
 
-	size = of_get_nand_ecc_step_size(np);
-	strength = of_get_nand_ecc_strength(np);
+	size = chip->ecc.size;
+	strength = chip->ecc.strength;
 	if (size != 1024) {
 		dev_err(dev, "error ecc size: %d\n", size);
 		return -EINVAL;
@@ -715,7 +713,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
 
 static int hisi_nfc_probe(struct platform_device *pdev)
 {
-	int ret = 0, irq, buswidth, flag, max_chips = HINFC504_MAX_CHIP;
+	int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
 	struct device *dev = &pdev->dev;
 	struct hinfc_host *host;
 	struct nand_chip  *chip;
@@ -767,12 +765,6 @@ static int hisi_nfc_probe(struct platform_device *pdev)
 	chip->read_buf		= hisi_nfc_read_buf;
 	chip->chip_delay	= HINFC504_CHIP_DELAY;
 
-	chip->ecc.mode = of_get_nand_ecc_mode(np);
-
-	buswidth = of_get_nand_bus_width(np);
-	if (buswidth == 16)
-		chip->options |= NAND_BUSWIDTH_16;
-
 	hisi_nfc_host_init(host);
 
 	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nand: lpc32xx: rely on generic DT parsing done in
 nand_scan_ident()
Message-ID: <E1b54R8-0001Ow-7C@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=f6c36aaa3b6828fe2720fbdae70b58e6c0cccae6
Commit:     f6c36aaa3b6828fe2720fbdae70b58e6c0cccae6
Parent:     2d01922c11601bed642e5a3d1c7051685218d0fc
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:28 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:58 2016 +0200

    mtd: nand: lpc32xx: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/lpc32xx_slc.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 219dd67..8d3edc3 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -35,7 +35,6 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
-#include <linux/of_mtd.h>
 #include <linux/of_gpio.h>
 #include <linux/mtd/lpc32xx_slc.h>
 
@@ -219,7 +218,6 @@ struct lpc32xx_nand_cfg_slc {
 	uint32_t rwidth;
 	uint32_t rhold;
 	uint32_t rsetup;
-	bool use_bbt;
 	int wp_gpio;
 	struct mtd_partition *parts;
 	unsigned num_parts;
@@ -783,7 +781,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
 		return NULL;
 	}
 
-	ncfg->use_bbt = of_get_nand_on_flash_bbt(np);
 	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
 
 	return ncfg;
@@ -918,19 +915,15 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
 	chip->ecc.prepad = chip->ecc.postpad = 0;
 
-	/* Avoid extra scan if using BBT, setup BBT support */
-	if (host->ncfg->use_bbt) {
-		chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-		/*
-		 * Use a custom BBT marker setup for small page FLASH that
-		 * won't interfere with the ECC layout. Large and huge page
-		 * FLASH use the standard layout.
-		 */
-		if (mtd->writesize <= 512) {
-			chip->bbt_td = &bbt_smallpage_main_descr;
-			chip->bbt_md = &bbt_smallpage_mirror_descr;
-		}
+	/*
+	 * Use a custom BBT marker setup for small page FLASH that
+	 * won't interfere with the ECC layout. Large and huge page
+	 * FLASH use the standard layout.
+	 */
+	if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+	    mtd->writesize <= 512) {
+		chip->bbt_td = &bbt_smallpage_main_descr;
+		chip->bbt_md = &bbt_smallpage_mirror_descr;
 	}
 
 	/*


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nand: mxc: rely on generic DT parsing done in nand_scan_ident()
Message-ID: <E1b54R8-0001PO-EW@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=609468f94883c7840b9b22ec0ee9674513363d9e
Commit:     609468f94883c7840b9b22ec0ee9674513363d9e
Parent:     f6c36aaa3b6828fe2720fbdae70b58e6c0cccae6
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:29 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:59 2016 +0200

    mtd: nand: mxc: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/mxc_nand.c | 45 +++++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index c4e84e1..aa0ba4b 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -34,7 +34,6 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-mxc_nand.h>
@@ -1460,25 +1459,12 @@ MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
 static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
 {
 	struct device_node *np = host->dev->of_node;
-	struct mxc_nand_platform_data *pdata = &host->pdata;
 	const struct of_device_id *of_id =
 		of_match_device(mxcnd_dt_ids, host->dev);
-	int buswidth;
 
 	if (!np)
 		return 1;
 
-	if (of_get_nand_ecc_mode(np) >= 0)
-		pdata->hw_ecc = 1;
-
-	pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
-
-	buswidth = of_get_nand_bus_width(np);
-	if (buswidth < 0)
-		return buswidth;
-
-	pdata->width = buswidth / 8;
-
 	host->devtype_data = of_id->data;
 
 	return 0;
@@ -1578,9 +1564,6 @@ static int mxcnd_probe(struct platform_device *pdev)
 	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
 
 	if (host->pdata.hw_ecc) {
-		this->ecc.calculate = mxc_nand_calculate_ecc;
-		this->ecc.hwctl = mxc_nand_enable_hwecc;
-		this->ecc.correct = host->devtype_data->correct_data;
 		this->ecc.mode = NAND_ECC_HW;
 	} else {
 		this->ecc.mode = NAND_ECC_SOFT;
@@ -1591,12 +1574,9 @@ static int mxcnd_probe(struct platform_device *pdev)
 	if (host->pdata.width == 2)
 		this->options |= NAND_BUSWIDTH_16;
 
-	if (host->pdata.flash_bbt) {
-		this->bbt_td = &bbt_main_descr;
-		this->bbt_md = &bbt_mirror_descr;
-		/* update flash based bbt */
+	/* update flash based bbt */
+	if (host->pdata.flash_bbt)
 		this->bbt_options |= NAND_BBT_USE_FLASH;
-	}
 
 	init_completion(&host->op_completion);
 
@@ -1637,6 +1617,27 @@ static int mxcnd_probe(struct platform_device *pdev)
 		goto escan;
 	}
 
+	switch (this->ecc.mode) {
+	case NAND_ECC_HW:
+		this->ecc.calculate = mxc_nand_calculate_ecc;
+		this->ecc.hwctl = mxc_nand_enable_hwecc;
+		this->ecc.correct = host->devtype_data->correct_data;
+		break;
+
+	case NAND_ECC_SOFT:
+	case NAND_ECC_SOFT_BCH:
+		break;
+
+	default:
+		err = -EINVAL;
+		goto escan;
+	}
+
+	if (this->bbt_options & NAND_BBT_USE_FLASH) {
+		this->bbt_td = &bbt_main_descr;
+		this->bbt_md = &bbt_mirror_descr;
+	}
+
 	/* allocate the right size buffer now */
 	devm_kfree(&pdev->dev, (void *)host->data_buf);
 	host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nand: sh_flctl: rely on generic DT parsing done in
 nand_scan_ident()
Message-ID: <E1b54R8-0001Pv-Jf@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=14667d8d586f93cd1514dfcfe85aeda41dc47142
Commit:     14667d8d586f93cd1514dfcfe85aeda41dc47142
Parent:     609468f94883c7840b9b22ec0ee9674513363d9e
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:31 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:51:59 2016 +0200

    mtd: nand: sh_flctl: rely on generic DT parsing done in nand_scan_ident()
    
    The core now takes care of parsing generic DT properties in
    nand_scan_ident() when nand_set_flash_node() has been called.
    Rely on this initialization instead of calling of_get_nand_xxx()
    manually.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/sh_flctl.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index a5abf6f..6fa3bcd 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -31,7 +31,6 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_mtd.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/sh_dma.h>
@@ -1092,8 +1091,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
 	const struct of_device_id *match;
 	struct flctl_soc_config *config;
 	struct sh_flctl_platform_data *pdata;
-	struct device_node *dn = dev->of_node;
-	int ret;
 
 	match = of_match_device(of_flctl_match, dev);
 	if (match)
@@ -1113,15 +1110,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
 	pdata->has_hwecc = config->has_hwecc;
 	pdata->use_holden = config->use_holden;
 
-	/* parse user defined options */
-	ret = of_get_nand_bus_width(dn);
-	if (ret == 16)
-		pdata->flcmncr_val |= SEL_16BIT;
-	else if (ret != 8) {
-		dev_err(dev, "%s: invalid bus width\n", __func__);
-		return NULL;
-	}
-
 	return pdata;
 }
 
@@ -1184,15 +1172,14 @@ static int flctl_probe(struct platform_device *pdev)
 	nand->chip_delay = 20;
 
 	nand->read_byte = flctl_read_byte;
+	nand->read_word = flctl_read_word;
 	nand->write_buf = flctl_write_buf;
 	nand->read_buf = flctl_read_buf;
 	nand->select_chip = flctl_select_chip;
 	nand->cmdfunc = flctl_cmdfunc;
 
-	if (pdata->flcmncr_val & SEL_16BIT) {
+	if (pdata->flcmncr_val & SEL_16BIT)
 		nand->options |= NAND_BUSWIDTH_16;
-		nand->read_word = flctl_read_word;
-	}
 
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_resume(&pdev->dev);
@@ -1203,6 +1190,16 @@ static int flctl_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_chip;
 
+	if (nand->options & NAND_BUSWIDTH_16) {
+		/*
+		 * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
+		 * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
+		 * flctl->flcmncr_base to pdata->flcmncr_val.
+		 */
+		pdata->flcmncr_val |= SEL_16BIT;
+		flctl->flcmncr_base = pdata->flcmncr_val;
+	}
+
 	ret = flctl_chip_init_tail(flctl_mtd);
 	if (ret)
 		goto err_chip;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nand: move of_get_nand_xxx() helpers into nand_base.c
Message-ID: <E1b54R8-0001QM-Ov@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d48f62b9a0a035d6c16de4a4dae315f7332a8939
Commit:     d48f62b9a0a035d6c16de4a4dae315f7332a8939
Parent:     14667d8d586f93cd1514dfcfe85aeda41dc47142
Author:     Boris Brezillon <boris.brezillon at free-electrons.com>
AuthorDate: Fri Apr 1 14:54:32 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:00 2016 +0200

    mtd: nand: move of_get_nand_xxx() helpers into nand_base.c
    
    Now that all drivers go through nand_set_flash_node() to parse the generic
    NAND properties, we can move all of_get_nand_xxx() helpers in to
    nand_base.c, make them static and remove of_mtd.c and of_mtd.h.
    
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c |  94 +++++++++++++++++++++++++-
 drivers/of/Makefile          |   1 -
 drivers/of/of_mtd.c          | 155 -------------------------------------------
 include/linux/of_mtd.h       |  56 ----------------
 4 files changed, 93 insertions(+), 213 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0001be1..9f157bb 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -45,7 +45,7 @@
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
-#include <linux/of_mtd.h>
+#include <linux/of.h>
 
 static int nand_get_device(struct mtd_info *mtd, int new_state);
 
@@ -3971,6 +3971,98 @@ ident_done:
 	return type;
 }
 
+static const char * const nand_ecc_modes[] = {
+	[NAND_ECC_NONE]		= "none",
+	[NAND_ECC_SOFT]		= "soft",
+	[NAND_ECC_HW]		= "hw",
+	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
+	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
+	[NAND_ECC_SOFT_BCH]	= "soft_bch",
+};
+
+static int of_get_nand_ecc_mode(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+		if (!strcasecmp(pm, nand_ecc_modes[i]))
+			return i;
+
+	return -ENODEV;
+}
+
+static int of_get_nand_ecc_algo(struct device_node *np)
+{
+	const char *pm;
+	int err;
+
+	/*
+	 * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
+	 * It's not implemented yet as currently NAND subsystem ignores
+	 * algorithm explicitly set this way. Once it's handled we should
+	 * document & support new property.
+	 */
+
+	/*
+	 * For backward compatibility we also read "nand-ecc-mode" checking
+	 * for some obsoleted values that were specifying ECC algorithm.
+	 */
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	if (!strcasecmp(pm, "soft"))
+		return NAND_ECC_HAMMING;
+	else if (!strcasecmp(pm, "soft_bch"))
+		return NAND_ECC_BCH;
+
+	return -ENODEV;
+}
+
+static int of_get_nand_ecc_step_size(struct device_node *np)
+{
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+	return ret ? ret : val;
+}
+
+static int of_get_nand_ecc_strength(struct device_node *np)
+{
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+	return ret ? ret : val;
+}
+
+static int of_get_nand_bus_width(struct device_node *np)
+{
+	u32 val;
+
+	if (of_property_read_u32(np, "nand-bus-width", &val))
+		return 8;
+
+	switch (val) {
+	case 8:
+	case 16:
+		return val;
+	default:
+		return -EIO;
+	}
+}
+
+static bool of_get_nand_on_flash_bbt(struct device_node *np)
+{
+	return of_property_read_bool(np, "nand-on-flash-bbt");
+}
+
 static int nand_dt_init(struct nand_chip *chip)
 {
 	struct device_node *dn = nand_get_flash_node(chip);
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 156c072..e31bdc1 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_OF_UNITTEST) += unittest.o
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
-obj-$(CONFIG_OF_MTD)	+= of_mtd.o
 obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
 obj-$(CONFIG_OF_RESOLVE)  += resolver.o
 obj-$(CONFIG_OF_OVERLAY) += overlay.o
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
deleted file mode 100644
index 15d056e..0000000
--- a/drivers/of/of_mtd.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
- *
- * OF helpers for mtd.
- *
- * This file is released under the GPLv2
- *
- */
-#include <linux/kernel.h>
-#include <linux/of_mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/export.h>
-
-/**
- * It maps 'enum nand_ecc_modes_t' found in include/linux/mtd/nand.h
- * into the device tree binding of 'nand-ecc', so that MTD
- * device driver can get nand ecc from device tree.
- */
-static const char *nand_ecc_modes[] = {
-	[NAND_ECC_NONE]		= "none",
-	[NAND_ECC_SOFT]		= "soft",
-	[NAND_ECC_HW]		= "hw",
-	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
-	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
-	[NAND_ECC_SOFT_BCH]	= "soft_bch",
-};
-
-/**
- * of_get_nand_ecc_mode - Get nand ecc mode for given device_node
- * @np:	Pointer to the given device_node
- *
- * The function gets ecc mode string from property 'nand-ecc-mode',
- * and return its index in nand_ecc_modes table, or errno in error case.
- */
-int of_get_nand_ecc_mode(struct device_node *np)
-{
-	const char *pm;
-	int err, i;
-
-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
-		if (!strcasecmp(pm, nand_ecc_modes[i]))
-			return i;
-
-	return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
-
-/**
- * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
- * @np:	Pointer to the given device_node
- *
- * The function gets ecc algorithm and returns its enum value, or errno in error
- * case.
- */
-int of_get_nand_ecc_algo(struct device_node *np)
-{
-	const char *pm;
-	int err;
-
-	/*
-	 * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
-	 * It's not implemented yet as currently NAND subsystem ignores
-	 * algorithm explicitly set this way. Once it's handled we should
-	 * document & support new property.
-	 */
-
-	/*
-	 * For backward compatibility we also read "nand-ecc-mode" checking
-	 * for some obsoleted values that were specifying ECC algorithm.
-	 */
-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
-	if (err < 0)
-		return err;
-
-	if (!strcasecmp(pm, "soft"))
-		return NAND_ECC_HAMMING;
-	else if (!strcasecmp(pm, "soft_bch"))
-		return NAND_ECC_BCH;
-
-	return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
-
-/**
- * of_get_nand_ecc_step_size - Get ECC step size associated to
- * the required ECC strength (see below).
- * @np:	Pointer to the given device_node
- *
- * return the ECC step size, or errno in error case.
- */
-int of_get_nand_ecc_step_size(struct device_node *np)
-{
-	int ret;
-	u32 val;
-
-	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
-	return ret ? ret : val;
-}
-EXPORT_SYMBOL_GPL(of_get_nand_ecc_step_size);
-
-/**
- * of_get_nand_ecc_strength - Get required ECC strength over the
- * correspnding step size as defined by 'nand-ecc-size'
- * @np:	Pointer to the given device_node
- *
- * return the ECC strength, or errno in error case.
- */
-int of_get_nand_ecc_strength(struct device_node *np)
-{
-	int ret;
-	u32 val;
-
-	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
-	return ret ? ret : val;
-}
-EXPORT_SYMBOL_GPL(of_get_nand_ecc_strength);
-
-/**
- * of_get_nand_bus_width - Get nand bus witdh for given device_node
- * @np:	Pointer to the given device_node
- *
- * return bus width option, or errno in error case.
- */
-int of_get_nand_bus_width(struct device_node *np)
-{
-	u32 val;
-
-	if (of_property_read_u32(np, "nand-bus-width", &val))
-		return 8;
-
-	switch(val) {
-	case 8:
-	case 16:
-		return val;
-	default:
-		return -EIO;
-	}
-}
-EXPORT_SYMBOL_GPL(of_get_nand_bus_width);
-
-/**
- * of_get_nand_on_flash_bbt - Get nand on flash bbt for given device_node
- * @np:	Pointer to the given device_node
- *
- * return true if present false other wise
- */
-bool of_get_nand_on_flash_bbt(struct device_node *np)
-{
-	return of_property_read_bool(np, "nand-on-flash-bbt");
-}
-EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
deleted file mode 100644
index 0f6aca5..0000000
--- a/include/linux/of_mtd.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
- *
- * OF helpers for mtd.
- *
- * This file is released under the GPLv2
- */
-
-#ifndef __LINUX_OF_MTD_H
-#define __LINUX_OF_MTD_H
-
-#ifdef CONFIG_OF_MTD
-
-#include <linux/of.h>
-int of_get_nand_ecc_mode(struct device_node *np);
-int of_get_nand_ecc_algo(struct device_node *np);
-int of_get_nand_ecc_step_size(struct device_node *np);
-int of_get_nand_ecc_strength(struct device_node *np);
-int of_get_nand_bus_width(struct device_node *np);
-bool of_get_nand_on_flash_bbt(struct device_node *np);
-
-#else /* CONFIG_OF_MTD */
-
-static inline int of_get_nand_ecc_mode(struct device_node *np)
-{
-	return -ENOSYS;
-}
-
-static inline int of_get_nand_ecc_algo(struct device_node *np)
-{
-	return -ENOSYS;
-}
-
-static inline int of_get_nand_ecc_step_size(struct device_node *np)
-{
-	return -ENOSYS;
-}
-
-static inline int of_get_nand_ecc_strength(struct device_node *np)
-{
-	return -ENOSYS;
-}
-
-static inline int of_get_nand_bus_width(struct device_node *np)
-{
-	return -ENOSYS;
-}
-
-static inline bool of_get_nand_on_flash_bbt(struct device_node *np)
-{
-	return false;
-}
-
-#endif /* CONFIG_OF_MTD */
-
-#endif /* __LINUX_OF_MTD_H */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:22 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:22 +0000
Subject: mtd: nandsim: add __init attribute
Message-ID: <E1b54R8-0001Qm-SK@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=7778478501938e071d40eeadb5d7d01770ce799f
Commit:     7778478501938e071d40eeadb5d7d01770ce799f
Parent:     d48f62b9a0a035d6c16de4a4dae315f7332a8939
Author:     Julia Lawall <julia.lawall at lip6.fr>
AuthorDate: Tue Apr 19 14:33:35 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:00 2016 +0200

    mtd: nandsim: add __init attribute
    
    Add __init attribute on functions that are only called from other __init
    functions and that are not inlined, at least with gcc version 4.8.4 on an
    x86 machine with allyesconfig.  Currently, the functions are put in the
    .text.unlikely segment.  Declaring them as __init will cause them to be
    put in the .init.text and to disappear after initialization.
    
    The result of objdump -x on the functions before the change is as follows:
    
    000000000000059a l     F .text.unlikely 0000000000000239 alloc_device
    000000000000034e l     F .text.unlikely 000000000000002e get_partition_name
    00000000000007d3 l     F .text.unlikely 00000000000005da init_nandsim
    
    And after the change it is as follows:
    
    0000000000000029 l     F .init.text	0000000000000234 alloc_device
    0000000000000000 l     F .init.text	0000000000000029 get_partition_name
    000000000000025d l     F .init.text	00000000000005d5 init_nandsim
    
    Done with the help of Coccinelle.  The semantic patch checks for local
    static non-init functions that are called from an __init function and are
    not called from any other function.
    
    Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nandsim.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 6ff1d8d..66eebb9 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -569,7 +569,7 @@ static void nandsim_debugfs_remove(struct nandsim *ns)
  *
  * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
  */
-static int alloc_device(struct nandsim *ns)
+static int __init alloc_device(struct nandsim *ns)
 {
 	struct file *cfile;
 	int i, err;
@@ -654,7 +654,7 @@ static void free_device(struct nandsim *ns)
 	}
 }
 
-static char *get_partition_name(int i)
+static char __init *get_partition_name(int i)
 {
 	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
 }
@@ -664,7 +664,7 @@ static char *get_partition_name(int i)
  *
  * RETURNS: 0 if success, -ERRNO if failure.
  */
-static int init_nandsim(struct mtd_info *mtd)
+static int __init init_nandsim(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct nandsim   *ns   = nand_get_controller_data(chip);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:23 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:23 +0000
Subject: mtd: nand: omap2: Start dma request before enabling prefetch
Message-ID: <E1b54R9-0001RO-31@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=03d3a1df6da660999d8f14552ac4d875e94090a3
Commit:     03d3a1df6da660999d8f14552ac4d875e94090a3
Parent:     7778478501938e071d40eeadb5d7d01770ce799f
Author:     Cooper Jr., Franklin <fcooper at ti.com>
AuthorDate: Fri Apr 15 15:28:58 2016 -0500
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:01 2016 +0200

    mtd: nand: omap2: Start dma request before enabling prefetch
    
    The prefetch engine sends a dma request once a FIFO threshold has
    been met. No other requests are received until the previous request
    is handled.
    
    Starting a dma transfer (dma_async_issue_pending) results in any
    previous event for the dma channel to be cleared. Therefore, starting
    the prefetch engine before initiating the dma transfer may result in
    the prefetch triggering a dma request but instead of it being handled
    it can end up being cleared. This will result in a hang since the code
    will continue to wait for the dma request to complete.
    
    By initiating the dma request before enabling the prefetch engine this
    race condition is avoided and no dma request are missed/cleared.
    
    Signed-off-by: Franklin S Cooper Jr <fcooper at ti.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 141852f..d1496b1 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -503,6 +503,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	tx->callback_param = &info->comp;
 	dmaengine_submit(tx);
 
+	init_completion(&info->comp);
+
+	/* setup and start DMA using dma_addr */
+	dma_async_issue_pending(info->dma);
+
 	/*  configure and start prefetch transfer */
 	ret = omap_prefetch_enable(info->gpmc_cs,
 		PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
@@ -510,10 +515,6 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 		/* PFPW engine is busy, use cpu copy method */
 		goto out_copy_unmap;
 
-	init_completion(&info->comp);
-	dma_async_issue_pending(info->dma);
-
-	/* setup and start DMA using dma_addr */
 	wait_for_completion(&info->comp);
 	tim = 0;
 	limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));


From linux-mtd at lists.infradead.org  Mon May 23 21:59:23 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:23 +0000
Subject: mtd: nand: omap2: Fix high memory dma prefetch transfer
Message-ID: <E1b54R9-0001S8-A1@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=8c6f0fc4d2d505b17fc67675f0797fe3fc6e6c26
Commit:     8c6f0fc4d2d505b17fc67675f0797fe3fc6e6c26
Parent:     03d3a1df6da660999d8f14552ac4d875e94090a3
Author:     Cooper Jr., Franklin <fcooper at ti.com>
AuthorDate: Fri Apr 15 15:28:59 2016 -0500
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:01 2016 +0200

    mtd: nand: omap2: Fix high memory dma prefetch transfer
    
    Based on DMA documentation and testing using high memory buffer when doing
    dma transfers can lead to various issues including kernel panics.
    
    To workaround this simply use cpu copy.
    
    Signed-off-by: Franklin S Cooper Jr <fcooper at ti.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/omap2.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index d1496b1..08e1588 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -473,17 +473,8 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	int ret;
 	u32 val;
 
-	if (addr >= high_memory) {
-		struct page *p1;
-
-		if (((size_t)addr & PAGE_MASK) !=
-			((size_t)(addr + len - 1) & PAGE_MASK))
-			goto out_copy;
-		p1 = vmalloc_to_page(addr);
-		if (!p1)
-			goto out_copy;
-		addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
-	}
+	if (!virt_addr_valid(addr))
+		goto out_copy;
 
 	sg_init_one(&sg, addr, len);
 	n = dma_map_sg(info->dma->device->dev, &sg, 1, dir);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:23 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:23 +0000
Subject: mtd: nand: bf5xx: set ECC algorithm explicitly
Message-ID: <E1b54R9-0001Sn-Ex@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=04dae62c89bd6e754518f9dcffac480e39f28758
Commit:     04dae62c89bd6e754518f9dcffac480e39f28758
Parent:     8c6f0fc4d2d505b17fc67675f0797fe3fc6e6c26
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:52:57 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:02 2016 +0200

    mtd: nand: bf5xx: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/bf5xx_nand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index b38f414..37da423 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -817,6 +817,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
 	} else {
 		chip->ecc.mode	    = NAND_ECC_SOFT;
+		chip->ecc.algo	= NAND_ECC_HAMMING;
 	}
 
 	/* scan hardware nand chip and setup mtd info data struct */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:23 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:23 +0000
Subject: mtd: nand: davinci: set ECC algorithm explicitly
Message-ID: <E1b54R9-0001TQ-K1@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=867f9873fef69414355e2e1ef547f9b080c3fd69
Commit:     867f9873fef69414355e2e1ef547f9b080c3fd69
Parent:     04dae62c89bd6e754518f9dcffac480e39f28758
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:52:58 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:02 2016 +0200

    mtd: nand: davinci: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/davinci_nand.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 0198536..cc07ba0 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -723,8 +723,17 @@ static int nand_davinci_probe(struct platform_device *pdev)
 
 	switch (info->chip.ecc.mode) {
 	case NAND_ECC_NONE:
+		pdata->ecc_bits = 0;
+		break;
 	case NAND_ECC_SOFT:
 		pdata->ecc_bits = 0;
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ->ecc_algo field to
+		 * davinci_nand_pdata.
+		 */
+		info->chip.ecc.algo = NAND_ECC_HAMMING;
 		break;
 	case NAND_ECC_HW:
 		if (pdata->ecc_bits == 4) {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:23 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:23 +0000
Subject: mtd: nand: atmel: set ECC algorithm explicitly
Message-ID: <E1b54R9-0001U4-Qh@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=d5f304ac6aff1462ddf3c14f48e2b849ab68d5a3
Commit:     d5f304ac6aff1462ddf3c14f48e2b849ab68d5a3
Parent:     867f9873fef69414355e2e1ef547f9b080c3fd69
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:52:59 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:03 2016 +0200

    mtd: nand: atmel: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/atmel_nand.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index eec8ca7..efc8ea2 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1212,6 +1212,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		dev_warn(host->dev,
 			"Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
 		return 0;
 	}
 
@@ -1295,6 +1296,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		/* page size not handled by HW ECC */
 		/* switching back to soft ECC */
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
 		return 0;
 	}
 
@@ -1613,6 +1615,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 	 * even if the nand-ecc-mode property is not defined.
 	 */
 	host->nand_chip.ecc.mode = NAND_ECC_SOFT;
+	host->nand_chip.ecc.algo = NAND_ECC_HAMMING;
 
 	return 0;
 }
@@ -1629,6 +1632,7 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
 		dev_err(host->dev,
 			"Can't get I/O resource regs, use software ECC\n");
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
 		return 0;
 	}
 
@@ -1661,6 +1665,7 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
 		/* page size not handled by HW ECC */
 		/* switching back to soft ECC */
 		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
 		return 0;
 	}
 
@@ -2160,6 +2165,14 @@ static int atmel_nand_probe(struct platform_device *pdev)
 		       sizeof(struct atmel_nand_data));
 		nand_chip->ecc.mode = host->board.ecc_mode;
 
+		/*
+		 * When using software ECC every supported avr32 board means
+		 * Hamming algorithm. If that ever changes we'll need to add
+		 * ecc_algo field to the struct atmel_nand_data.
+		 */
+		if (nand_chip->ecc.mode == NAND_ECC_SOFT)
+			nand_chip->ecc.algo = NAND_ECC_HAMMING;
+
 		/* 16-bit bus width */
 		if (host->board.bus_width_16)
 			nand_chip->options |= NAND_BUSWIDTH_16;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: CRIS v32: nand: set ECC algorithm explicitly
Message-ID: <E1b54R9-0001UY-W6@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=40438a1ea7fb8326daffa692dbf41a5c60bbf3da
Commit:     40438a1ea7fb8326daffa692dbf41a5c60bbf3da
Parent:     d5f304ac6aff1462ddf3c14f48e2b849ab68d5a3
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:00 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:03 2016 +0200

    CRIS v32: nand: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Acked-by: Mikael Starvik <starvik at axis.com>
    Acked-by: Jesper Nilsson <jesper.nilsson at axis.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 arch/cris/arch-v32/drivers/mach-a3/nandflash.c | 1 +
 arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
index 5aa3f51..3f646c7 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -157,6 +157,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
 	/* 20 us command delay time */
 	this->chip_delay = 20;
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	/* Enable the following for a flash based bad block table */
 	/* this->bbt_options = NAND_BBT_USE_FLASH; */
diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index a7c17b0..a745405 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -148,6 +148,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
 	/* 20 us command delay time */
 	this->chip_delay = 20;
 	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
 
 	/* Enable the following for a flash based bad block table */
 	/* this->bbt_options = NAND_BBT_USE_FLASH; */


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: staging: mt29f_spinand: set ECC algorithm explicitly
Message-ID: <E1b54RA-0001VC-5b@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=cc71538fab2f5470775b060c59eddafe8ffa2674
Commit:     cc71538fab2f5470775b060c59eddafe8ffa2674
Parent:     40438a1ea7fb8326daffa692dbf41a5c60bbf3da
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:01 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:04 2016 +0200

    staging: mt29f_spinand: set ECC algorithm explicitly
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Acked-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/staging/mt29f_spinand/mt29f_spinand.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index f503699..e389009 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -900,6 +900,7 @@ static int spinand_probe(struct spi_device *spi_nand)
 	chip->ecc.write_page = spinand_write_page_hwecc;
 #else
 	chip->ecc.mode	= NAND_ECC_SOFT;
+	chip->ecc.algo	= NAND_ECC_HAMMING;
 	if (spinand_disable_ecc(spi_nand) < 0)
 		dev_info(&spi_nand->dev, "%s: disable ecc failed!\n",
 			 __func__);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: mtd: nand: set ECC algorithm to Hamming on fallback
Message-ID: <E1b54RA-0001Vm-9Y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e9d4faed71d5a63fa0ef8fcfef559f67f8b85a22
Commit:     e9d4faed71d5a63fa0ef8fcfef559f67f8b85a22
Parent:     cc71538fab2f5470775b060c59eddafe8ffa2674
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:02 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:04 2016 +0200

    mtd: nand: set ECC algorithm to Hamming on fallback
    
    This is part of process deprecating NAND_ECC_SOFT_BCH (and switching to
    enum nand_ecc_algo).
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9f157bb..2a04957 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4337,6 +4337,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 		pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
 			ecc->size, mtd->writesize);
 		ecc->mode = NAND_ECC_SOFT;
+		ecc->algo = NAND_ECC_HAMMING;
 
 	case NAND_ECC_SOFT:
 		ecc->calculate = nand_calculate_ecc;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: mtd: nand: fsmc: validate ECC setup by checking algorithm directly
Message-ID: <E1b54RA-0001WL-GL@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ef296dc947f6a9300a7fb5b696d1e1f543479e18
Commit:     ef296dc947f6a9300a7fb5b696d1e1f543479e18
Parent:     e9d4faed71d5a63fa0ef8fcfef559f67f8b85a22
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:04 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:52:05 2016 +0200

    mtd: nand: fsmc: validate ECC setup by checking algorithm directly
    
    NAND core sets ECC algorithm in algo field now and it should be
    preferred over the mode field. This also prepares driver for dropping
    NAND_ECC_SOFT_BCH.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 1372040..0f8c63f 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -958,9 +958,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 			nand->ecc.strength = 1;
 			break;
 
+		case NAND_ECC_SOFT:
 		case NAND_ECC_SOFT_BCH:
-			dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
-			break;
+			if (nand->ecc.algo == NAND_ECC_BCH) {
+				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
+				break;
+			}
 
 		default:
 			dev_err(&pdev->dev, "Unsupported ECC mode!\n");


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: mtd: nand: read ECC algorithm from the new field
Message-ID: <E1b54RA-0001Wy-M5@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=06f384c9010ea7fa1146b9dfdd419d99c9b8a962
Commit:     06f384c9010ea7fa1146b9dfdd419d99c9b8a962
Parent:     ef296dc947f6a9300a7fb5b696d1e1f543479e18
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:05 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:10 2016 +0200

    mtd: nand: read ECC algorithm from the new field
    
    Now we have all drivers properly setting this new field we can start
    using it. For a very short period of time we should support both values:
    NAND_ECC_SOFT and NAND_ECC_SOFT_BCH treating them the same. It's because
    of_get_nand_ecc_mode may still be setting NAND_ECC_SOFT_BCH.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 146 +++++++++++++++++++++++++------------------
 1 file changed, 85 insertions(+), 61 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 2a04957..9f96753 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4171,6 +4171,83 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 }
 EXPORT_SYMBOL(nand_scan_ident);
 
+static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (WARN_ON(ecc->mode != NAND_ECC_SOFT &&
+		    ecc->mode != NAND_ECC_SOFT_BCH))
+		return -EINVAL;
+
+	switch (ecc->algo) {
+	case NAND_ECC_HAMMING:
+		ecc->calculate = nand_calculate_ecc;
+		ecc->correct = nand_correct_data;
+		ecc->read_page = nand_read_page_swecc;
+		ecc->read_subpage = nand_read_subpage;
+		ecc->write_page = nand_write_page_swecc;
+		ecc->read_page_raw = nand_read_page_raw;
+		ecc->write_page_raw = nand_write_page_raw;
+		ecc->read_oob = nand_read_oob_std;
+		ecc->write_oob = nand_write_oob_std;
+		if (!ecc->size)
+			ecc->size = 256;
+		ecc->bytes = 3;
+		ecc->strength = 1;
+		return 0;
+	case NAND_ECC_BCH:
+		if (!mtd_nand_has_bch()) {
+			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+			return -EINVAL;
+		}
+		ecc->calculate = nand_bch_calculate_ecc;
+		ecc->correct = nand_bch_correct_data;
+		ecc->read_page = nand_read_page_swecc;
+		ecc->read_subpage = nand_read_subpage;
+		ecc->write_page = nand_write_page_swecc;
+		ecc->read_page_raw = nand_read_page_raw;
+		ecc->write_page_raw = nand_write_page_raw;
+		ecc->read_oob = nand_read_oob_std;
+		ecc->write_oob = nand_write_oob_std;
+		/*
+		* Board driver should supply ecc.size and ecc.strength
+		* values to select how many bits are correctable.
+		* Otherwise, default to 4 bits for large page devices.
+		*/
+		if (!ecc->size && (mtd->oobsize >= 64)) {
+			ecc->size = 512;
+			ecc->strength = 4;
+		}
+
+		/*
+		 * if no ecc placement scheme was provided pickup the default
+		 * large page one.
+		 */
+		if (!mtd->ooblayout) {
+			/* handle large page devices only */
+			if (mtd->oobsize < 64) {
+				WARN(1, "OOB layout is required when using software BCH on small pages\n");
+				return -EINVAL;
+			}
+
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+		}
+
+		/* See nand_bch_init() for details. */
+		ecc->bytes = 0;
+		ecc->priv = nand_bch_init(mtd);
+		if (!ecc->priv) {
+			WARN(1, "BCH ECC initialization failed!\n");
+			return -EINVAL;
+		}
+		return 0;
+	default:
+		WARN(1, "Unsupported ECC algorithm!\n");
+		return -EINVAL;
+	}
+}
+
 /*
  * Check if the chip configuration meet the datasheet requirements.
 
@@ -4246,7 +4323,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 	/*
 	 * If no default placement scheme is given, select an appropriate one.
 	 */
-	if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
+	if (!mtd->ooblayout &&
+	    !((ecc->mode == NAND_ECC_SOFT || ecc->mode == NAND_ECC_SOFT_BCH) &&
+	       ecc->algo == NAND_ECC_BCH)) {
 		switch (mtd->oobsize) {
 		case 8:
 		case 16:
@@ -4340,66 +4419,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 		ecc->algo = NAND_ECC_HAMMING;
 
 	case NAND_ECC_SOFT:
-		ecc->calculate = nand_calculate_ecc;
-		ecc->correct = nand_correct_data;
-		ecc->read_page = nand_read_page_swecc;
-		ecc->read_subpage = nand_read_subpage;
-		ecc->write_page = nand_write_page_swecc;
-		ecc->read_page_raw = nand_read_page_raw;
-		ecc->write_page_raw = nand_write_page_raw;
-		ecc->read_oob = nand_read_oob_std;
-		ecc->write_oob = nand_write_oob_std;
-		if (!ecc->size)
-			ecc->size = 256;
-		ecc->bytes = 3;
-		ecc->strength = 1;
-		break;
-
 	case NAND_ECC_SOFT_BCH:
-		if (!mtd_nand_has_bch()) {
-			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
-			ret = -EINVAL;
-			goto err_free;
-		}
-		ecc->calculate = nand_bch_calculate_ecc;
-		ecc->correct = nand_bch_correct_data;
-		ecc->read_page = nand_read_page_swecc;
-		ecc->read_subpage = nand_read_subpage;
-		ecc->write_page = nand_write_page_swecc;
-		ecc->read_page_raw = nand_read_page_raw;
-		ecc->write_page_raw = nand_write_page_raw;
-		ecc->read_oob = nand_read_oob_std;
-		ecc->write_oob = nand_write_oob_std;
-		/*
-		 * Board driver should supply ecc.size and ecc.strength values
-		 * to select how many bits are correctable. Otherwise, default
-		 * to 4 bits for large page devices.
-		 */
-		if (!ecc->size && (mtd->oobsize >= 64)) {
-			ecc->size = 512;
-			ecc->strength = 4;
-		}
-
-		/*
-		 * if no ecc placement scheme was provided pickup the default
-		 * large page one.
-		 */
-		if (!mtd->ooblayout) {
-			/* handle large page devices only */
-			if (mtd->oobsize < 64) {
-				WARN(1, "OOB layout is required when using software BCH on small pages\n");
-				ret = -EINVAL;
-				goto err_free;
-			}
-
-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-		}
-
-		/* See nand_bch_init() for details. */
-		ecc->bytes = 0;
-		ecc->priv = nand_bch_init(mtd);
-		if (!ecc->priv) {
-			WARN(1, "BCH ECC initialization failed!\n");
+		ret = nand_set_ecc_soft_ops(mtd);
+		if (ret) {
 			ret = -EINVAL;
 			goto err_free;
 		}
@@ -4585,7 +4607,9 @@ void nand_release(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
+	if ((chip->ecc.mode == NAND_ECC_SOFT ||
+	     chip->ecc.mode == NAND_ECC_SOFT_BCH) &&
+	    chip->ecc.algo == NAND_ECC_BCH)
 		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
 	mtd_device_unregister(mtd);


From linux-mtd at lists.infradead.org  Mon May 23 21:59:24 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:24 +0000
Subject: mtd: drop support for NAND_ECC_SOFT_BCH as "soft_bch" mapping
Message-ID: <E1b54RA-0001Xe-Sl@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ae211bcfa1d013bea16912e7caebb1367740d4b4
Commit:     ae211bcfa1d013bea16912e7caebb1367740d4b4
Parent:     06f384c9010ea7fa1146b9dfdd419d99c9b8a962
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:06 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:13 2016 +0200

    mtd: drop support for NAND_ECC_SOFT_BCH as "soft_bch" mapping
    
    There isn't any difference between handling NAND_ECC_SOFT and
    NAND_ECC_SOFT_BCH now. What matters is the new field called "algo".
    Please note we're keeping backward DT compatibility. We are still
    treating "soft_bch" value as the one setting Hamming algorithm, it's
    just handled in of_get_nand_ecc_algo now.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9f96753..1d74b80 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3977,7 +3977,6 @@ static const char * const nand_ecc_modes[] = {
 	[NAND_ECC_HW]		= "hw",
 	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
 	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
-	[NAND_ECC_SOFT_BCH]	= "soft_bch",
 };
 
 static int of_get_nand_ecc_mode(struct device_node *np)
@@ -3993,6 +3992,14 @@ static int of_get_nand_ecc_mode(struct device_node *np)
 		if (!strcasecmp(pm, nand_ecc_modes[i]))
 			return i;
 
+	/*
+	 * For backward compatibility we support few obsoleted values that don't
+	 * have their mappings into nand_ecc_modes_t anymore (they were merged
+	 * with other enums).
+	 */
+	if (!strcasecmp(pm, "soft_bch"))
+		return NAND_ECC_SOFT;
+
 	return -ENODEV;
 }
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:25 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:25 +0000
Subject: mtd: mtd: drop NAND_ECC_SOFT_BCH enum value
Message-ID: <E1b54RB-0001YF-3Y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e4225ae8234cf5548c38dc887b233ad1d45b4d53
Commit:     e4225ae8234cf5548c38dc887b233ad1d45b4d53
Parent:     ae211bcfa1d013bea16912e7caebb1367740d4b4
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Sun Apr 17 22:53:07 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:13 2016 +0200

    mtd: mtd: drop NAND_ECC_SOFT_BCH enum value
    
    This value should not be part of nand_ecc_modes_t as it specifies
    algorithm not a mode. We successfully managed to introduce new "algo"
    field which is respected now.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c   |  3 +--
 drivers/mtd/nand/jz4780_nand.c |  1 -
 drivers/mtd/nand/mxc_nand.c    |  1 -
 drivers/mtd/nand/nand_base.c   | 11 +++--------
 drivers/mtd/nand/nandsim.c     |  2 +-
 drivers/mtd/nand/sunxi_nand.c  |  2 --
 include/linux/mtd/nand.h       |  1 -
 7 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 0f8c63f..d4f454a 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -959,7 +959,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 			break;
 
 		case NAND_ECC_SOFT:
-		case NAND_ECC_SOFT_BCH:
 			if (nand->ecc.algo == NAND_ECC_BCH) {
 				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
 				break;
@@ -974,7 +973,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 		 * Don't set layout for BCH4 SW ECC. This will be
 		 * generated later in nand_bch_init() later.
 		 */
-		if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
+		if (nand->ecc.mode == NAND_ECC_HW) {
 			switch (mtd->oobsize) {
 			case 16:
 			case 64:
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
index 10f249a..daf3c42 100644
--- a/drivers/mtd/nand/jz4780_nand.c
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -179,7 +179,6 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
 		chip->ecc.correct = jz4780_nand_ecc_correct;
 		/* fall through */
 	case NAND_ECC_SOFT:
-	case NAND_ECC_SOFT_BCH:
 		dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
 			(nfc->bch) ? "hardware BCH" : "software ECC",
 			chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index aa0ba4b..5173fad 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1625,7 +1625,6 @@ static int mxcnd_probe(struct platform_device *pdev)
 		break;
 
 	case NAND_ECC_SOFT:
-	case NAND_ECC_SOFT_BCH:
 		break;
 
 	default:
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 1d74b80..c9d6230 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4183,8 +4183,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-	if (WARN_ON(ecc->mode != NAND_ECC_SOFT &&
-		    ecc->mode != NAND_ECC_SOFT_BCH))
+	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
 		return -EINVAL;
 
 	switch (ecc->algo) {
@@ -4331,8 +4330,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	 * If no default placement scheme is given, select an appropriate one.
 	 */
 	if (!mtd->ooblayout &&
-	    !((ecc->mode == NAND_ECC_SOFT || ecc->mode == NAND_ECC_SOFT_BCH) &&
-	       ecc->algo == NAND_ECC_BCH)) {
+	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
 		switch (mtd->oobsize) {
 		case 8:
 		case 16:
@@ -4426,7 +4424,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 		ecc->algo = NAND_ECC_HAMMING;
 
 	case NAND_ECC_SOFT:
-	case NAND_ECC_SOFT_BCH:
 		ret = nand_set_ecc_soft_ops(mtd);
 		if (ret) {
 			ret = -EINVAL;
@@ -4514,7 +4511,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 	/* Large page NAND with SOFT_ECC should support subpage reads */
 	switch (ecc->mode) {
 	case NAND_ECC_SOFT:
-	case NAND_ECC_SOFT_BCH:
 		if (chip->page_shift > 9)
 			chip->options |= NAND_SUBPAGE_READ;
 		break;
@@ -4614,8 +4610,7 @@ void nand_release(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	if ((chip->ecc.mode == NAND_ECC_SOFT ||
-	     chip->ecc.mode == NAND_ECC_SOFT_BCH) &&
+	if (chip->ecc.mode == NAND_ECC_SOFT &&
 	    chip->ecc.algo == NAND_ECC_BCH)
 		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 66eebb9..794745d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2339,7 +2339,7 @@ static int __init ns_init_module(void)
 			retval = -EINVAL;
 			goto error;
 		}
-		chip->ecc.mode = NAND_ECC_SOFT_BCH;
+		chip->ecc.mode = NAND_ECC_SOFT;
 		chip->ecc.algo = NAND_ECC_BCH;
 		chip->ecc.size = 512;
 		chip->ecc.strength = bch;
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 1baf8983..a83a690 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1612,8 +1612,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
 		return -EINVAL;
 
 	switch (ecc->mode) {
-	case NAND_ECC_SOFT_BCH:
-		break;
 	case NAND_ECC_HW:
 		ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
 		if (ret)
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index e851839..fbe8e16 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -116,7 +116,6 @@ typedef enum {
 	NAND_ECC_HW,
 	NAND_ECC_HW_SYNDROME,
 	NAND_ECC_HW_OOB_FIRST,
-	NAND_ECC_SOFT_BCH,
 } nand_ecc_modes_t;
 
 enum nand_ecc_algo {


From linux-mtd at lists.infradead.org  Mon May 23 21:59:25 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:25 +0000
Subject: Documentation: devicetree: deprecate "soft_bch" nand-ecc-mode value
Message-ID: <E1b54RB-0001ZQ-EV@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=32698aafc9f0c6373b240f15a91fefb65c55907c
Commit:     32698aafc9f0c6373b240f15a91fefb65c55907c
Parent:     ba4f46b28f87396d3270d05d8d0e08467471b7fb
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 22 13:23:14 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:14 2016 +0200

    Documentation: devicetree: deprecate "soft_bch" nand-ecc-mode value
    
    Now that we support nand-ecc-algo property it should be used together
    with "soft" to specify software BCH ECC.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 Documentation/devicetree/bindings/mtd/nand.txt | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 5ac4ab7..68342ea 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -20,8 +20,10 @@ Optional NAND controller properties
 Optional NAND chip properties:
 
 - nand-ecc-mode : String, operation mode of the NAND ecc mode.
-  Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
-  "soft_bch".
+		  Supported values are: "none", "soft", "hw", "hw_syndrome",
+		  "hw_oob_first".
+		  Deprecated values:
+		  "soft_bch": use "soft" and nand-ecc-algo instead
 - nand-ecc-algo: string, algorithm of NAND ECC.
 		 Supported values are: "hamming", "bch".
 - nand-bus-width : 8 or 16 bus width if not present 8


From linux-mtd at lists.infradead.org  Mon May 23 21:59:25 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:25 +0000
Subject: mtd: nand: add support for "nand-ecc-algo" DT property
Message-ID: <E1b54RB-0001Yr-9y@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=ba4f46b28f87396d3270d05d8d0e08467471b7fb
Commit:     ba4f46b28f87396d3270d05d8d0e08467471b7fb
Parent:     e4225ae8234cf5548c38dc887b233ad1d45b4d53
Author:     Rafa? Mi?ecki <zajec5 at gmail.com>
AuthorDate: Fri Apr 22 13:23:13 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:14 2016 +0200

    mtd: nand: add support for "nand-ecc-algo" DT property
    
    So far it was only possible to specify ECC algorithm using "soft" and
    "soft_bch" values of nand-ecc-mode prop. There wasn't a way to specify
    it for a hardware ECC mode.
    
    Now that we have independent field in NAND subsystem for storing info
    about ECC algorithm we may also add support for this new DT property.
    
    Signed-off-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 Documentation/devicetree/bindings/mtd/nand.txt |  2 ++
 drivers/mtd/nand/nand_base.c                   | 20 +++++++++++++-------
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index a17662b..5ac4ab7 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -22,6 +22,8 @@ Optional NAND chip properties:
 - nand-ecc-mode : String, operation mode of the NAND ecc mode.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
+- nand-ecc-algo: string, algorithm of NAND ECC.
+		 Supported values are: "hamming", "bch".
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
 
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c9d6230..c26f185 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4003,17 +4003,23 @@ static int of_get_nand_ecc_mode(struct device_node *np)
 	return -ENODEV;
 }
 
+static const char * const nand_ecc_algos[] = {
+	[NAND_ECC_HAMMING]	= "hamming",
+	[NAND_ECC_BCH]		= "bch",
+};
+
 static int of_get_nand_ecc_algo(struct device_node *np)
 {
 	const char *pm;
-	int err;
+	int err, i;
 
-	/*
-	 * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
-	 * It's not implemented yet as currently NAND subsystem ignores
-	 * algorithm explicitly set this way. Once it's handled we should
-	 * document & support new property.
-	 */
+	err = of_property_read_string(np, "nand-ecc-algo", &pm);
+	if (!err) {
+		for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
+			if (!strcasecmp(pm, nand_ecc_algos[i]))
+				return i;
+		return -ENODEV;
+	}
 
 	/*
 	 * For backward compatibility we also read "nand-ecc-mode" checking


From linux-mtd at lists.infradead.org  Mon May 23 21:59:25 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:25 +0000
Subject: gpmi-nand: Handle ECC Errors in erased pages
Message-ID: <E1b54RB-0001Zx-JG@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=bd2e778c9ee361c23ccb2b10591712e129d97893
Commit:     bd2e778c9ee361c23ccb2b10591712e129d97893
Parent:     32698aafc9f0c6373b240f15a91fefb65c55907c
Author:     Markus Pargmann <mpa at pengutronix.de>
AuthorDate: Mon Apr 25 14:35:12 2016 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:15 2016 +0200

    gpmi-nand: Handle ECC Errors in erased pages
    
    ECC is only calculated for written pages. As erased pages are not
    actively written the ECC is always invalid. For this purpose the
    Hardware BCH unit is able to check for erased pages and does not raise
    an ECC error in this case. This behaviour can be influenced using the
    BCH_MODE register which sets the number of allowed bitflips in an erased
    page. Unfortunately the unit is not capable of fixing the bitflips in
    memory.
    
    To avoid complete software checks for erased pages, we can simply check
    buffers with uncorrectable ECC errors because we know that any erased
    page with errors is uncorrectable by the BCH unit.
    
    This patch adds the generic nand_check_erased_ecc_chunk() to gpmi-nand
    to correct erased pages. To have the valid data in the buffer before
    using them, this patch moves the read_page_swap_end() call before the
    ECC status checking for-loop.
    
    Signed-off-by: Markus Pargmann <mpa at pengutronix.de>
    [Squashed patches by Stefan and Boris to check ECC area]
    Tested-by: Stefan Christ <s.christ at phytec.de>
    Acked-by: Han xu <han.xu at nxp.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 78 +++++++++++++++++++++++++++++++---
 1 file changed, 73 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 798ed59..6e46156 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1064,14 +1064,87 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 	/* Loop over status bytes, accumulating ECC status. */
 	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
 
+	read_page_swap_end(this, buf, nfc_geo->payload_size,
+			   this->payload_virt, this->payload_phys,
+			   nfc_geo->payload_size,
+			   payload_virt, payload_phys);
+
 	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
 		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
 			continue;
 
 		if (*status == STATUS_UNCORRECTABLE) {
+			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+			u8 *eccbuf = this->raw_buffer;
+			int offset, bitoffset;
+			int eccbytes;
+			int flips;
+
+			/* Read ECC bytes into our internal raw_buffer */
+			offset = nfc_geo->metadata_size * 8;
+			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+			offset -= eccbits;
+			bitoffset = offset % 8;
+			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
+			offset /= 8;
+			eccbytes -= offset;
+			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+			chip->read_buf(mtd, eccbuf, eccbytes);
+
+			/*
+			 * ECC data are not byte aligned and we may have
+			 * in-band data in the first and last byte of
+			 * eccbuf. Set non-eccbits to one so that
+			 * nand_check_erased_ecc_chunk() does not count them
+			 * as bitflips.
+			 */
+			if (bitoffset)
+				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
+
+			bitoffset = (bitoffset + eccbits) % 8;
+			if (bitoffset)
+				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
+
+			/*
+			 * The ECC hardware has an uncorrectable ECC status
+			 * code in case we have bitflips in an erased page. As
+			 * nothing was written into this subpage the ECC is
+			 * obviously wrong and we can not trust it. We assume
+			 * at this point that we are reading an erased page and
+			 * try to correct the bitflips in buffer up to
+			 * ecc_strength bitflips. If this is a page with random
+			 * data, we exceed this number of bitflips and have a
+			 * ECC failure. Otherwise we use the corrected buffer.
+			 */
+			if (i == 0) {
+				/* The first block includes metadata */
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						auxiliary_virt,
+						nfc_geo->metadata_size,
+						nfc_geo->ecc_strength);
+			} else {
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						NULL, 0,
+						nfc_geo->ecc_strength);
+			}
+
+			if (flips > 0) {
+				max_bitflips = max_t(unsigned int, max_bitflips,
+						     flips);
+				mtd->ecc_stats.corrected += flips;
+				continue;
+			}
+
 			mtd->ecc_stats.failed++;
 			continue;
 		}
+
 		mtd->ecc_stats.corrected += *status;
 		max_bitflips = max_t(unsigned int, max_bitflips, *status);
 	}
@@ -1091,11 +1164,6 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
 	}
 
-	read_page_swap_end(this, buf, nfc_geo->payload_size,
-			this->payload_virt, this->payload_phys,
-			nfc_geo->payload_size,
-			payload_virt, payload_phys);
-
 	return max_bitflips;
 }
 


From linux-mtd at lists.infradead.org  Mon May 23 21:59:25 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:25 +0000
Subject: mtd: brcmnand: respect ECC algorithm set by NAND subsystem
Message-ID: <E1b54RB-0001aS-OE@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=666b65683dad9aa90efaa4aad24ef3710101e3aa
Commit:     666b65683dad9aa90efaa4aad24ef3710101e3aa
Parent:     bd2e778c9ee361c23ccb2b10591712e129d97893
Author:     Brian Norris <computersforpeace at gmail.com>
AuthorDate: Mon Apr 25 22:53:55 2016 -0700
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Thu May 5 23:55:15 2016 +0200

    mtd: brcmnand: respect ECC algorithm set by NAND subsystem
    
    This is more obvious than guessing based on ECC strength. It allows
    using NAND on devices with BCH-1 (e.g. D-Link DIR-885L).
    
    This maintains DT backward compatibility by defaulting to Hamming if a
    1-bit ECC algorithm is specified without a corresponding algorithm
    selection. i.e., to use BCH-1, you must specify:
    
      nand-ecc-strength = <1>;
      nand-ecc-step-size = <512>;
      nand-ecc-algo = "bch";
    
    Also adds a check to ensure we haven't allowed someone to get by with SW
    ECC. If we want to support SW ECC, we need to refactor some other pieces
    of this driver.
    
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
    Tested-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/brcmnand/brcmnand.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index c3331ff..b76ad7c 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -1925,9 +1925,31 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 	cfg->col_adr_bytes = 2;
 	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
 
+	if (chip->ecc.mode != NAND_ECC_HW) {
+		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
+			chip->ecc.mode);
+		return -EINVAL;
+	}
+
+	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
+		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
+			/* Default to Hamming for 1-bit ECC, if unspecified */
+			chip->ecc.algo = NAND_ECC_HAMMING;
+		else
+			/* Otherwise, BCH */
+			chip->ecc.algo = NAND_ECC_BCH;
+	}
+
+	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
+						   chip->ecc.size != 512)) {
+		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
+			chip->ecc.strength, chip->ecc.size);
+		return -EINVAL;
+	}
+
 	switch (chip->ecc.size) {
 	case 512:
-		if (chip->ecc.strength == 1) /* Hamming */
+		if (chip->ecc.algo == NAND_ECC_HAMMING)
 			cfg->ecc_level = 15;
 		else
 			cfg->ecc_level = chip->ecc.strength;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:26 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:26 +0000
Subject: mtd: nand_bch: fix spelling of "probably"
Message-ID: <E1b54RB-0001b2-Up@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=3603ea0aeed7dc2b54144b5913eb303173361123
Commit:     3603ea0aeed7dc2b54144b5913eb303173361123
Parent:     2cbaf5491cb7095252c72e74e79863b75ad2d8d0
Author:     Brian Norris <computersforpeace at gmail.com>
AuthorDate: Fri May 6 09:31:18 2016 -0700
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Fri May 6 09:45:45 2016 -0700

    mtd: nand_bch: fix spelling of "probably"
    
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/nand_bch.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 28ef7b1..44763f8 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -175,7 +175,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 	 * which is called by mtd_ooblayout_count_eccbytes().
 	 * Make sure they are properly initialized before calling
 	 * mtd_ooblayout_count_eccbytes().
-	 * FIXME: we should probaly rework the sequencing in nand_scan_tail()
+	 * FIXME: we should probably rework the sequencing in nand_scan_tail()
 	 * to avoid setting those fields twice.
 	 */
 	nand->ecc.steps = eccsteps;


From linux-mtd at lists.infradead.org  Mon May 23 21:59:26 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 24 May 2016 04:59:26 +0000
Subject: mtd: spi-nor: support GigaDevice gd25lq64c
Message-ID: <E1b54RC-0001ba-34@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e5366a266a8cd4cd6b0fe66876462cca2e1c6a89
Commit:     e5366a266a8cd4cd6b0fe66876462cca2e1c6a89
Parent:     3603ea0aeed7dc2b54144b5913eb303173361123
Author:     Brian Norris <computersforpeace at gmail.com>
AuthorDate: Fri May 6 08:37:41 2016 -0700
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Tue May 10 15:44:18 2016 -0700

    mtd: spi-nor: support GigaDevice gd25lq64c
    
    Also note the GigaDevice JEDEC ID.
    
    No write-protect support yet, since this flash uses a different status
    register layout.
    
    Cc: Ezequiel Garcia <ezequiel at vanguardiasur.com.ar>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
    Acked-by: Marek Vasut <marex at denx.de>
---
 drivers/mtd/spi-nor/spi-nor.c | 1 +
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 157841d..c52e455 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -832,6 +832,7 @@ static const struct flash_info spi_nor_ids[] = {
 	/* GigaDevice */
 	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
+	{ "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
 
 	/* Intel/Numonyx -- xxxs33b */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 3c36113..7f041bd 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -21,6 +21,7 @@
  * Sometimes these are the same as CFI IDs, but sometimes they aren't.
  */
 #define SNOR_MFR_ATMEL		CFI_MFR_ATMEL
+#define SNOR_MFR_GIGADEVICE	0xc8
 #define SNOR_MFR_INTEL		CFI_MFR_INTEL
 #define SNOR_MFR_MICRON		CFI_MFR_ST /* ST Micro <--> Micron */
 #define SNOR_MFR_MACRONIX	CFI_MFR_MACRONIX


From linux-mtd at lists.infradead.org  Wed May 25 20:59:01 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 26 May 2016 03:59:01 +0000
Subject: Revert "mtd: atmel_nand: Support variable RB_EDGE interrupts"
Message-ID: <E1b5mRp-0003Kh-9W@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=53b74ed2d0b4170764bf6d4cba6b786be1cab846
Commit:     53b74ed2d0b4170764bf6d4cba6b786be1cab846
Parent:     e5366a266a8cd4cd6b0fe66876462cca2e1c6a89
Author:     Wenyou Yang <wenyou.yang at atmel.com>
AuthorDate: Mon May 9 14:51:18 2016 +0800
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Wed May 25 20:06:28 2016 -0700

    Revert "mtd: atmel_nand: Support variable RB_EDGE interrupts"
    
    This reverts commit 5ddc7bd43ccc ("mtd: atmel_nand: Support variable
    RB_EDGE interrupts")
    
    Because for current SoCs, the RB_EDGE3(i.e. bit 27) of HSMC_SR
    register does not exist, the RB_EDGE0 (i.e. bit 24) is the ready/busy
    line edge status bit. It is a datasheet bug.
    
    Cc: <stable at vger.kernel.org>
    Fixes: commit 5ddc7bd43ccc ("mtd: atmel_nand: Support variable RB_EDGE interrupts")
    Signed-off-by: Wenyou Yang <wenyou.yang at atmel.com>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 .../devicetree/bindings/mtd/atmel-nand.txt         |  2 +-
 drivers/mtd/nand/atmel_nand.c                      | 35 +++++-----------------
 drivers/mtd/nand/atmel_nand_nfc.h                  |  3 +-
 3 files changed, 10 insertions(+), 30 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index d53aba9..3e7ee99 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -39,7 +39,7 @@ Optional properties:
 
 Nand Flash Controller(NFC) is an optional sub-node
 Required properties:
-- compatible : "atmel,sama5d3-nfc" or "atmel,sama5d4-nfc".
+- compatible : "atmel,sama5d3-nfc".
 - reg : should specify the address and size used for NFC command registers,
         NFC registers and NFC SRAM. NFC SRAM address and size can be absent
         if don't want to use it.
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index efc8ea2..68b9160 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -67,10 +67,6 @@ struct atmel_nand_caps {
 	uint8_t pmecc_max_correction;
 };
 
-struct atmel_nand_nfc_caps {
-	uint32_t rb_mask;
-};
-
 /*
  * oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -129,7 +125,6 @@ struct atmel_nfc {
 	/* Point to the sram bank which include readed data via NFC */
 	void			*data_in_sram;
 	bool			will_write_sram;
-	const struct atmel_nand_nfc_caps *caps;
 };
 static struct atmel_nfc	nand_nfc;
 
@@ -1715,9 +1710,9 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
 		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
 		ret = IRQ_HANDLED;
 	}
-	if (pending & host->nfc->caps->rb_mask) {
+	if (pending & NFC_SR_RB_EDGE) {
 		complete(&host->nfc->comp_ready);
-		nfc_writel(host->nfc->hsmc_regs, IDR, host->nfc->caps->rb_mask);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
 		ret = IRQ_HANDLED;
 	}
 	if (pending & NFC_SR_CMD_DONE) {
@@ -1735,7 +1730,7 @@ static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag)
 	if (flag & NFC_SR_XFR_DONE)
 		init_completion(&host->nfc->comp_xfer_done);
 
-	if (flag & host->nfc->caps->rb_mask)
+	if (flag & NFC_SR_RB_EDGE)
 		init_completion(&host->nfc->comp_ready);
 
 	if (flag & NFC_SR_CMD_DONE)
@@ -1753,7 +1748,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
 	if (flag & NFC_SR_XFR_DONE)
 		comp[index++] = &host->nfc->comp_xfer_done;
 
-	if (flag & host->nfc->caps->rb_mask)
+	if (flag & NFC_SR_RB_EDGE)
 		comp[index++] = &host->nfc->comp_ready;
 
 	if (flag & NFC_SR_CMD_DONE)
@@ -1821,7 +1816,7 @@ static int nfc_device_ready(struct mtd_info *mtd)
 		dev_err(host->dev, "Lost the interrupt flags: 0x%08x\n",
 				mask & status);
 
-	return status & host->nfc->caps->rb_mask;
+	return status & NFC_SR_RB_EDGE;
 }
 
 static void nfc_select_chip(struct mtd_info *mtd, int chip)
@@ -1994,8 +1989,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 		}
 		/* fall through */
 	default:
-		nfc_prepare_interrupt(host, host->nfc->caps->rb_mask);
-		nfc_wait_interrupt(host, host->nfc->caps->rb_mask);
+		nfc_prepare_interrupt(host, NFC_SR_RB_EDGE);
+		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
 	}
 }
 
@@ -2426,11 +2421,6 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
 		}
 	}
 
-	nfc->caps = (const struct atmel_nand_nfc_caps *)
-		of_device_get_match_data(&pdev->dev);
-	if (!nfc->caps)
-		return -ENODEV;
-
 	nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
 	nfc_readl(nfc->hsmc_regs, SR);	/* clear the NFC_SR */
 
@@ -2459,17 +2449,8 @@ static int atmel_nand_nfc_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct atmel_nand_nfc_caps sama5d3_nfc_caps = {
-	.rb_mask = NFC_SR_RB_EDGE0,
-};
-
-static const struct atmel_nand_nfc_caps sama5d4_nfc_caps = {
-	.rb_mask = NFC_SR_RB_EDGE3,
-};
-
 static const struct of_device_id atmel_nand_nfc_match[] = {
-	{ .compatible = "atmel,sama5d3-nfc", .data = &sama5d3_nfc_caps },
-	{ .compatible = "atmel,sama5d4-nfc", .data = &sama5d4_nfc_caps },
+	{ .compatible = "atmel,sama5d3-nfc" },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match);
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
index 0bbc1fa..4d5d262 100644
--- a/drivers/mtd/nand/atmel_nand_nfc.h
+++ b/drivers/mtd/nand/atmel_nand_nfc.h
@@ -42,8 +42,7 @@
 #define		NFC_SR_UNDEF		(1 << 21)
 #define		NFC_SR_AWB		(1 << 22)
 #define		NFC_SR_ASE		(1 << 23)
-#define		NFC_SR_RB_EDGE0		(1 << 24)
-#define		NFC_SR_RB_EDGE3		(1 << 27)
+#define		NFC_SR_RB_EDGE		(1 << 24)
 
 #define ATMEL_HSMC_NFC_IER	0x0c
 #define ATMEL_HSMC_NFC_IDR	0x10


From linux-mtd at lists.infradead.org  Fri May 27 09:59:01 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Fri, 27 May 2016 16:59:01 +0000
Subject: Documentation: dt: mtd: drop "soft_bch" from example
Message-ID: <E1b6L6D-0008Vb-8N@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=507e617440d70bc4269daac1b0ee96671bf2761a
Commit:     507e617440d70bc4269daac1b0ee96671bf2761a
Parent:     53b74ed2d0b4170764bf6d4cba6b786be1cab846
Author:     Baruch Siach <baruch at tkos.co.il>
AuthorDate: Wed May 25 06:45:10 2016 +0300
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Fri May 27 09:56:26 2016 -0700

    Documentation: dt: mtd: drop "soft_bch" from example
    
    Commit 32698aafc9f0 (Documentation: devicetree: deprecate "soft_bch"
    nand-ecc-mode value, 2016-04-22) deprecated "soft_bch". Update the example to
    match.
    
    Signed-off-by: Baruch Siach <baruch at tkos.co.il>
    Acked-by: Rafa? Mi?ecki <zajec5 at gmail.com>
    Acked-by: Rob Herring <robh at kernel.org>
    Acked-by: Boris Brezillon <boris.brezillon at free-electrons.com>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 Documentation/devicetree/bindings/mtd/nand.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 68342ea..3733300 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -53,7 +53,8 @@ Example:
 
 		nand at 0 {
 			reg = <0>;
-			nand-ecc-mode = "soft_bch";
+			nand-ecc-mode = "soft";
+			nand-ecc-algo = "bch";
 
 			/* controller specific properties */
 		};


From linux-mtd at lists.infradead.org  Tue May 31 12:59:01 2016
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 31 May 2016 19:59:01 +0000
Subject: MAINTAINERS: Add file patterns for mtd device tree bindings
Message-ID: <E1b7pob-0000p1-CY@bombadil.infradead.org>

Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=becc7ae544c61395b5eba7b9913e14aa567ca07a
Commit:     becc7ae544c61395b5eba7b9913e14aa567ca07a
Parent:     1a695a905c18548062509178b98bc91e67510864
Author:     Geert Uytterhoeven <geert at linux-m68k.org>
AuthorDate: Sun May 22 11:06:06 2016 +0200
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Tue May 31 12:30:54 2016 -0700

    MAINTAINERS: Add file patterns for mtd device tree bindings
    
    Submitters of device tree binding documentation may forget to CC
    the subsystem maintainer if this is missing.
    
    Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
    Cc: David Woodhouse <dwmw2 at infradead.org>
    Cc: linux-mtd at lists.infradead.org
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7304d2e..adcb370 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7457,6 +7457,7 @@ Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
 T:	git git://git.infradead.org/linux-mtd.git
 T:	git git://git.infradead.org/l2-mtd.git
 S:	Maintained
+F:	Documentation/devicetree/bindings/mtd/
 F:	drivers/mtd/
 F:	include/linux/mtd/
 F:	include/uapi/mtd/


