Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:09:22 +0000 (01:09 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:09:22 +0000 (01:09 +0100)
Pull mtd updates from Boris Brezillon:
 "SPI NOR core changes:
   - Support non-uniform erase size
   - Support controllers with limited TX fifo size

 Driver changes:
   - m25p80: Re-issue a WREN command after each write access
   - cadence: Pass a proper dir value to dma_[un]map_single()
   - fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B
     addressing opcodes are properly handled
   - intel-spi: Add a new PCI entry for Ice Lake

 Raw NAND core changes:
   - Two batchs of cleanups of the NAND API, including:
      * Deprecating a lot of interfaces (now replaced by ->exec_op()).
      * Moving code in separate drivers (JEDEC, ONFI), in private files
        (internals), in platform drivers, etc.
      * Functions/structures reordering.
      * Exclusive use of the nand_chip structure instead of the MTD one
        all across the subsystem.
   - Addition of the nand_wait_readrdy/rdy_op() helpers.

 Raw NAND controllers drivers changes:
   - Various coccinelle patches.
   - Marvell:
      * Use regmap_update_bits() for syscon access.
      * More documentation.
      * BCH failure path rework.
      * More layouts to be supported.
      * IRQ handler complete() condition fixed.
   - Fsl_ifc:
      * SRAM initialization fixed for newer controller versions.
   - Denali:
      * Fix licenses mismatch and use a SPDX tag.
      * Set SPARE_AREA_SKIP_BYTES register to 8 if unset.
   - Qualcomm:
      * Do not include dma-direct.h.
   - Docg4:
      * Removed.
   - Ams-delta:
      * Use of a GPIO lookup table
      * Internal machinery changes.

 Raw NAND chip drivers changes:
   - Toshiba:
      * Add support for Toshiba memory BENAND
      * Pass a single nand_chip object to the status helper.
   - ESMT:
      * New driver to retrieve the ECC requirements from the 5th ID
        byte.

  MTD changes:
   - physmap cleanups/fixe
   - gpio-addr-flash cleanups/fixes"

* tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd: (93 commits)
  jffs2: free jffs2_sb_info through jffs2_kill_sb()
  mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
  mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash
  mtd: maps: gpio-addr-flash: Convert to gpiod
  mtd: maps: gpio-addr-flash: Replace array with an integer
  mtd: maps: gpio-addr-flash: Use order instead of size
  mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus
  mtd: devices: m25p80: Make sure WRITE_EN is issued before each write
  mtd: spi-nor: Support controllers with limited TX FIFO size
  mtd: spi-nor: cadence-quadspi: Use proper enum for dma_[un]map_single
  mtd: spi-nor: parse SFDP Sector Map Parameter Table
  mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories
  mtd: rawnand: marvell: fix the IRQ handler complete() condition
  mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset
  mtd: rawnand: r852: fix spelling mistake "card_registred" -> "card_registered"
  mtd: rawnand: toshiba: Pass a single nand_chip object to the status helper
  mtd: maps: gpio-addr-flash: Use devm_* functions
  mtd: maps: gpio-addr-flash: Fix ioremapped size
  mtd: maps: gpio-addr-flash: Replace custom printk
  mtd: physmap_of: Release resources on error
  ...

1  2 
drivers/mtd/devices/m25p80.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/marvell_nand.c

index 270d3c9580c51195ccb6b05e3719e98fb1836031,cb14cf985b95ebefd267473b05bc32ce7be9a7bd..c4a1d04b8c800d1b090e99dc9975025d4b61009c
@@@ -39,23 -39,13 +39,23 @@@ static int m25p80_read_reg(struct spi_n
        struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
                                          SPI_MEM_OP_NO_ADDR,
                                          SPI_MEM_OP_NO_DUMMY,
 -                                        SPI_MEM_OP_DATA_IN(len, val, 1));
 +                                        SPI_MEM_OP_DATA_IN(len, NULL, 1));
 +      void *scratchbuf;
        int ret;
  
 +      scratchbuf = kmalloc(len, GFP_KERNEL);
 +      if (!scratchbuf)
 +              return -ENOMEM;
 +
 +      op.data.buf.in = scratchbuf;
        ret = spi_mem_exec_op(flash->spimem, &op);
        if (ret < 0)
                dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
                        code);
 +      else
 +              memcpy(val, scratchbuf, len);
 +
 +      kfree(scratchbuf);
  
        return ret;
  }
@@@ -66,19 -56,9 +66,19 @@@ static int m25p80_write_reg(struct spi_
        struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
                                          SPI_MEM_OP_NO_ADDR,
                                          SPI_MEM_OP_NO_DUMMY,
 -                                        SPI_MEM_OP_DATA_OUT(len, buf, 1));
 +                                        SPI_MEM_OP_DATA_OUT(len, NULL, 1));
 +      void *scratchbuf;
 +      int ret;
 +
 +      scratchbuf = kmemdup(buf, len, GFP_KERNEL);
 +      if (!scratchbuf)
 +              return -ENOMEM;
  
 -      return spi_mem_exec_op(flash->spimem, &op);
 +      op.data.buf.out = scratchbuf;
 +      ret = spi_mem_exec_op(flash->spimem, &op);
 +      kfree(scratchbuf);
 +
 +      return ret;
  }
  
  static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
@@@ -90,7 -70,6 +90,6 @@@
                                   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(len, buf, 1));
-       size_t remaining = len;
        int ret;
  
        /* get transfer protocols. */
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
                op.addr.nbytes = 0;
  
-       while (remaining) {
-               op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
-               ret = spi_mem_adjust_op_size(flash->spimem, &op);
-               if (ret)
-                       return ret;
-               ret = spi_mem_exec_op(flash->spimem, &op);
-               if (ret)
-                       return ret;
+       ret = spi_mem_adjust_op_size(flash->spimem, &op);
+       if (ret)
+               return ret;
+       op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
  
-               op.addr.val += op.data.nbytes;
-               remaining -= op.data.nbytes;
-               op.data.buf.out += op.data.nbytes;
-       }
+       ret = spi_mem_exec_op(flash->spimem, &op);
+       if (ret)
+               return ret;
  
-       return len;
+       return op.data.nbytes;
  }
  
  /*
index b864b93dd289ed6eda8b2591006a6ab57922c1b7,07a87717a3cad49da0fdc989440bc47c025d0436..830ea247277b1cac529e4814834eb20c05212e7f
@@@ -1,15 -1,10 +1,10 @@@
+ // SPDX-License-Identifier: GPL-2.0
  /*
   * NAND Flash Controller Device Driver
   * Copyright © 2009-2010, Intel Corporation and its suppliers.
   *
-  * 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.
-  *
-  * This program is distributed in the hope it will be useful, but WITHOUT
-  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  * more details.
+  * Copyright (c) 2017 Socionext Inc.
+  *   Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
   */
  
  #include <linux/bitfield.h>
@@@ -25,9 -20,8 +20,8 @@@
  
  #include "denali.h"
  
- MODULE_LICENSE("GPL");
  #define DENALI_NAND_NAME    "denali-nand"
+ #define DENALI_DEFAULT_OOB_SKIP_BYTES 8
  
  /* for Indexed Addressing */
  #define DENALI_INDEXED_CTRL   0x00
@@@ -222,8 -216,9 +216,9 @@@ static uint32_t denali_check_irq(struc
        return irq_status;
  }
  
- static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+ static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        int i;
                buf[i] = denali->host_read(denali, addr);
  }
  
- static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+ static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
+                            int len)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        int i;
  
                denali->host_write(denali, addr, buf[i]);
  }
  
- static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+ static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        uint16_t *buf16 = (uint16_t *)buf;
        int i;
                buf16[i] = denali->host_read(denali, addr);
  }
  
- static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+ static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
                               int len)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        const uint16_t *buf16 = (const uint16_t *)buf;
        int i;
                denali->host_write(denali, addr, buf16[i]);
  }
  
- static uint8_t denali_read_byte(struct mtd_info *mtd)
+ static uint8_t denali_read_byte(struct nand_chip *chip)
  {
        uint8_t byte;
  
-       denali_read_buf(mtd, &byte, 1);
+       denali_read_buf(chip, &byte, 1);
  
        return byte;
  }
  
- static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
- {
-       denali_write_buf(mtd, &byte, 1);
- }
- static uint16_t denali_read_word(struct mtd_info *mtd)
+ static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
  {
-       uint16_t word;
-       denali_read_buf16(mtd, (uint8_t *)&word, 2);
-       return word;
+       denali_write_buf(chip, &byte, 1);
  }
  
- static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+ static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t type;
  
        if (ctrl & NAND_CLE)
                return;
  
        /*
-        * Some commands are followed by chip->dev_ready or chip->waitfunc.
+        * Some commands are followed by chip->legacy.dev_ready or
+        * chip->legacy.waitfunc.
         * irq_status must be cleared here to catch the R/B# interrupt later.
         */
        if (ctrl & NAND_CTRL_CHANGE)
        denali->host_write(denali, DENALI_BANK(denali) | type, dat);
  }
  
- static int denali_dev_ready(struct mtd_info *mtd)
+ static int denali_dev_ready(struct nand_chip *chip)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
  
        return !!(denali_check_irq(denali) & INTR__INT_ACT);
  }
@@@ -596,12 -584,6 +584,12 @@@ static int denali_dma_xfer(struct denal
        }
  
        iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
 +      /*
 +       * The ->setup_dma() hook kicks DMA by using the data/command
 +       * interface, which belongs to a different AXI port from the
 +       * register interface.  Read back the register to avoid a race.
 +       */
 +      ioread32(denali->reg + DMA_ENABLE);
  
        denali_reset_irq(denali);
        denali->setup_dma(denali, dma_addr, page, write);
@@@ -698,9 -680,10 +686,10 @@@ static void denali_oob_xfer(struct mtd_
                                           false);
  }
  
- static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+ static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        int writesize = mtd->writesize;
        int oobsize = mtd->oobsize;
        return 0;
  }
  
- static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                          int page)
+ static int denali_read_oob(struct nand_chip *chip, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        denali_oob_xfer(mtd, chip, page, 0);
  
        return 0;
  }
  
- static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page)
+ static int denali_write_oob(struct nand_chip *chip, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
  
        denali_reset_irq(denali);
        return nand_prog_page_end_op(chip);
  }
  
- static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                           uint8_t *buf, int oob_required, int page)
+ static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
+                           int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        unsigned long uncor_ecc_flags = 0;
        int stat = 0;
                return stat;
  
        if (uncor_ecc_flags) {
-               ret = denali_read_oob(mtd, chip, page);
+               ret = denali_read_oob(chip, page);
                if (ret)
                        return ret;
  
        return stat;
  }
  
- static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                const uint8_t *buf, int oob_required, int page)
+ static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+                                int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        int writesize = mtd->writesize;
        int oobsize = mtd->oobsize;
        return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
  }
  
- static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                            const uint8_t *buf, int oob_required, int page)
+ static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
+                            int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
  
        return denali_data_xfer(denali, (void *)buf, mtd->writesize,
                                page, 0, 1);
  }
  
- static void denali_select_chip(struct mtd_info *mtd, int chip)
+ static void denali_select_chip(struct nand_chip *chip, int cs)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
  
-       denali->active_bank = chip;
+       denali->active_bank = cs;
  }
  
- static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+ static int denali_waitfunc(struct nand_chip *chip)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t irq_status;
  
        /* R/B# pin transitioned from low to high? */
        return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
  }
  
- static int denali_erase(struct mtd_info *mtd, int page)
+ static int denali_erase(struct nand_chip *chip, int page)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t irq_status;
  
        denali_reset_irq(denali);
        return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
  }
  
- static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
                                       const struct nand_data_interface *conf)
  {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        const struct nand_sdr_timings *timings;
        unsigned long t_x, mult_x;
        int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
@@@ -1105,12 -1092,17 +1098,17 @@@ static void denali_hw_init(struct denal
                denali->revision = swab16(ioread32(denali->reg + REVISION));
  
        /*
-        * tell driver how many bit controller will skip before
-        * writing ECC code in OOB, this register may be already
-        * set by firmware. So we read this value out.
-        * if this value is 0, just let it be.
+        * Set how many bytes should be skipped before writing data in OOB.
+        * If a non-zero value has already been set (by firmware or something),
+        * just use it.  Otherwise, set the driver default.
         */
        denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+       if (!denali->oob_skip_bytes) {
+               denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
+               iowrite32(denali->oob_skip_bytes,
+                         denali->reg + SPARE_AREA_SKIP_BYTES);
+       }
        denali_detect_max_banks(denali);
        iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
        iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
@@@ -1277,11 -1269,11 +1275,11 @@@ static int denali_attach_chip(struct na
        mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
  
        if (chip->options & NAND_BUSWIDTH_16) {
-               chip->read_buf = denali_read_buf16;
-               chip->write_buf = denali_write_buf16;
+               chip->legacy.read_buf = denali_read_buf16;
+               chip->legacy.write_buf = denali_write_buf16;
        } else {
-               chip->read_buf = denali_read_buf;
-               chip->write_buf = denali_write_buf;
+               chip->legacy.read_buf = denali_read_buf;
+               chip->legacy.write_buf = denali_write_buf;
        }
        chip->ecc.read_page = denali_read_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
        chip->ecc.write_page_raw = denali_write_page_raw;
        chip->ecc.read_oob = denali_read_oob;
        chip->ecc.write_oob = denali_write_oob;
-       chip->erase = denali_erase;
+       chip->legacy.erase = denali_erase;
  
        ret = denali_multidev_fixup(denali);
        if (ret)
@@@ -1358,12 -1350,11 +1356,11 @@@ int denali_init(struct denali_nand_inf
                mtd->name = "denali-nand";
  
        chip->select_chip = denali_select_chip;
-       chip->read_byte = denali_read_byte;
-       chip->write_byte = denali_write_byte;
-       chip->read_word = denali_read_word;
-       chip->cmd_ctrl = denali_cmd_ctrl;
-       chip->dev_ready = denali_dev_ready;
-       chip->waitfunc = denali_waitfunc;
+       chip->legacy.read_byte = denali_read_byte;
+       chip->legacy.write_byte = denali_write_byte;
+       chip->legacy.cmd_ctrl = denali_cmd_ctrl;
+       chip->legacy.dev_ready = denali_dev_ready;
+       chip->legacy.waitfunc = denali_waitfunc;
  
        if (features & FEATURES__INDEX_ADDR) {
                denali->host_read = denali_indexed_read;
                chip->setup_data_interface = denali_setup_data_interface;
  
        chip->dummy_controller.ops = &denali_controller_ops;
-       ret = nand_scan(mtd, denali->max_banks);
+       ret = nand_scan(chip, denali->max_banks);
        if (ret)
                goto disable_irq;
  
@@@ -1401,9 -1392,11 +1398,11 @@@ EXPORT_SYMBOL(denali_init)
  
  void denali_remove(struct denali_nand_info *denali)
  {
-       struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-       nand_release(mtd);
+       nand_release(&denali->nand);
        denali_disable_irq(denali);
  }
  EXPORT_SYMBOL(denali_remove);
+ MODULE_DESCRIPTION("Driver core for Denali NAND controller");
+ MODULE_AUTHOR("Intel Corporation and its suppliers");
+ MODULE_LICENSE("GPL v2");
index bc2ef52097834f7c43194835a5177d102e6e2c88,c6e039f362f1bf2f10e9d75afb347e624ae81d6a..650f2b490a054c16c8c20f882f0c72134fadd7b1
@@@ -5,6 -5,73 +5,73 @@@
   * Copyright (C) 2017 Marvell
   * Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
   *
+  *
+  * This NAND controller driver handles two versions of the hardware,
+  * one is called NFCv1 and is available on PXA SoCs and the other is
+  * called NFCv2 and is available on Armada SoCs.
+  *
+  * The main visible difference is that NFCv1 only has Hamming ECC
+  * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
+  * is not used with NFCv2.
+  *
+  * The ECC layouts are depicted in details in Marvell AN-379, but here
+  * is a brief description.
+  *
+  * When using Hamming, the data is split in 512B chunks (either 1, 2
+  * or 4) and each chunk will have its own ECC "digest" of 6B at the
+  * beginning of the OOB area and eventually the remaining free OOB
+  * bytes (also called "spare" bytes in the driver). This engine
+  * corrects up to 1 bit per chunk and detects reliably an error if
+  * there are at most 2 bitflips. Here is the page layout used by the
+  * controller when Hamming is chosen:
+  *
+  * +-------------------------------------------------------------+
+  * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
+  * +-------------------------------------------------------------+
+  *
+  * When using the BCH engine, there are N identical (data + free OOB +
+  * ECC) sections and potentially an extra one to deal with
+  * configurations where the chosen (data + free OOB + ECC) sizes do
+  * not align with the page (data + OOB) size. ECC bytes are always
+  * 30B per ECC chunk. Here is the page layout used by the controller
+  * when BCH is chosen:
+  *
+  * +-----------------------------------------
+  * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
+  * +-----------------------------------------
+  *
+  *      -------------------------------------------
+  *       ... | Data N | Free OOB bytes N | ECC N |
+  *      -------------------------------------------
+  *
+  *           --------------------------------------------+
+  *            Last Data | Last Free OOB bytes | Last ECC |
+  *           --------------------------------------------+
+  *
+  * In both cases, the layout seen by the user is always: all data
+  * first, then all free OOB bytes and finally all ECC bytes. With BCH,
+  * ECC bytes are 30B long and are padded with 0xFF to align on 32
+  * bytes.
+  *
+  * The controller has certain limitations that are handled by the
+  * driver:
+  *   - It can only read 2k at a time. To overcome this limitation, the
+  *     driver issues data cycles on the bus, without issuing new
+  *     CMD + ADDR cycles. The Marvell term is "naked" operations.
+  *   - The ECC strength in BCH mode cannot be tuned. It is fixed 16
+  *     bits. What can be tuned is the ECC block size as long as it
+  *     stays between 512B and 2kiB. It's usually chosen based on the
+  *     chip ECC requirements. For instance, using 2kiB ECC chunks
+  *     provides 4b/512B correctability.
+  *   - The controller will always treat data bytes, free OOB bytes
+  *     and ECC bytes in that order, no matter what the real layout is
+  *     (which is usually all data then all OOB bytes). The
+  *     marvell_nfc_layouts array below contains the currently
+  *     supported layouts.
+  *   - Because of these weird layouts, the Bad Block Markers can be
+  *     located in data section. In this case, the NAND_BBT_NO_OOB_BBM
+  *     option must be set to prevent scanning/writing bad block
+  *     markers.
   */
  
  #include <linux/module.h>
@@@ -217,8 -284,11 +284,11 @@@ static const struct marvell_hw_ecc_layo
        MARVELL_LAYOUT(  512,   512,  1,  1,  1,  512,  8,  8,  0,  0,  0),
        MARVELL_LAYOUT( 2048,   512,  1,  1,  1, 2048, 40, 24,  0,  0,  0),
        MARVELL_LAYOUT( 2048,   512,  4,  1,  1, 2048, 32, 30,  0,  0,  0),
+       MARVELL_LAYOUT( 2048,   512,  8,  2,  1, 1024,  0, 30,1024,32, 30),
        MARVELL_LAYOUT( 4096,   512,  4,  2,  2, 2048, 32, 30,  0,  0,  0),
        MARVELL_LAYOUT( 4096,   512,  8,  5,  4, 1024,  0, 30,  0, 64, 30),
+       MARVELL_LAYOUT( 8192,   512,  4,  4,  4, 2048,  0, 30,  0,  0,  0),
+       MARVELL_LAYOUT( 8192,   512,  8,  9,  8, 1024,  0, 30,  0, 160, 30),
  };
  
  /**
@@@ -634,9 -704,8 +704,8 @@@ static int marvell_nfc_wait_op(struct n
        return 0;
  }
  
- static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+ static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
  {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
        u32 ndcr_generic;
@@@ -686,7 -755,7 +755,7 @@@ static irqreturn_t marvell_nfc_isr(int 
  
        marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
  
-       if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+       if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
                complete(&nfc->complete);
  
        return IRQ_HANDLED;
@@@ -959,18 -1028,15 +1028,15 @@@ static int marvell_nfc_hw_ecc_hmg_do_re
        return ret;
  }
  
- static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip, u8 *buf,
+ static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
                                                int oob_required, int page)
  {
        return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
                                                   true, page);
  }
  
- static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
-                                           u8 *buf, int oob_required,
-                                           int page)
+ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
+                                           int oob_required, int page)
  {
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
   * it appears before the ECC bytes when reading), the ->read_oob_raw() function
   * also stands for ->read_oob().
   */
- static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
-                                              struct nand_chip *chip, int page)
+ static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
  {
        /* Invalidate page cache */
        chip->pagebuf = -1;
@@@ -1073,8 -1138,7 +1138,7 @@@ static int marvell_nfc_hw_ecc_hmg_do_wr
        return ret;
  }
  
- static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
-                                                struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
                                                 const u8 *buf,
                                                 int oob_required, int page)
  {
                                                    true, page);
  }
  
- static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
                                             const u8 *buf,
                                             int oob_required, int page)
  {
   * it appears before the ECC bytes when reading), the ->write_oob_raw() function
   * also stands for ->write_oob().
   */
- static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
                                                int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        /* Invalidate page cache */
        chip->pagebuf = -1;
  
  }
  
  /* BCH read helpers */
- static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip, u8 *buf,
+ static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
                                                int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        u8 *oob = chip->oob_poi;
        int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@@ -1228,17 -1292,17 +1292,17 @@@ static void marvell_nfc_hw_ecc_bch_read
        }
  }
  
- static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
                                            u8 *buf, int oob_required,
                                            int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-       int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
-       u8 *data = buf, *spare = chip->oob_poi, *ecc;
+       int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
+       u8 *data = buf, *spare = chip->oob_poi;
        int max_bitflips = 0;
        u32 failure_mask = 0;
-       int chunk, ecc_offset_in_page, ret;
+       int chunk, ret;
  
        /*
         * With BCH, OOB is not fully used (and thus not read entirely), not
         * the controller in normal mode and must be re-read in raw mode. To
         * avoid dropping the performances, we prefer not to include them. The
         * user should re-read the page in raw mode if ECC bytes are required.
+        */
+       /*
+        * In case there is any subpage read error reported by ->correct(), we
+        * usually re-read only ECC bytes in raw mode and check if the whole
+        * page is empty. In this case, it is normal that the ECC check failed
+        * and we just ignore the error.
         *
-        * However, for any subpage read error reported by ->correct(), the ECC
-        * bytes must be read in raw mode and the full subpage must be checked
-        * to see if it is entirely empty of if there was an actual error.
+        * However, it has been empirically observed that for some layouts (e.g
+        * 2k page, 8b strength per 512B chunk), the controller tries to correct
+        * bits and may create itself bitflips in the erased area. To overcome
+        * this strange behavior, the whole page is re-read in raw mode, not
+        * only the ECC bytes.
         */
        for (chunk = 0; chunk < lt->nchunks; chunk++) {
+               int data_off_in_page, spare_off_in_page, ecc_off_in_page;
+               int data_off, spare_off, ecc_off;
+               int data_len, spare_len, ecc_len;
                /* No failure reported for this chunk, move to the next one */
                if (!(failure_mask & BIT(chunk)))
                        continue;
  
-               /* Derive ECC bytes positions (in page/buffer) and length */
-               ecc = chip->oob_poi +
-                       (lt->full_chunk_cnt * lt->spare_bytes) +
-                       lt->last_spare_bytes +
-                       (chunk * ALIGN(lt->ecc_bytes, 32));
-               ecc_offset_in_page =
-                       (chunk * (lt->data_bytes + lt->spare_bytes +
-                                 lt->ecc_bytes)) +
-                       (chunk < lt->full_chunk_cnt ?
-                        lt->data_bytes + lt->spare_bytes :
-                        lt->last_data_bytes + lt->last_spare_bytes);
-               ecc_len = chunk < lt->full_chunk_cnt ?
-                       lt->ecc_bytes : lt->last_ecc_bytes;
-               /* Do the actual raw read of the ECC bytes */
-               nand_change_read_column_op(chip, ecc_offset_in_page,
-                                          ecc, ecc_len, false);
-               /* Derive data/spare bytes positions (in buffer) and length */
-               data = buf + (chunk * lt->data_bytes);
-               data_len = chunk < lt->full_chunk_cnt ?
-                       lt->data_bytes : lt->last_data_bytes;
-               spare = chip->oob_poi + (chunk * (lt->spare_bytes +
-                                                 lt->ecc_bytes));
-               spare_len = chunk < lt->full_chunk_cnt ?
-                       lt->spare_bytes : lt->last_spare_bytes;
+               data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
+                                           lt->ecc_bytes);
+               spare_off_in_page = data_off_in_page +
+                       (chunk < lt->full_chunk_cnt ? lt->data_bytes :
+                                                     lt->last_data_bytes);
+               ecc_off_in_page = spare_off_in_page +
+                       (chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+                                                     lt->last_spare_bytes);
+               data_off = chunk * lt->data_bytes;
+               spare_off = chunk * lt->spare_bytes;
+               ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
+                         lt->last_spare_bytes +
+                         (chunk * (lt->ecc_bytes + 2));
+               data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
+                                                       lt->last_data_bytes;
+               spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+                                                        lt->last_spare_bytes;
+               ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
+                                                      lt->last_ecc_bytes;
+               /*
+                * Only re-read the ECC bytes, unless we are using the 2k/8b
+                * layout which is buggy in the sense that the ECC engine will
+                * try to correct data bytes anyway, creating bitflips. In this
+                * case, re-read the entire page.
+                */
+               if (lt->writesize == 2048 && lt->strength == 8) {
+                       nand_change_read_column_op(chip, data_off_in_page,
+                                                  buf + data_off, data_len,
+                                                  false);
+                       nand_change_read_column_op(chip, spare_off_in_page,
+                                                  chip->oob_poi + spare_off, spare_len,
+                                                  false);
+               }
+               nand_change_read_column_op(chip, ecc_off_in_page,
+                                          chip->oob_poi + ecc_off, ecc_len,
+                                          false);
  
                /* Check the entire chunk (data + spare + ecc) for emptyness */
-               marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
-                                             spare_len, ecc, ecc_len,
+               marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
+                                             chip->oob_poi + spare_off, spare_len,
+                                             chip->oob_poi + ecc_off, ecc_len,
                                              &max_bitflips);
        }
  
        return max_bitflips;
  }
  
- static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
-                                              struct nand_chip *chip, int page)
+ static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
  {
        /* Invalidate page cache */
        chip->pagebuf = -1;
  
-       return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
  }
  
- static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
-                                          struct nand_chip *chip, int page)
+ static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
  {
        /* Invalidate page cache */
        chip->pagebuf = -1;
  
-       return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.read_page(chip, chip->data_buf, true, page);
  }
  
  /* BCH write helpers */
- static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
-                                                struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
                                                 const u8 *buf,
                                                 int oob_required, int page)
  {
@@@ -1458,11 -1547,11 +1547,11 @@@ marvell_nfc_hw_ecc_bch_write_chunk(stru
        return 0;
  }
  
- static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
                                             const u8 *buf,
                                             int oob_required, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        const u8 *data = buf;
        const u8 *spare = chip->oob_poi;
        return 0;
  }
  
- static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+ static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
                                                int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        /* Invalidate page cache */
        chip->pagebuf = -1;
  
        memset(chip->data_buf, 0xFF, mtd->writesize);
  
-       return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
  }
  
- static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
-                                           struct nand_chip *chip, int page)
+ static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
  {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        /* Invalidate page cache */
        chip->pagebuf = -1;
  
        memset(chip->data_buf, 0xFF, mtd->writesize);
  
-       return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.write_page(chip, chip->data_buf, true, page);
  }
  
  /* NAND framework ->exec_op() hooks and related helpers */
@@@ -1547,7 -1638,7 +1638,7 @@@ static void marvell_nfc_parse_instructi
        for (op_id = 0; op_id < subop->ninstrs; op_id++) {
                unsigned int offset, naddrs;
                const u8 *addrs;
 -              int len = nand_subop_get_data_len(subop, op_id);
 +              int len;
  
                instr = &subop->instrs[op_id];
  
                                nfc_op->ndcb[0] |=
                                        NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
                                        NDCB0_LEN_OVRD;
 +                              len = nand_subop_get_data_len(subop, op_id);
                                nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
                        }
                        nfc_op->data_delay_ns = instr->delay_ns;
                                nfc_op->ndcb[0] |=
                                        NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
                                        NDCB0_LEN_OVRD;
 +                              len = nand_subop_get_data_len(subop, op_id);
                                nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
                        }
                        nfc_op->data_delay_ns = instr->delay_ns;
@@@ -2097,6 -2186,16 +2188,16 @@@ static int marvell_nand_hw_ecc_ctrl_ini
                return -ENOTSUPP;
        }
  
+       /* Special care for the layout 2k/8-bit/512B  */
+       if (l->writesize == 2048 && l->strength == 8) {
+               if (mtd->oobsize < 128) {
+                       dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
+                       return -ENOTSUPP;
+               } else {
+                       chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+               }
+       }
        mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
        ecc->steps = l->nchunks;
        ecc->size = l->data_bytes;
@@@ -2192,11 -2291,10 +2293,10 @@@ static struct nand_bbt_descr bbt_mirror
        .pattern = bbt_mirror_pattern
  };
  
- static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+ static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
                                            const struct nand_data_interface
                                            *conf)
  {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
        unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
@@@ -2540,7 -2638,7 +2640,7 @@@ static int marvell_nand_chip_init(struc
  
        chip->options |= NAND_BUSWIDTH_AUTO;
  
-       ret = nand_scan(mtd, marvell_nand->nsels);
+       ret = nand_scan(chip, marvell_nand->nsels);
        if (ret) {
                dev_err(dev, "could not scan the nand chip\n");
                return ret;
                ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "failed to register mtd device: %d\n", ret);
-               nand_release(mtd);
+               nand_release(chip);
                return ret;
        }
  
@@@ -2608,7 -2706,7 +2708,7 @@@ static void marvell_nand_chips_cleanup(
        struct marvell_nand_chip *entry, *temp;
  
        list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
-               nand_release(nand_to_mtd(&entry->chip));
+               nand_release(&entry->chip);
                list_del(&entry->node);
        }
  }
@@@ -2699,24 -2797,23 +2799,23 @@@ static int marvell_nfc_init(struct marv
                struct regmap *sysctrl_base =
                        syscon_regmap_lookup_by_phandle(np,
                                                        "marvell,system-controller");
-               u32 reg;
  
                if (IS_ERR(sysctrl_base))
                        return PTR_ERR(sysctrl_base);
  
-               reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
-                     GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
-                     GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
-                     GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
-               regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+               regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
+                            GENCONF_SOC_DEVICE_MUX_NFC_EN |
+                            GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+                            GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+                            GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
  
-               regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
-               reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
-               regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+               regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
+                                  GENCONF_CLK_GATING_CTRL_ND_GATE,
+                                  GENCONF_CLK_GATING_CTRL_ND_GATE);
  
-               regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
-               reg |= GENCONF_ND_CLK_CTRL_EN;
-               regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+               regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
+                                  GENCONF_ND_CLK_CTRL_EN,
+                                  GENCONF_ND_CLK_CTRL_EN);
        }
  
        /* Configure the DMA if appropriate */