devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
@ 2017-12-07 20:18 Miquel Raynal
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Hi,

After the addition of the NAND framework ->exec_op() interface (see [1]
for the series preparing it and [2] for the last version of the
core-side implementation of ->exec_op() itself), this series replaces
the current Marvell NAND controller driver pxa3xx_nand.c with a rework
called marvell_nand.c.

Aside the fact that it drops the big state machine, improves the overall
speed and implements raw accesses, it is the first driver-side
implementation of the ->exec_op() interface and may be used as reference
for latter reworks of the same type.

One may find more detail about why a completely new driver is needed in
the commit log of:

    "mtd: nand: add reworked Marvell NAND controller driver"

The series also changes the device tree NAND node definition for all
platforms referring to the Marvell driver to use the new bindings. They
are more hierarchical and fit the real organization of the hardware, by
having NAND partitions that are part of NAND chip nodes, themselves part
of the NAND controller node.

These changes have been tested on:
   - PXA3xx platform with a CM-X300 board (2kiB page NAND, 1b/512B
     strength, Hamming ECC engine) [32 bits]
   - Armada 385 DB AP (4kiB page NAND, 4b/512B, BCH ECC engine) [32 bits]
   - Armada 398 DB (4kiB page NAND, 8b/512B, BCH ECC engine using a layout
     with a last chunk different than the others) [32 bits]
   - Armada 7040 DB and Armada 8040 DB (4kiB page NAND, 4b/512B, BCH ECC
     engine) [64 bits]

Robert, it would be great if you could also do more testing on PXA and
validate this driver. If needed, a branch ready to be tested is
available at [3]. It is based on nand/next and has all the changes
brought by the previously mentionned series as well as this one.

Thank you,
Miquèl


[1] https://www.spinics.net/lists/arm-kernel/msg619633.html
[2] http://lists.infradead.org/pipermail/linux-mtd/2017-December/077965.html
[3] https://github.com/miquelraynal/linux/tree/marvell/nand-next/nfc-rework

Miquel Raynal (12):
  dt-bindings: mtd: add Marvell NAND controller documentation
  mtd: nand: add reworked Marvell NAND controller driver
  mtd: nand: replace pxa3xx_nand driver by its rework called
    marvell_nand
  dt-bindings: mtd: remove pxa3xx NAND controller documentation
  mtd: nand: remove useless fields from pxa3xx NAND platform data
  ARM: dts: armada-370-xp: use reworked NAND controller driver
  ARM: dts: armada-375: use reworked NAND controller driver
  ARM: dts: armada-38x: use reworked NAND controller driver
  ARM: dts: armada-39x: use reworked NAND controller driver
  ARM: dts: pxa: use reworked NAND controller driver
  ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
  ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K

 .../devicetree/bindings/mtd/marvell-nand.txt       |   84 +
 .../devicetree/bindings/mtd/pxa3xx-nand.txt        |   50 -
 arch/arm/boot/dts/armada-370-db.dts                |   57 +-
 arch/arm/boot/dts/armada-370-dlink-dns327l.dts     |  120 +-
 arch/arm/boot/dts/armada-370-mirabox.dts           |   51 +-
 arch/arm/boot/dts/armada-370-netgear-rn102.dts     |   90 +-
 arch/arm/boot/dts/armada-370-netgear-rn104.dts     |   90 +-
 arch/arm/boot/dts/armada-370-rd.dts                |   52 +-
 arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi |   64 +-
 arch/arm/boot/dts/armada-370-xp.dtsi               |    6 +-
 arch/arm/boot/dts/armada-375-db.dts                |   50 +-
 arch/arm/boot/dts/armada-375.dtsi                  |    6 +-
 arch/arm/boot/dts/armada-385-db-ap.dts             |   69 +-
 arch/arm/boot/dts/armada-385-linksys-caiman.dts    |  129 +-
 arch/arm/boot/dts/armada-385-linksys-cobra.dts     |  129 +-
 arch/arm/boot/dts/armada-385-linksys-rango.dts     |  141 +-
 arch/arm/boot/dts/armada-385-linksys-shelby.dts    |  129 +-
 arch/arm/boot/dts/armada-385-linksys.dtsi          |   16 +-
 arch/arm/boot/dts/armada-388-db.dts                |   55 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |    6 +-
 arch/arm/boot/dts/armada-390-db.dts                |   66 +-
 arch/arm/boot/dts/armada-395-gp.dts                |   74 +-
 arch/arm/boot/dts/armada-398-db.dts                |   60 +-
 arch/arm/boot/dts/armada-39x.dtsi                  |    6 +-
 arch/arm/boot/dts/armada-xp-db-dxbc2.dts           |    2 +-
 arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts      |    2 +-
 arch/arm/boot/dts/armada-xp-db.dts                 |    2 +-
 arch/arm/boot/dts/armada-xp-gp.dts                 |    2 +-
 arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts    |    2 +-
 arch/arm/boot/dts/armada-xp-linksys-mamba.dts      |  156 +-
 arch/arm/boot/dts/armada-xp-netgear-rn2120.dts     |   90 +-
 arch/arm/boot/dts/pxa3xx.dtsi                      |    6 +-
 arch/arm/configs/cm_x300_defconfig                 |    2 +-
 arch/arm/configs/mvebu_v7_defconfig                |    2 +-
 arch/arm/configs/pxa3xx_defconfig                  |    3 +-
 arch/arm/configs/pxa_defconfig                     |    2 +-
 arch/arm/configs/raumfeld_defconfig                |    2 +-
 arch/arm/mach-mmp/ttc_dkb.c                        |    4 +-
 arch/arm/mach-pxa/cm-x300.c                        |    8 +-
 arch/arm/mach-pxa/colibri-pxa3xx.c                 |    8 +-
 arch/arm/mach-pxa/colibri.h                        |    2 +-
 arch/arm/mach-pxa/littleton.c                      |   10 +-
 arch/arm/mach-pxa/mxm8x10.c                        |   10 +-
 arch/arm/mach-pxa/raumfeld.c                       |    6 +-
 arch/arm/mach-pxa/zylonite.c                       |   10 +-
 arch/arm64/boot/dts/marvell/armada-7040-db.dts     |   52 +-
 arch/arm64/boot/dts/marvell/armada-8040-db.dts     |   46 +-
 .../boot/dts/marvell/armada-cp110-master.dtsi      |    8 +-
 .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi |   10 +-
 drivers/mtd/nand/Kconfig                           |   12 +
 drivers/mtd/nand/Makefile                          |    2 +-
 drivers/mtd/nand/marvell_nand.c                    | 2950 ++++++++++++++++++++
 drivers/mtd/nand/pxa3xx_nand.c                     | 2104 --------------
 include/linux/platform_data/mtd-nand-pxa3xx.h      |   43 +-
 54 files changed, 4093 insertions(+), 3065 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mtd/marvell-nand.txt
 delete mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
 create mode 100644 drivers/mtd/nand/marvell_nand.c
 delete mode 100644 drivers/mtd/nand/pxa3xx_nand.c

-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 01/12] dt-bindings: mtd: add Marvell NAND controller documentation
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-07 20:18   ` Miquel Raynal
       [not found]     ` <20171207201814.30411-2-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-07 20:18   ` [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver Miquel Raynal
                     ` (12 subsequent siblings)
  13 siblings, 1 reply; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Document the legacy and the new bindings for Marvell NAND controller.

The pxa3xx_nand.c driver does only support legacy bindings, which are
incomplete and inaccurate. A rework of this controller (called
marvell_nand.c) does support both.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 .../devicetree/bindings/mtd/marvell-nand.txt       | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/marvell-nand.txt

diff --git a/Documentation/devicetree/bindings/mtd/marvell-nand.txt b/Documentation/devicetree/bindings/mtd/marvell-nand.txt
new file mode 100644
index 000000000000..0b3d5e0bab83
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/marvell-nand.txt
@@ -0,0 +1,84 @@
+Marvell NAND Flash Controller (NFC)
+
+Required properties:
+- compatible: can be one of the following:
+    * "marvell,armada-8k-nand-controller"
+    * "marvell,armada370-nand-controller"
+    * "marvell,pxa3xx-nand-controller"
+    * "marvell,armada-8k-nand" (deprecated)
+    * "marvell,armada370-nand" (deprecated)
+    * "marvell,pxa3xx-nand" (deprecated)
+- reg: NAND flash controller memory area.
+- #address-cells: shall be set to 1. Encode the NAND CS.
+- #size-cells: shall be set to 0.
+- interrupts: shall define the NAND controller interrupt.
+- clocks: shall reference the NAND controller clock.
+- marvell,system-controller: Set to retrieve the syscon node that handles
+  NAND controller related registers (only required with the
+  "marvell,armada-8k-nand[-controller]" compatibles).
+
+Optional properties:
+- label: see partition.txt. New platforms shall omit this property.
+- dmas: shall reference DMA channel associated to the NAND controller.
+- dma-names: shall be "rxtx".
+
+Optional children nodes:
+Children nodes represent the available NAND chips.
+
+Required properties:
+- reg: shall contain the native Chip Select ids (0-3)
+- marvell,rb: shall contain the native Ready/Busy ids (0-1)
+
+Optional properties:
+- marvell,nand-keep-config: orders the driver not to take the timings
+  from the core and leaving them completely untouched. Bootloader
+  timings will then be used.
+- nand-on-flash-bbt: see nand.txt.
+- nand-ecc-mode: see nand.txt. Will use hardware ECC if not specified.
+- nand-ecc-algo: see nand.txt. This property may be added when using
+  hardware ECC for clarification but will be ignored by the driver
+  because ECC mode is chosen depending on the page size and the strength
+  required by the NAND chip. This value may be overwritten with
+  nand-ecc-strength property.
+- nand-ecc-strength: see nand.txt.
+- nand-ecc-step-size: see nand.txt. This has no effect and will be
+  ignored by the driver when using hardware ECC because Marvell's NAND
+  flash controller does use fixed strength (1-bit for Hamming, 16-bit
+  for BCH), so the step size will shrink or grow in order to fit the
+  required strength. Step sizes are not completely random for all and
+  follow certain patterns described in AN-379, "Marvell SoC NFC ECC".
+
+See Documentation/devicetree/bindings/mtd/nand.txt for more details on
+generic bindings.
+
+
+Example:
+nand_controller: nand-controller@d0000 {
+	compatible = "marvell,armada370-nand-controller";
+	reg = <0xd0000 0x54>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&coredivclk 0>;
+
+	nand@0 {
+		reg = <0>;
+		marvell,rb = <0>;
+		nand-ecc-mode = "hw";
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "Rootfs";
+				reg = <0x00000000 0x40000000>;
+			};
+		};
+	};
+};
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-07 20:18   ` [PATCH 01/12] dt-bindings: mtd: add Marvell NAND controller documentation Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
       [not found]     ` <20171207201814.30411-3-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-07 20:18   ` [PATCH 03/12] mtd: nand: replace pxa3xx_nand driver by its rework called marvell_nand Miquel Raynal
                     ` (11 subsequent siblings)
  13 siblings, 1 reply; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Add marvell_nand driver which aims at replacing the existing pxa3xx_nand
driver.

The new driver intends to be easier to understand and follows the brand
new NAND framework rules by implementing hooks for every pattern the
controller might support and referencing them inside a parser object
that will be given to the core at each ->exec_op() call.

Raw accessors are implemented, useful to test/debug memory/filesystem
corruptions. Userspace binaries contained in the mtd-utils package may
now be used and their output trusted.

Timings may not be kept from the bootloader anymore, the timings used
for instance in U-Boot were not optimal and it supposed to have NAND
support (and initialized) in the bootloader.

Thanks to the improved timings, implementation of ONFI mode 5 support
(with EDO managed by adding a delay on data sampling), merging the
commands together and optimizing writes in the command registers, the
new driver may achieve faster throughputs in both directions.
Measurements show an improvement of about +23% read throughput and +24%
write throughput. These measurements have been done with an
Armada-385-DB-AP (4kiB NAND pages forced in 4-bit strength BCH ECC
correction) using the userspace tool 'flash_speed' from the MTD test
suite.

Besides these important topics, the new driver addresses several
unsolved known issues in the old driver which:
- did not work with ECC soft neither with ECC none ;
- relied on naked read/write (which is unchanged) while the NFCv1
  embedded in the pxa3xx platforms do not implement it, so several
  NAND commands did not actually ever work without any notice (like
  reading the ONFI PARAM_PAGE or SET/GET_FEATURES) ;
- wrote the OOB data correctly, but was not able to read it correctly
  past the first OOB data chunk ;
- did not displayed ECC bytes ;
- used device tree bindings that did not allow more than one NAND chip,
  and did not allow to choose the correct chip select if not
  incrementing from 0. Plus, the Ready/Busy line used had to be 0.

Old device tree bindings are still supported but deprecated. A more
hierarchical view has to be used to keep the controller and the NAND
chip structures clearly separated both inside the device tree and also
in the driver code.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 drivers/mtd/nand/Kconfig        |   12 +
 drivers/mtd/nand/Makefile       |    1 +
 drivers/mtd/nand/marvell_nand.c | 2951 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 2964 insertions(+)
 create mode 100644 drivers/mtd/nand/marvell_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 859eb7790c46..9e141e03f5c2 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -323,6 +323,18 @@ config MTD_NAND_PXA3xx
 	  platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
 	  platforms (7K, 8K) (NFCv2).
 
+config MTD_NAND_MARVELL
+	tristate "NAND controller support on Marvell boards"
+	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
+		   COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This enables the NAND flash controller driver for Marvell boards,
+	  including:
+	  - PXA3xx processors (NFCv1)
+	  - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
+	  - 64-bit Aramda platforms (7k, 8k) (NFCv2)
+
 config MTD_NAND_SLC_LPC32XX
 	tristate "NXP LPC32xx SLC Controller"
 	depends on ARCH_LPC32XX
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 118a1349aad3..921634ba400c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
 obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
 obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
+obj-$(CONFIG_MTD_NAND_MARVELL)		+= marvell_nand.o
 obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c
new file mode 100644
index 000000000000..2525d9b2f4fa
--- /dev/null
+++ b/drivers/mtd/nand/marvell_nand.c
@@ -0,0 +1,2951 @@
+/*
+ * Marvell NAND flash controller driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2017 Marvell
+ * Author: Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of_platform.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <asm/unaligned.h>
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
+#include <linux/platform_data/mtd-nand-pxa3xx.h>
+
+/* Data FIFO granularity, FIFO reads/writes must be a multiple of this length */
+#define FIFO_DEPTH		8
+#define FIFO_REP(x)		(x / sizeof(u32))
+#define BCH_SEQ_READS		(32 / FIFO_DEPTH)
+/* NFC does not support transfers of larger chunks at a time */
+#define MAX_CHUNK_SIZE		2112
+/* NFCv1 cannot read more that 7 bytes of ID */
+#define NFCV1_READID_LEN	7
+/* Polling is done at a pace of POLL_PERIOD us until POLL_TIMEOUT is reached */
+#define POLL_PERIOD		0
+#define POLL_TIMEOUT		100000
+/* Interrupt maximum wait period in ms */
+#define IRQ_TIMEOUT		1000
+/* Latency in clock cycles between SoC pins and NFC logic */
+#define MIN_RD_DEL_CNT		3
+/* Maximum number of contiguous address cycles */
+#define MAX_ADDRESS_CYC_NFCV1	5
+#define MAX_ADDRESS_CYC_NFCV2	7
+/* System control registers/bits to enable the NAND controller on some SoCs */
+#define GENCONF_SOC_DEVICE_MUX	0x208
+#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
+#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
+#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
+#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
+#define GENCONF_CLK_GATING_CTRL	0x220
+#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
+#define GENCONF_ND_CLK_CTRL	0x700
+#define GENCONF_ND_CLK_CTRL_EN	BIT(0)
+
+/* NAND controller data flash control register */
+#define NDCR			0x00
+/* NAND interface timing parameter 0 register */
+#define NDTR0			0x04
+/* NAND interface timing parameter 1 register */
+#define NDTR1			0x0C
+/* NAND controller status register */
+#define NDSR			0x14
+/* NAND ECC control register */
+#define NDECCCTRL		0x28
+/* NAND controller data buffer register */
+#define NDDB			0x40
+/* NAND controller command buffer 0 register */
+#define NDCB0			0x48
+/* NAND controller command buffer 1 register */
+#define NDCB1			0x4C
+/* NAND controller command buffer 2 register */
+#define NDCB2			0x50
+/* NAND controller command buffer 3 register */
+#define NDCB3			0x54
+
+/* Data flash control register bitfields */
+#define NDCR_ALL_INT		GENMASK(11, 0)
+#define NDCR_CS1_CMDDM		BIT(7)
+#define NDCR_CS0_CMDDM		BIT(8)
+#define NDCR_RDYM		BIT(11)
+#define NDCR_ND_ARB_EN		BIT(12)
+#define NDCR_RA_START		BIT(15)
+#define NDCR_RD_ID_CNT(x)	(min_t(unsigned int, x, 0x7) << 16)
+#define NDCR_PAGE_SZ(x)		(x >= 2048 ? BIT(24) : 0)
+#define NDCR_DWIDTH_M		BIT(26)
+#define NDCR_DWIDTH_C		BIT(27)
+#define NDCR_ND_RUN		BIT(28)
+#define NDCR_DMA_EN		BIT(29)
+#define NDCR_ECC_EN		BIT(30)
+#define NDCR_SPARE_EN		BIT(31)
+
+/* NAND interface timing parameter registers bitfields */
+#define NDTR0_TRP(x)		((min_t(unsigned int, x, 0xF) & 0x7) << 0)
+#define NDTR0_TRH(x)		(min_t(unsigned int, x, 0x7) << 3)
+#define NDTR0_ETRP(x)		((min_t(unsigned int, x, 0xF) & 0x8) << 3)
+#define NDTR0_SEL_NRE_EDGE	BIT(7)
+#define NDTR0_TWP(x)		(min_t(unsigned int, x, 0x7) << 8)
+#define NDTR0_TWH(x)		(min_t(unsigned int, x, 0x7) << 11)
+#define NDTR0_TCS(x)		(min_t(unsigned int, x, 0x7) << 16)
+#define NDTR0_TCH(x)		(min_t(unsigned int, x, 0x7) << 19)
+#define NDTR0_RD_CNT_DEL(x)	(min_t(unsigned int, x, 0xF) << 22)
+#define NDTR0_SELCNTR		BIT(26)
+#define NDTR0_TADL(x)		(min_t(unsigned int, x, 0x1F) << 27)
+
+#define NDTR1_TAR(x)		(min_t(unsigned int, x, 0xF) << 0)
+#define NDTR1_TWHR(x)		(min_t(unsigned int, x, 0xF) << 4)
+#define NDTR1_TRHW(x)		(min_t(unsigned int, x / 16, 0x3) << 8)
+#define NDTR1_PRESCALE		BIT(14)
+#define NDTR1_WAIT_MODE		BIT(15)
+#define NDTR1_TR(x)		(min_t(unsigned int, x, 0xFFFF) << 16)
+
+/* NAND controller status register bitfields */
+#define NDSR_WRCMDREQ		BIT(0)
+#define NDSR_RDDREQ		BIT(1)
+#define NDSR_WRDREQ		BIT(2)
+#define NDSR_CORERR		BIT(3)
+#define NDSR_UNCERR		BIT(4)
+#define NDSR_CMDD(cs)		BIT(8 - cs)
+#define NDSR_RDY(rb)		BIT(11 + rb)
+#define NDSR_ERRCNT(x)		((x >> 16) & 0x1F)
+
+/* NAND ECC control register bitfields */
+#define NDECCTRL_BCH_EN		BIT(0)
+
+/* NAND controller command buffer registers bitfields */
+#define NDCB0_CMD1(x)		((x & 0xFF) << 0)
+#define NDCB0_CMD2(x)		((x & 0xFF) << 8)
+#define NDCB0_ADDR_CYC(x)	((x & 0x7) << 16)
+#define NDCB0_DBC		BIT(19)
+#define NDCB0_CMD_TYPE(x)	((x & 0x7) << 21)
+#define NDCB0_CSEL		BIT(24)
+#define NDCB0_RDY_BYP		BIT(27)
+#define NDCB0_LEN_OVRD		BIT(28)
+#define NDCB0_CMD_XTYPE(x)	((x & 0x7) << 29)
+
+#define NDCB1_COLS(x)		((x & 0xFFFF) << 0)
+#define NDCB1_ADDRS(x)		(x << 16)
+
+#define NDCB2_ADDR5(x)		(((x >> 16) & 0xFF) << 0)
+
+#define NDCB3_ADDR6(x)		((x & 0xFF) << 16)
+#define NDCB3_ADDR7(x)		((x & 0xFF) << 24)
+
+/* NAND controller command buffer 0 register 'type' and 'xtype' fields */
+#define TYPE_READ		0
+#define TYPE_WRITE		1
+#define TYPE_ERASE		2
+#define TYPE_READ_ID		3
+#define TYPE_STATUS		4
+#define TYPE_RESET		5
+#define TYPE_NAKED_CMD		6
+#define TYPE_NAKED_ADDR		7
+#define TYPE_MASK		7
+#define XTYPE_MONOLITHIC_RW	0
+#define XTYPE_LAST_NAKED_RW	1
+#define XTYPE_FINAL_COMMAND	3
+#define XTYPE_READ		4
+#define XTYPE_WRITE_DISPATCH	4
+#define XTYPE_NAKED_RW		5
+#define XTYPE_COMMAND_DISPATCH	6
+#define XTYPE_MASK		7
+
+/*
+ * Marvell ECC engine works differently than the others, in order to limit the
+ * size of the IP, hardware engineers choose to set a fixed strength at 16 bits
+ * per subpage, and depending on a the desired strength needed by the NAND chip,
+ * a particular layout mixing data/spare/ecc is defined, with a possible last
+ * chunk smaller that the others.
+ *
+ * @writesize:		Full page size on which the layout applies
+ * @chunk:		Desired ECC chunk size on which the layout applies
+ * @strength:		Desired ECC strength (per chunk size bytes) on which the
+ *			layout applies
+ * @full_chunk_cnt:	Number of full-sized chunks, which is the number of
+ *			repetitions of the pattern:
+ *			(data_bytes + spare_bytes + ecc_bytes).
+ * @data_bytes:		Number of data bytes per chunk
+ * @spare_bytes:	Number of spare bytes per chunk
+ * @ecc_bytes:		Number of ecc bytes per chunk
+ * @last_chunk_cnt:	If there is a last chunk with a different size than
+ *			the first ones, the next fields may not be empty
+ * @last_data_bytes:	Number of data bytes in the last chunk
+ * @last_spare_bytes:	Number of spare bytes in the last chunk
+ * @last_ecc_bytes:	Number of ecc bytes in the last chunk
+ */
+struct marvell_hw_ecc_layout {
+	/* Constraints */
+	int writesize;
+	int chunk;
+	int strength;
+	/* Corresponding layout */
+	int full_chunk_cnt;
+	int data_bytes;
+	int spare_bytes;
+	int ecc_bytes;
+	int last_chunk_cnt;
+	int last_data_bytes;
+	int last_spare_bytes;
+	int last_ecc_bytes;
+};
+
+#define MARVELL_LAYOUT(ws, dc, ds, fcc, db, sb, eb, lcc, ldb, lsb, leb) \
+	{								\
+		.writesize = ws,					\
+		.chunk = dc,						\
+		.strength = ds,						\
+		.full_chunk_cnt = fcc,					\
+		.data_bytes = db,					\
+		.spare_bytes = sb,					\
+		.ecc_bytes = eb,					\
+		.last_chunk_cnt = lcc,					\
+		.last_data_bytes = ldb,					\
+		.last_spare_bytes = lsb,				\
+		.last_ecc_bytes = leb,					\
+	}
+
+/* Layouts explained in AN-379_Marvell_SoC_NFC_ECC */
+static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
+	MARVELL_LAYOUT(  512,   512,  1,  1,  512,  8,  8,  0,  0,  0,  0),
+	MARVELL_LAYOUT( 2048,   512,  1,  1, 2048, 40, 24,  0,  0,  0,  0),
+	MARVELL_LAYOUT( 2048,   512,  4,  1, 2048, 32, 30,  0,  0,  0,  0),
+	MARVELL_LAYOUT( 4096,   512,  4,  2, 2048, 32, 30,  0,  0,  0,  0),
+	MARVELL_LAYOUT( 4096,   512,  8,  4, 1024,  0, 30,  1,  0, 64, 30),
+};
+
+/*
+ * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
+ * is made by a field in NDCB0 register, and in another field in NDCB2 register.
+ * The datasheet describes the logic with an error: ADDR5 field is once
+ * declared at the beginning of NDCB2, and another time at its end. Because the
+ * ADDR5 field of NDCB2 may be used by other bytes, it would be more logical
+ * to use the last bit of this field instead of the first ones.
+ *
+ * @cs:			Wanted CE lane.
+ * @ndcb0_csel:		Value of the NDCB0 register with or without the flag
+ *			selecting the wanted CE lane. This is set once when
+ *			the Device Tree is probed.
+ * @rb:			Ready/Busy pin for the flash chip
+ */
+struct marvell_nand_chip_sel {
+	unsigned int cs;
+	u32 ndcb0_csel;
+	unsigned int rb;
+};
+
+/*
+ * NAND chip structure: stores NAND chip device related information
+ *
+ * @chip:		Base NAND chip structure
+ * @node:		Used to store NAND chips into a list
+ * @layout		NAND layout when using hardware ECC
+ * @ndtr0		Timing registers 0 value for this NAND chip
+ * @ndtr1		Timing registers 1 value for this NAND chip
+ * @selected_die:	Current active CS
+ * @nsels:		Number of CS lines required by the NAND chip
+ * @sels:		Array of CS lines descriptions
+ */
+struct marvell_nand_chip {
+	struct nand_chip chip;
+	struct list_head node;
+	const struct marvell_hw_ecc_layout *layout;
+	u32 ndtr0;
+	u32 ndtr1;
+	int addr_cyc;
+	int selected_die;
+	unsigned int nsels;
+	struct marvell_nand_chip_sel sels[0];
+};
+
+static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip)
+{
+	return container_of(chip, struct marvell_nand_chip, chip);
+}
+
+static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
+							*nand)
+{
+	return &nand->sels[nand->selected_die];
+}
+
+/*
+ * NAND controller capabilities for distinction between compatible strings
+ *
+ * @max_cs_nb:		Number of Chip Select lines available
+ * @max_rb_nb:		Number of Ready/Busy lines available
+ * @need_system_controller: Indicates if the SoC needs to have access to the
+ *                      system controller (ie. to enable the NAND controller)
+ * @legacy_of_bindings:	Indicates if DT parsing must be done using the old
+ *			fashion way
+ * @is_nfcv2:		NFCv2 has numerous enhancements compared to NFCv1, ie.
+ *			BCH error detection and correction algorithm,
+ *			NDCB3 register has been added
+ * @use_dma:		Use dma for data transfers
+ */
+struct marvell_nfc_caps {
+	unsigned int max_cs_nb;
+	unsigned int max_rb_nb;
+	bool need_system_controller;
+	bool legacy_of_bindings;
+	bool is_nfcv2;
+	bool use_dma;
+};
+
+/*
+ * NAND controller structure: stores Marvell NAND controller information
+ *
+ * @controller:		Base controller structure
+ * @dev:		Parent device (used to print error messages)
+ * @regs:		NAND controller registers
+ * @ecc_clk:		ECC block clock, two times the NAND controller clock
+ * @complete:		Completion object to wait for NAND controller events
+ * @assigned_cs:	Bitmask describing already assigned CS lines
+ * @chips:		List containing all the NAND chips attached to
+ *			this NAND controller
+ * @caps:		NAND controller capabilities for each compatible string
+ * @buf:		Controller local buffer to store a part of the read
+ *			buffer when the read operation was not 8 bytes aligned
+ *			as is the FIFO.
+ * @buf_pos:		Position in the 'buf' buffer
+ * @dma_chan:		DMA channel (NFCv1 only)
+ * @dma_buf:		32-bit aligned buffer for DMA transfers (NFCv1 only)
+ */
+struct marvell_nfc {
+	struct nand_hw_control controller;
+	struct device *dev;
+	void __iomem *regs;
+	struct clk *ecc_clk;
+	struct completion complete;
+	unsigned long assigned_cs;
+	struct list_head chips;
+	struct nand_chip *selected_chip;
+	const struct marvell_nfc_caps *caps;
+
+	/*
+	 * Buffer handling: @buf will be accessed byte-per-byter but also
+	 * int-per-int when exchanging data with the NAND controller FIFO,
+	 * 32-bit alignment is then required.
+	 */
+	u8 buf[FIFO_DEPTH] __aligned(sizeof(u32));
+	int buf_pos;
+
+	/* DMA (NFCv1 only) */
+	bool use_dma;
+	struct dma_chan *dma_chan;
+	u8 *dma_buf;
+};
+
+static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
+{
+	return container_of(ctrl, struct marvell_nfc, controller);
+}
+
+/*
+ * NAND controller timings expressed in NAND Controller clock cycles
+ *
+ * @tRP:		ND_nRE pulse width
+ * @tRH:		ND_nRE high duration
+ * @tWP:		ND_nWE pulse time
+ * @tWH:		ND_nWE high duration
+ * @tCS:		Enable signal setup time
+ * @tCH:		Enable signal hold time
+ * @tADL:		Address to write data delay
+ * @tAR:		ND_ALE low to ND_nRE low delay
+ * @tWHR:		ND_nWE high to ND_nRE low for status read
+ * @tRHW:		ND_nRE high duration, read to write delay
+ * @tR:			ND_nWE high to ND_nRE low for read
+ */
+struct marvell_nfc_timings {
+	/* NDTR0 fields */
+	unsigned int tRP;
+	unsigned int tRH;
+	unsigned int tWP;
+	unsigned int tWH;
+	unsigned int tCS;
+	unsigned int tCH;
+	unsigned int tADL;
+	/* NDTR1 fields */
+	unsigned int tAR;
+	unsigned int tWHR;
+	unsigned int tRHW;
+	unsigned int tR;
+};
+
+/*
+ * Derives a duration in numbers of clock cycles.
+ *
+ * @ps: Duration in pico-seconds
+ * @period_ns:  Clock period in nano-seconds
+ *
+ * Convert the duration in nano-seconds, then divide by the period and
+ * return the number of clock periods.
+ */
+#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns))
+
+/*
+ * NAND driver structure filled during the parsing of the ->exec_op() subop
+ * subset of instructions.
+ *
+ * @ndcb:		Array for the values of the NDCBx registers
+ * @cle_ale_delay_ns:	Optional delay after the last CMD or ADDR cycle
+ * @rdy_timeout_ms:	Timeout for waits on Ready/Busy pin
+ * @rdy_delay_ns:	Optional delay after waiting for the RB pin
+ * @data_delay_ns:	Optional delay after the data xfer
+ * @data_instr_idx:	Index of the data instruction in the subop
+ * @data_instr:		Pointer to the data instruction in the subop
+ */
+struct marvell_nfc_op {
+	u32 ndcb[4];
+	unsigned int cle_ale_delay_ns;
+	unsigned int rdy_timeout_ms;
+	unsigned int rdy_delay_ns;
+	unsigned int data_delay_ns;
+	unsigned int data_instr_idx;
+	const struct nand_op_instr *data_instr;
+};
+
+/*
+ * Internal helper to conditionnally apply a delay (from the above structure,
+ * most of the time).
+ */
+static void cond_delay(unsigned int ns)
+{
+	if (!ns)
+		return;
+
+	if (ns < 10000)
+		ndelay(ns);
+	else
+		udelay(DIV_ROUND_UP(ns, 1000));
+}
+
+/*
+ * Internal helper to mimic core functions whithout having to distinguish if
+ * this is the first read operation on the page or not and hence choose the
+ * right function.
+ */
+int read_page_data(struct nand_chip *chip, unsigned int page,
+		   unsigned int column, void *buf, unsigned int len)
+{
+	if (!column)
+		return nand_read_page_op(chip, page, column, buf, len);
+	else
+		return nand_change_read_column_op(chip, column, buf, len,
+						  false);
+}
+
+/*
+ * The controller has many flags that could generate interrupts, most of them
+ * are disabled and polling is used. For the very slow signals, using interrupts
+ * may relax the CPU charge.
+ */
+static void marvell_nfc_disable_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	u32 reg;
+
+	/* Writing 1 disables the interrupt */
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg | int_mask, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	u32 reg;
+
+	/* Writing 0 enables the interrupt */
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg & ~int_mask, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	writel_relaxed(int_mask, nfc->regs + NDSR);
+}
+
+/*
+ * The core may ask the controller to use only 8-bit accesses while usually
+ * using 16-bit accesses. Later function may blindly call this one with a
+ * boolean to indicate if 8-bit accesses must be enabled of disabled without
+ * knowing if 16-bit accesses are actually in use.
+ */
+static void marvell_nfc_force_byte_access(struct nand_chip *chip,
+					  bool force_8bit)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr;
+
+	if (!(chip->options & NAND_BUSWIDTH_16))
+		return;
+
+	ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (force_8bit)
+		ndcr &= ~(NDCR_DWIDTH_M | NDCR_DWIDTH_C);
+	else
+		ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+	writel_relaxed(ndcr, nfc->regs + NDCR);
+}
+
+static int marvell_nfc_wait_ndrun(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 val;
+	int ret;
+
+	/*
+	 * The command is being processed, wait for the ND_RUN bit to be
+	 * cleared by the NFC. If not, we must clear it by hand.
+	 */
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDCR, val,
+					 (val & NDCR_ND_RUN) == 0,
+					 POLL_PERIOD, POLL_TIMEOUT);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on NAND controller run mode\n");
+		writel_relaxed(readl_relaxed(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Any time a command has to be sent to the controller, the following sequence
+ * has to be followed:
+ * - call marvell_nfc_prepare_cmd()
+ *      -> activate the ND_RUN bit that will kind of 'start a job'
+ *      -> wait the signal indicating the NFC is waiting for a command
+ * - send the command (cmd and address cycles)
+ * - enventually send or receive the data
+ * - call marvell_nfc_end_cmd() with the corresponding flag
+ *      -> wait the flag to be triggered or cancel the job with a timeout
+ *
+ * The following functions are helpers to do this job and keep in the
+ * specialized functions the code that really does the operations.
+ */
+static int marvell_nfc_prepare_cmd(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr, val;
+	int ret;
+
+	/* Poll ND_RUN and clear NDSR before issuing any command */
+	ret = marvell_nfc_wait_ndrun(chip);
+	if (ret) {
+		dev_err(nfc->dev, "Last operation did not suceed\n");
+		return ret;
+	}
+
+	ndcr = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(readl_relaxed(nfc->regs + NDSR), nfc->regs + NDSR);
+
+	/* Assert ND_RUN bit and wait the NFC to be ready */
+	writel_relaxed(ndcr | NDCR_ND_RUN, nfc->regs + NDCR);
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
+					 val & NDSR_WRCMDREQ,
+					 POLL_PERIOD, POLL_TIMEOUT);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on WRCMDRE\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Command may be written, clear WRCMDREQ status bit */
+	writel_relaxed(NDSR_WRCMDREQ, nfc->regs + NDSR);
+
+	return 0;
+}
+
+static void marvell_nfc_send_cmd(struct nand_chip *chip,
+				 struct marvell_nfc_op *nfc_op)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+	dev_dbg(nfc->dev,
+		"NDCB0: 0x%08x\nNDCB1: 0x%08x\nNDCB2: 0x%08x\nNDCB3: 0x%08x\n",
+		nfc_op->ndcb[0], nfc_op->ndcb[1], nfc_op->ndcb[2],
+		nfc_op->ndcb[3]);
+
+	writel_relaxed(to_nand_sel(marvell_nand)->ndcb0_csel | nfc_op->ndcb[0],
+		       nfc->regs + NDCB0);
+	writel_relaxed(nfc_op->ndcb[1], nfc->regs + NDCB0);
+	writel(nfc_op->ndcb[2], nfc->regs + NDCB0);
+
+	/*
+	 * Write NDCB0 four times only if LEN_OVRD is set or if ADDR6 or ADDR7
+	 * fields are used (only available on NFCv2).
+	 */
+	if (nfc_op->ndcb[0] & NDCB0_LEN_OVRD ||
+	    (nfc_op->ndcb[0] & NDCB0_ADDR_CYC(6)) == NDCB0_ADDR_CYC(6)) {
+		if (nfc->caps->is_nfcv2)
+			writel(nfc_op->ndcb[3], nfc->regs + NDCB0);
+		else
+			dev_err(nfc->dev,
+				"NDCB3 does not exist on NFCv1 and should not be written\n");
+	}
+}
+
+static int marvell_nfc_end_cmd(struct nand_chip *chip, int flag,
+			       const char *label)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 val;
+	int ret;
+
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
+					 val & flag,
+					 POLL_PERIOD, POLL_TIMEOUT);
+
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on %s (NDSR: 0x%08x)\n",
+			label, val);
+		if (nfc->dma_chan)
+			dmaengine_terminate_all(nfc->dma_chan);
+		return ret;
+	}
+
+	/*
+	 * DMA function uses this helper to poll on CMDD bits without wanting
+	 * them to be bleared.
+	 */
+	if (nfc->use_dma && (readl(nfc->regs + NDCR) & NDCR_DMA_EN))
+		return 0;
+
+	writel_relaxed(flag, nfc->regs + NDSR);
+
+	return 0;
+}
+
+static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	int cs_flag = NDSR_CMDD(to_nand_sel(marvell_nand)->ndcb0_csel);
+
+	return marvell_nfc_end_cmd(chip, cs_flag, "CMDD");
+}
+
+static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int ret;
+
+	/* Timeout is expressed in ms */
+	if (!timeout_ms)
+		timeout_ms = IRQ_TIMEOUT;
+
+	init_completion(&nfc->complete);
+
+	marvell_nfc_enable_int(nfc, NDCR_RDYM);
+	ret = wait_for_completion_timeout(&nfc->complete,
+					  msecs_to_jiffies(timeout_ms));
+	marvell_nfc_disable_int(nfc, NDCR_RDYM);
+	marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
+	if (!ret) {
+		dev_err(nfc->dev, "Timeout waiting for RB signal\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_select_chip(struct mtd_info *mtd, 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;
+
+	if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die)
+		return;
+
+	if (die_nr < 0 || die_nr >= marvell_nand->nsels) {
+		nfc->selected_chip = NULL;
+		marvell_nand->selected_die = -1;
+		return;
+	}
+
+	/*
+	 * Do not change the timing registers when using the DT property
+	 * marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
+	 * marvell_nand structure are supposedly empty.
+	 */
+	if (marvell_nand->ndtr0 && marvell_nand->ndtr1) {
+		writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
+		writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
+	}
+
+	ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	/* Ensure controller is not blocked; also clear some fields */
+	ndcr &= ~(NDCR_ND_RUN | NDCR_DWIDTH_M | NDCR_DWIDTH_C |
+		  NDCR_PAGE_SZ(2048));
+
+	/* Adapt bus width */
+	if (chip->options & NAND_BUSWIDTH_16)
+		ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+	/* Page size as seen by the controller, either 512B or 2kiB */
+	ndcr |= NDCR_PAGE_SZ(mtd->writesize);
+
+	/* Update the control register */
+	writel_relaxed(ndcr,  nfc->regs + NDCR);
+
+	/* Also reset the interrupt status register */
+	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
+
+	nfc->selected_chip = chip;
+	marvell_nand->selected_die = die_nr;
+}
+
+static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
+{
+	struct marvell_nfc *nfc = dev_id;
+	u32 st = readl_relaxed(nfc->regs + NDSR);
+	u32 ien = (~readl_relaxed(nfc->regs + NDCR)) & NDCR_ALL_INT;
+
+	/*
+	 * RDY interrupt mask is one bit in NDCR while there are two status
+	 * bit in NDSR (RDY[cs0/cs2] and RDY[cs1/cs3]).
+	 */
+	if (st & NDSR_RDY(1))
+		st |= NDSR_RDY(0);
+
+	if (!(st & ien))
+		return IRQ_NONE;
+
+	marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
+
+	if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+		complete(&nfc->complete);
+
+	return IRQ_HANDLED;
+}
+
+/* HW ECC related functions */
+static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (!(ndcr & NDCR_ECC_EN)) {
+		writel(ndcr | NDCR_ECC_EN, nfc->regs + NDCR);
+
+		/*
+		 * When enabling BCH, set threshold to 0 to always know the
+		 * number of corrected bitflips.
+		 */
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			writel(NDECCTRL_BCH_EN, nfc->regs + NDECCCTRL);
+	}
+}
+
+static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (ndcr & NDCR_ECC_EN) {
+		writel_relaxed(ndcr & ~NDCR_ECC_EN, nfc->regs + NDCR);
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			writel_relaxed(0, nfc->regs + NDECCCTRL);
+	}
+}
+
+/*
+ * Enable/disable spare area
+ *
+ * NFCv1 needs it (see Hamming related functions). NFCv2 uses LEN_OVRD and thus
+ * does not need this bit to be set.
+ */
+static void marvell_nfc_enable_spare(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (!(ndcr & NDCR_SPARE_EN))
+		writel(ndcr | NDCR_SPARE_EN, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_disable_spare(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (ndcr & NDCR_SPARE_EN)
+		writel_relaxed(ndcr & ~NDCR_SPARE_EN, nfc->regs + NDCR);
+}
+
+/* DMA related helpers */
+static void marvell_nfc_enable_dma(struct marvell_nfc *nfc)
+{
+	u32 reg;
+
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg | NDCR_DMA_EN, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_disable_dma(struct marvell_nfc *nfc)
+{
+	u32 reg;
+
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg & ~NDCR_DMA_EN, nfc->regs + NDCR);
+}
+
+/* Read/write PIO/DMA accessors */
+static int marvell_nfc_xfer_data_dma(struct marvell_nfc *nfc,
+				     enum dma_data_direction direction,
+				     unsigned int len)
+{
+	unsigned int dma_len = min_t(int, ALIGN(len, 32), MAX_CHUNK_SIZE);
+	struct dma_async_tx_descriptor *tx;
+	struct scatterlist sg;
+	dma_cookie_t cookie;
+	int ret;
+
+	marvell_nfc_enable_dma(nfc);
+	/* Prepare the DMA transfer */
+	sg_init_one(&sg, nfc->dma_buf, dma_len);
+	dma_map_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
+	tx = dmaengine_prep_slave_sg(nfc->dma_chan, &sg, 1,
+				     direction == DMA_FROM_DEVICE ?
+				     DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+				     DMA_PREP_INTERRUPT);
+	if (!tx) {
+		dev_err(nfc->dev, "Could not prepare DMA S/G list\n");
+		return -ENXIO;
+	}
+
+	/* Do the task and wait for it to finish */
+	cookie = dmaengine_submit(tx);
+	ret = dma_submit_error(cookie);
+	if (ret)
+		return -EIO;
+
+	dma_async_issue_pending(nfc->dma_chan);
+	ret = marvell_nfc_wait_cmdd(nfc->selected_chip);
+	dma_unmap_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
+	marvell_nfc_disable_dma(nfc);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout waiting for DMA (status: %d)\n",
+			dmaengine_tx_status(nfc->dma_chan, cookie, NULL));
+		dmaengine_terminate_all(nfc->dma_chan);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_xfer_data_in_pio(struct marvell_nfc *nfc, u8 *in,
+					unsigned int len)
+{
+	unsigned int last_len = len % FIFO_DEPTH;
+	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
+	int i;
+
+	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
+		ioread32_rep(nfc->regs + NDDB, in + i, FIFO_REP(FIFO_DEPTH));
+
+	if (last_len) {
+		ioread32_rep(nfc->regs + NDDB, nfc->buf, FIFO_REP(FIFO_DEPTH));
+		memcpy(in + last_full_offset, nfc->buf, last_len);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_xfer_data_out_pio(struct marvell_nfc *nfc, const u8 *out,
+					 unsigned int len)
+{
+	unsigned int last_len = len % FIFO_DEPTH;
+	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
+	int i;
+
+	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
+		iowrite32_rep(nfc->regs + NDDB, out + i, FIFO_REP(FIFO_DEPTH));
+
+	if (last_len) {
+		memcpy(nfc->buf, out + last_full_offset, last_len);
+		iowrite32_rep(nfc->regs + NDDB, nfc->buf, FIFO_REP(FIFO_DEPTH));
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_hw_ecc_correct(struct nand_chip *chip,
+				       u8 *data, int data_len,
+				       u8 *oob, int oob_len,
+				       unsigned int *max_bitflips)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int bf = 0;
+	u32 ndsr;
+
+	ndsr = readl_relaxed(nfc->regs + NDSR);
+
+	/* Check uncorrectable error flag */
+	if (ndsr & NDSR_UNCERR) {
+		writel_relaxed(ndsr, nfc->regs + NDSR);
+
+		/*
+		 * Blank pages (all 0xFF) with no ECC are recognized as bad
+		 * because hardware ECC engine expects non-empty ECC values
+		 * in that case, so whenever an uncorrectable error occurs,
+		 * check if the page is actually blank or not.
+		 *
+		 * It is important to check the emptyness only on oob_len,
+		 * which only covers the spare bytes because after a read with
+		 * ECC enabled, the ECC bytes in the buffer have been set by the
+		 * ECC engine, so they are not 0xFF.
+		 */
+		if (!data)
+			data_len = 0;
+		if (!oob)
+			oob_len = 0;
+		bf = nand_check_erased_ecc_chunk(data, data_len, NULL, 0,
+						 oob, oob_len,
+						 chip->ecc.strength);
+		if (bf < 0) {
+			mtd->ecc_stats.failed++;
+			return;
+		}
+	}
+
+	/* Check correctable error flag */
+	if (ndsr & NDSR_CORERR) {
+		writel_relaxed(ndsr, nfc->regs + NDSR);
+
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			bf = NDSR_ERRCNT(ndsr);
+		else
+			bf = 1;
+	}
+
+	/*
+	 * Derive max_bitflips either from the number of bitflips detected by
+	 * the hardware ECC engine or by nand_check_erased_ecc_chunk().
+	 */
+	mtd->ecc_stats.corrected += bf;
+	*max_bitflips = max_t(unsigned int, *max_bitflips, bf);
+}
+
+/* Hamming read helpers */
+static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip, u8 *buf,
+					       bool oob_required, bool raw,
+					       int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_DBC |
+			   NDCB0_CMD1(NAND_CMD_READ0) |
+			   NDCB0_CMD2(NAND_CMD_READSTART),
+		.ndcb[1] = NDCB1_ADDRS(page),
+		.ndcb[2] = NDCB2_ADDR5(page),
+	};
+	unsigned int oob_bytes = 0;
+	int ret;
+
+	/* NFCv2 needs more information about the operation being executed */
+	if (nfc->caps->is_nfcv2)
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	if (oob_required) {
+		marvell_nfc_enable_spare(chip);
+		oob_bytes = lt->spare_bytes;
+		if (raw)
+			oob_bytes += lt->ecc_bytes;
+	}
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while draining FIFO (data/oob)");
+	if (ret)
+		return ret;
+
+	/* Read the page then the OOB area */
+	if (nfc->use_dma) {
+		marvell_nfc_xfer_data_dma(nfc, DMA_FROM_DEVICE,
+					  lt->data_bytes + oob_bytes);
+		memcpy(buf, nfc->dma_buf, lt->data_bytes);
+		memcpy(chip->oob_poi + (raw ? 0 : lt->ecc_bytes),
+		       nfc->dma_buf + lt->data_bytes, oob_bytes);
+	} else {
+		marvell_nfc_xfer_data_in_pio(nfc, buf, lt->data_bytes);
+		marvell_nfc_xfer_data_in_pio(nfc, chip->oob_poi, oob_bytes);
+	}
+
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	if (oob_required)
+		marvell_nfc_disable_spare(chip);
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
+						struct nand_chip *chip, u8 *buf,
+						int oob_required, int page)
+{
+	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, oob_required,
+						   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)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int max_bf = 0;
+
+	/*
+	 * Reading/Writing a given page must always be performed with the same
+	 * configuration regarding the state of the SPARE_EN bit or ECC bytes
+	 * will not be present at the same location (writing only data, without
+	 * SPARE_EN will put the ECC bytes at the beginning of the OOB area,
+	 * while writing with the SPARE_EN bit (hence, also writing free OOB
+	 * bytes) will put first the spare bytes then, at the end of the OOB
+	 * area, the ECC bytes. Choices has been made to always read/write OOB
+	 * area (padding with 0xFF is handled by the core for writes).
+	 */
+
+	marvell_nfc_enable_hw_ecc(chip);
+	marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, true, false, page);
+	marvell_nfc_hw_ecc_correct(chip, buf, lt->data_bytes, NULL, 0, &max_bf);
+	marvell_nfc_disable_hw_ecc(chip);
+
+	/*
+	 * Re-read the OOB area in raw mode to get the ECC bytes if the OOB area
+	 * is needed.
+	 */
+	if (oob_required)
+		chip->ecc.read_oob_raw(mtd, chip, page);
+
+	return max_bf;
+}
+
+/*
+ * Spare area in Hamming layouts is not protected by the ECC engine (even if
+ * 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)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf, true,
+						   true, page);
+}
+
+/* Hamming write helpers */
+static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
+						const u8 *buf,
+						bool oob_required, bool raw,
+						int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_CMD1(NAND_CMD_SEQIN) |
+			   NDCB0_CMD2(NAND_CMD_PAGEPROG) |
+			   NDCB0_DBC,
+		.ndcb[1] = NDCB1_ADDRS(page),
+		.ndcb[2] = NDCB2_ADDR5(page),
+	};
+	int oob_bytes = 0;
+	int ret;
+
+	/* NFCv2 needs more information about the operation being executed */
+	if (nfc->caps->is_nfcv2)
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	if (oob_required) {
+		marvell_nfc_enable_spare(chip);
+		oob_bytes = lt->spare_bytes;
+		if (raw)
+			oob_bytes += lt->ecc_bytes;
+	}
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
+				  "WRDREQ while loading FIFO (data)");
+	if (ret)
+		return ret;
+
+	/* Write the page then the OOB area */
+	if (nfc->use_dma) {
+		memcpy(nfc->dma_buf, buf, lt->data_bytes);
+		if (oob_required)
+			memcpy(nfc->dma_buf + lt->data_bytes, chip->oob_poi,
+			       oob_bytes);
+		marvell_nfc_xfer_data_dma(nfc, DMA_TO_DEVICE, lt->data_bytes +
+					  lt->ecc_bytes + lt->spare_bytes);
+	} else {
+		marvell_nfc_xfer_data_out_pio(nfc, buf, lt->data_bytes);
+		if (oob_required)
+			marvell_nfc_xfer_data_out_pio(nfc, chip->oob_poi,
+						      oob_bytes);
+	}
+
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	ret = marvell_nfc_wait_op(chip,
+				  chip->data_interface.timings.sdr.tPROG_max);
+	if (ret)
+		return ret;
+
+	if (oob_required)
+		marvell_nfc_disable_spare(chip);
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
+						 struct nand_chip *chip,
+						 const u8 *buf,
+						 int oob_required, int page)
+{
+	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, oob_required,
+						    true, page);
+}
+
+static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     const u8 *buf,
+					     int oob_required, int page)
+{
+	int ret;
+
+	/*
+	 * Reading/Writing a given page must always be performed with the same
+	 * configuration regarding the state of the SPARE_EN bit or ECC bytes
+	 * will not be present at the same location (writing only data, without
+	 * SPARE_EN will put the ECC bytes at the beginning of the OOB area,
+	 * while writing with the SPARE_EN bit (hence, also writing free OOB
+	 * bytes) will put first the spare bytes then, at the end of the OOB
+	 * area, the ECC bytes. Choices has been made to always read/write OOB
+	 * area (padding with 0xFF is handled by the core for writes).
+	 */
+
+	marvell_nfc_enable_hw_ecc(chip);
+	ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, true, false,
+						   page);
+	marvell_nfc_disable_hw_ecc(chip);
+
+	return ret;
+}
+
+/*
+ * Spare area in Hamming layouts is not protected by the ECC engine (even if
+ * 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,
+						int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	memset(chip->data_buf, 0xFF, mtd->writesize);
+
+	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf, true,
+						    true, page);
+}
+
+/* BCH read helpers */
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
+						struct nand_chip *chip, u8 *buf,
+						int oob_required, int page)
+{
+	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;
+	int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
+		(lt->last_chunk_cnt * lt->last_spare_bytes);
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int ecc_len = lt->ecc_bytes;
+	int chunk;
+
+	if (oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	for (chunk = 0; chunk < nchunks; chunk++) {
+		int offset_in_page = chunk * chunk_size;
+
+		/* Update last chunk length */
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+			ecc_len = lt->last_ecc_bytes;
+		}
+
+		nand_change_read_column_op(chip, offset_in_page, buf,
+					   lt->data_bytes, false);
+		buf += lt->data_bytes;
+
+		if (!oob_required)
+			continue;
+
+		offset_in_page += data_len;
+		nand_change_read_column_op(chip, offset_in_page,
+					   oob + (lt->spare_bytes * chunk),
+					   spare_len, false);
+
+		offset_in_page += spare_len;
+		nand_change_read_column_op(chip, offset_in_page,
+					   oob + ecc_offset +
+					   (ALIGN(lt->ecc_bytes, 32) * chunk),
+					   ecc_len, false);
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
+					      u8 *data, unsigned int data_len,
+					      u8 *spare, unsigned int spare_len,
+					      int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	int i, ret;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_LEN_OVRD,
+		.ndcb[1] = NDCB1_ADDRS(page),
+		.ndcb[2] = NDCB2_ADDR5(page),
+	};
+
+	/*
+	 * Reading spare area is mandatory when using HW ECC or read operation
+	 * will trigger uncorrectable ECC errors, but do not read ECC here.
+	 */
+	nfc_op.ndcb[3] = data_len + spare_len;
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return;
+
+	if (chunk == 0)
+		nfc_op.ndcb[0] |= NDCB0_DBC |
+				  NDCB0_CMD1(NAND_CMD_READ0) |
+				  NDCB0_CMD2(NAND_CMD_READSTART);
+
+	/*
+	 * Trigger the naked read operation only on the last chunk.
+	 * Otherwise, use monolithic read.
+	 */
+	if (chunk < nchunks - 1)
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+	else
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+
+	/*
+	 * According to the datasheet, when reading from NDDB
+	 * with BCH enabled, after each 32 bytes reads, we
+	 * have to make sure that the NDSR.RDDREQ bit is set.
+	 *
+	 * Drain the FIFO, 8 32-bit reads at a time, and skip
+	 * the polling on the last read.
+	 *
+	 * Length is a multiple of 32 bytes, hence it is a multiple of 8 too.
+	 *
+	 */
+
+	for (i = 0; i < data_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
+		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				    "RDDREQ while draining FIFO (data)");
+		marvell_nfc_xfer_data_in_pio(nfc, data,
+					     FIFO_DEPTH * BCH_SEQ_READS);
+		data += FIFO_DEPTH * BCH_SEQ_READS;
+	}
+
+	for (i = 0; i < spare_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
+		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				    "RDDREQ while draining FIFO (OOB)");
+		marvell_nfc_xfer_data_in_pio(nfc, spare,
+					     FIFO_DEPTH * BCH_SEQ_READS);
+		spare += FIFO_DEPTH * BCH_SEQ_READS;
+	}
+}
+
+static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    u8 *buf, int oob_required,
+					    int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	u8 *data = buf;
+	u8 *spare = chip->oob_poi;
+	int max_bitflips = 0;
+	int chunk, ecc_offset_in_page, ecc_offset_in_oob_buf, ecc_len;
+
+	/*
+	 * With BCH, OOB is not fully used (and thus not read entirely), not
+	 * expected bytes could show up at the end of the OOB buffer if not
+	 * explicitly erased.
+	 */
+	if (oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	marvell_nfc_enable_hw_ecc(chip);
+
+	for (chunk = 0; chunk < nchunks; chunk++) {
+		/* Update length for the last chunk */
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+		}
+
+		/* Read the chunk and detect number of bitflips */
+		marvell_nfc_hw_ecc_bch_read_chunk(chip, chunk, data, data_len,
+						  spare, spare_len, page);
+		marvell_nfc_hw_ecc_correct(chip, data, data_len,
+					   spare, spare_len, &max_bitflips);
+
+		data += data_len;
+		spare += spare_len;
+	}
+
+	marvell_nfc_disable_hw_ecc(chip);
+
+	if (!oob_required)
+		return max_bitflips;
+
+	/*
+	 * Re-read ECC bytes without ECC enabled, else it is garbage and it
+	 * fails the ->correct() call.
+	 */
+	ecc_len = lt->ecc_bytes;
+	ecc_offset_in_oob_buf =
+		(lt->full_chunk_cnt * lt->spare_bytes) +
+		(lt->last_chunk_cnt * lt->last_spare_bytes);
+	ecc_offset_in_page = lt->data_bytes + lt->spare_bytes;
+
+	for (chunk = 0; chunk < nchunks;) {
+		/* Do the actual raw read of the ECC bytes */
+		nand_change_read_column_op(chip, ecc_offset_in_page,
+					   chip->oob_poi + ecc_offset_in_oob_buf,
+					   ecc_len, false);
+
+		chunk++;
+
+		/* When using a "last chunk", the ECC size might vary */
+		if (chunk >= lt->full_chunk_cnt)
+			ecc_len = lt->last_ecc_bytes;
+
+		/* Increment the offsets where ECC will be read and written */
+		ecc_offset_in_oob_buf += ALIGN(lt->ecc_bytes, 32);
+		ecc_offset_in_page += lt->ecc_bytes;
+		if (chunk < lt->full_chunk_cnt)
+			ecc_offset_in_page += lt->data_bytes + lt->spare_bytes;
+		else
+			ecc_offset_in_page += lt->last_data_bytes +
+				lt->last_spare_bytes;
+	}
+
+	return max_bitflips;
+}
+
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
+					       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);
+}
+
+static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
+					   struct nand_chip *chip, int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	return chip->ecc.read_page(mtd, 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,
+						 const u8 *buf,
+						 int oob_required, int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	int full_chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int ecc_len = lt->ecc_bytes;
+	int oob_len = spare_len + ecc_len;
+	int spare_offset = 0;
+	int ecc_offset =
+		(lt->full_chunk_cnt * lt->spare_bytes) +
+		(lt->last_chunk_cnt * lt->last_spare_bytes);
+	int chunk;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	for (chunk = 0; chunk < nchunks; chunk++) {
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+			ecc_len = lt->last_ecc_bytes;
+			oob_len = spare_len + ecc_len;
+		}
+
+		/* Point to the column of the next chunk */
+		nand_change_write_column_op(chip, chunk * full_chunk_size,
+					    NULL, 0, false);
+
+		/* Write the data */
+		nand_write_data_op(chip, buf + (chunk * lt->data_bytes),
+				   data_len, false);
+
+		if (!oob_required)
+			continue;
+
+		/* Write the spare bytes */
+		if (spare_len)
+			nand_write_data_op(chip, chip->oob_poi + spare_offset,
+					   spare_len, false);
+
+		/* Write the ECC bytes */
+		if (ecc_len)
+			nand_write_data_op(chip, chip->oob_poi + ecc_offset,
+					   ecc_len, false);
+
+		spare_offset += spare_len;
+		ecc_offset += ALIGN(ecc_len, 32);
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int
+marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
+				   const u8 *data, unsigned int data_len,
+				   const u8 *spare, unsigned int spare_len,
+				   int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	int ret;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) | NDCB0_LEN_OVRD,
+		.ndcb[3] = data_len + spare_len,
+	};
+
+	/*
+	 * First operation dispatches the CMD_SEQIN command, issue the address
+	 * cycles and asks for the first chunk of data.
+	 * All operations in the middle (if any) will issue a naked write and
+	 * also ask for data.
+	 * Last operation dispatches the PAGEPROG command and also asks for the
+	 * last chunk of data.
+	 */
+	if (chunk == 0) {
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_WRITE_DISPATCH) |
+				  NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+				  NDCB0_CMD1(NAND_CMD_SEQIN);
+		nfc_op.ndcb[1] |= NDCB1_ADDRS(page);
+		nfc_op.ndcb[2] |= NDCB2_ADDR5(page);
+	} else if (chunk < nchunks - 1) {
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_NAKED_RW);
+	} else {
+		nfc_op.ndcb[0] |= NDCB0_CMD2(NAND_CMD_PAGEPROG) | NDCB0_DBC |
+				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+	}
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
+				  "WRDREQ while loading FIFO (data)");
+	if (ret)
+		return ret;
+
+	/* Transfer the contents */
+	iowrite32_rep(nfc->regs + NDDB, data, FIFO_REP(data_len));
+	iowrite32_rep(nfc->regs + NDDB, spare, FIFO_REP(spare_len));
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     const u8 *buf,
+					     int oob_required, int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
+	const u8 *data = buf;
+	const u8 *spare = chip->oob_poi;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int chunk, ret;
+
+	/* Spare data will be written anyway, so clear it to avoid garbage */
+	if (!oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	marvell_nfc_enable_hw_ecc(chip);
+
+	for (chunk = 0; chunk < nchunks; chunk++) {
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+		}
+
+		marvell_nfc_hw_ecc_bch_write_chunk(chip, chunk, data, data_len,
+						   spare, spare_len, page);
+		data += data_len;
+		spare += spare_len;
+
+		/*
+		 * Waiting only for CMDD or PAGED is not enough, ECC are
+		 * partially written. No flag is set once the operation is
+		 * really finished but the ND_RUN bit is cleared, so wait for it
+		 * before stepping into the next command.
+		 */
+		marvell_nfc_wait_ndrun(chip);
+	}
+
+	ret = marvell_nfc_wait_op(chip,
+				  chip->data_interface.timings.sdr.tPROG_max);
+
+	marvell_nfc_disable_hw_ecc(chip);
+
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						int page)
+{
+	/* 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);
+}
+
+static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
+					    struct nand_chip *chip, int page)
+{
+	/* 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);
+}
+
+/* NAND framework ->exec_op() hooks and related helpers */
+static void marvell_nfc_parse_instructions(struct nand_chip *chip,
+					   const struct nand_subop *subop,
+					   struct marvell_nfc_op *nfc_op)
+{
+	const struct nand_op_instr *instr = NULL;
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	bool first_cmd = true;
+	unsigned int op_id;
+	int i;
+
+	/* Reset the input structure as most of its fields will be OR'ed */
+	memset(nfc_op, 0, sizeof(struct marvell_nfc_op));
+
+	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);
+
+		instr = &subop->instrs[op_id];
+
+		switch (instr->type) {
+		case NAND_OP_CMD_INSTR:
+			if (first_cmd)
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD1(instr->ctx.cmd.opcode);
+			else
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD2(instr->ctx.cmd.opcode) |
+					NDCB0_DBC;
+
+			nfc_op->cle_ale_delay_ns = instr->delay_ns;
+			first_cmd = false;
+			break;
+
+		case NAND_OP_ADDR_INSTR:
+			offset = nand_subop_get_addr_start_off(subop, op_id);
+			naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
+			addrs = &instr->ctx.addr.addrs[offset];
+
+			nfc_op->ndcb[0] |= NDCB0_ADDR_CYC(naddrs);
+
+			for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
+				nfc_op->ndcb[1] |= addrs[i] << (8 * i);
+
+			if (naddrs >= 5)
+				nfc_op->ndcb[2] |= NDCB2_ADDR5(addrs[5]);
+			if (naddrs >= 6)
+				nfc_op->ndcb[3] |= NDCB3_ADDR6(addrs[6]);
+			if (naddrs == 7)
+				nfc_op->ndcb[3] |= NDCB3_ADDR7(addrs[7]);
+
+			nfc_op->cle_ale_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_DATA_IN_INSTR:
+			nfc_op->data_instr = instr;
+			nfc_op->data_instr_idx = op_id;
+			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ);
+			if (nfc->caps->is_nfcv2) {
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
+					NDCB0_LEN_OVRD;
+				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
+			}
+			nfc_op->data_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_DATA_OUT_INSTR:
+			nfc_op->data_instr = instr;
+			nfc_op->data_instr_idx = op_id;
+			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE);
+			if (nfc->caps->is_nfcv2) {
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
+					NDCB0_LEN_OVRD;
+				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
+			}
+			nfc_op->data_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_WAITRDY_INSTR:
+			nfc_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
+			nfc_op->rdy_delay_ns = instr->delay_ns;
+			break;
+		}
+	}
+}
+
+static int marvell_nfc_xfer_data_pio(struct nand_chip *chip,
+				     const struct nand_subop *subop,
+				     struct marvell_nfc_op *nfc_op)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct nand_op_instr *instr = nfc_op->data_instr;
+	unsigned int op_id = nfc_op->data_instr_idx;
+	unsigned int len = nand_subop_get_data_len(subop, op_id);
+	unsigned int offset = nand_subop_get_data_start_off(subop, op_id);
+	bool reading = (instr->type == NAND_OP_DATA_IN_INSTR);
+	int ret;
+
+	if (instr->ctx.data.force_8bit)
+		marvell_nfc_force_byte_access(chip, true);
+
+	if (reading) {
+		u8 *in = instr->ctx.data.buf.in + offset;
+
+		ret = marvell_nfc_xfer_data_in_pio(nfc, in, len);
+	} else {
+		const u8 *out = instr->ctx.data.buf.out + offset;
+
+		ret = marvell_nfc_xfer_data_out_pio(nfc, out, len);
+	}
+
+	if (instr->ctx.data.force_8bit)
+		marvell_nfc_force_byte_access(chip, false);
+
+	return ret;
+}
+
+static int marvell_nfc_monolithic_access_exec(struct nand_chip *chip,
+					      const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	bool reading;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	reading = (nfc_op.data_instr->type == NAND_OP_DATA_IN_INSTR);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
+				  "RDDREQ/WRDREQ while draining raw data");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (reading) {
+		if (nfc_op.rdy_timeout_ms) {
+			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+			if (ret)
+				return ret;
+		}
+
+		cond_delay(nfc_op.rdy_delay_ns);
+	}
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	if (!reading) {
+		if (nfc_op.rdy_timeout_ms) {
+			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+			if (ret)
+				return ret;
+		}
+
+		cond_delay(nfc_op.rdy_delay_ns);
+	}
+
+	/*
+	 * NDCR ND_RUN bit should be cleared automatically at the end of each
+	 * operation but experience shows that the behavior is buggy when it
+	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
+	 */
+	if (!reading) {
+		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_naked_access_exec(struct nand_chip *chip,
+					 const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+
+	/*
+	 * Naked access are different in that they need to be flagged as naked
+	 * by the controller. Reset the controller registers fields that inform
+	 * on the type and refill them according to the ongoing operation.
+	 */
+	nfc_op.ndcb[0] &= ~(NDCB0_CMD_TYPE(TYPE_MASK) |
+			    NDCB0_CMD_XTYPE(XTYPE_MASK));
+	switch (subop->instrs[0].type) {
+	case NAND_OP_CMD_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_CMD);
+		break;
+	case NAND_OP_ADDR_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_ADDR);
+		break;
+	case NAND_OP_DATA_IN_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ) |
+				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+		break;
+	case NAND_OP_DATA_OUT_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE) |
+				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+		break;
+	default:
+		/* This should never happen */
+		break;
+	}
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+
+	if (!nfc_op.data_instr) {
+		ret = marvell_nfc_wait_cmdd(chip);
+		cond_delay(nfc_op.cle_ale_delay_ns);
+		return ret;
+	}
+
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
+				  "RDDREQ/WRDREQ while draining raw data");
+	if (ret)
+		return ret;
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	/*
+	 * NDCR ND_RUN bit should be cleared automatically at the end of each
+	 * operation but experience shows that the behavior is buggy when it
+	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
+	 */
+	if (subop->instrs[0].type == NAND_OP_DATA_OUT_INSTR) {
+		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_naked_waitrdy_exec(struct nand_chip *chip,
+					  const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return ret;
+}
+
+static int marvell_nfc_read_id_type_exec(struct nand_chip *chip,
+					 const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ_ID);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while reading ID");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (nfc_op.rdy_timeout_ms) {
+		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+		if (ret)
+			return ret;
+	}
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_read_status_exec(struct nand_chip *chip,
+					const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_STATUS);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while reading status");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (nfc_op.rdy_timeout_ms) {
+		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+		if (ret)
+			return ret;
+	}
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_reset_cmd_type_exec(struct nand_chip *chip,
+					   const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_RESET);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_erase_cmd_type_exec(struct nand_chip *chip,
+					   const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_ERASE);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return 0;
+}
+
+static const struct nand_op_parser marvell_nfcv2_op_parser = NAND_OP_PARSER(
+	/* Monolithic reads/writes */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_monolithic_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC_NFCV2),
+		NAND_OP_PARSER_PAT_CMD_ELEM(true),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_monolithic_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2),
+		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE),
+		NAND_OP_PARSER_PAT_CMD_ELEM(true),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+	/* Naked commands */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_waitrdy_exec,
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	);
+
+static const struct nand_op_parser marvell_nfcv1_op_parser = NAND_OP_PARSER(
+	/* Naked commands not supported, use a function for each pattern */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_read_id_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_erase_cmd_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_read_status_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_reset_cmd_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_waitrdy_exec,
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	);
+
+static int marvell_nfc_exec_op(struct nand_chip *chip,
+			       const struct nand_operation *op,
+			       bool check_only)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+	if (nfc->caps->is_nfcv2)
+		return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser,
+					      op, check_only);
+	else
+		return nand_op_parser_exec_op(chip, &marvell_nfcv1_op_parser,
+					      op, check_only);
+}
+
+/*
+ * HW ECC layouts, identical to old pxa3xx_nand driver,
+ * to be fully backward compatible.
+ */
+static int marvell_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	oobregion->offset = ((lt->spare_bytes + lt->ecc_bytes) * section) +
+		lt->spare_bytes;
+	oobregion->length = lt->ecc_bytes;
+
+	return 0;
+}
+
+static int marvell_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int nchunks = lt->full_chunk_cnt;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	if (!lt->spare_bytes)
+		return 0;
+
+	oobregion->offset = section * (lt->spare_bytes + lt->ecc_bytes);
+	oobregion->length = lt->spare_bytes;
+	if (!section) {
+		/*
+		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
+		 * 4KB page / 4bit BCH combination.
+		 */
+		if (mtd->writesize == 4096 && lt->data_bytes == 2048) {
+			oobregion->offset += 6;
+			oobregion->length -= 6;
+		} else {
+			oobregion->offset += 2;
+			oobregion->length -= 2;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops marvell_nand_ooblayout_ops = {
+	.ecc = marvell_nand_ooblayout_ecc,
+	.free = marvell_nand_ooblayout_free,
+};
+
+static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
+					 struct nand_ecc_ctrl *ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *l;
+	int i;
+
+	if (!nfc->caps->is_nfcv2 &&
+	    (mtd->writesize + mtd->oobsize > MAX_CHUNK_SIZE)) {
+		dev_err(nfc->dev,
+			"NFCv1: writesize (%d) cannot be bigger than a chunk (%d)\n",
+			mtd->writesize, MAX_CHUNK_SIZE - mtd->oobsize);
+		return -ENOTSUPP;
+	}
+
+	to_marvell_nand(chip)->layout = NULL;
+	for (i = 0; i < ARRAY_SIZE(marvell_nfc_layouts); i++) {
+		l = &marvell_nfc_layouts[i];
+		if (mtd->writesize == l->writesize &&
+		    ecc->size == l->chunk && ecc->strength == l->strength) {
+			to_marvell_nand(chip)->layout = l;
+			break;
+		}
+	}
+
+	if (!to_marvell_nand(chip)->layout ||
+	    (!nfc->caps->is_nfcv2 && ecc->strength > 1)) {
+		dev_err(nfc->dev,
+			"ECC strength %d at page size %d is not supported\n",
+			ecc->strength, mtd->writesize);
+		return -ENOTSUPP;
+	}
+
+	mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
+	ecc->steps = l->full_chunk_cnt + l->last_chunk_cnt;
+	ecc->size = l->data_bytes;
+
+	if (ecc->strength == 1) {
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		ecc->read_page_raw = marvell_nfc_hw_ecc_hmg_read_page_raw;
+		ecc->read_page = marvell_nfc_hw_ecc_hmg_read_page;
+		ecc->read_oob_raw = marvell_nfc_hw_ecc_hmg_read_oob_raw;
+		ecc->read_oob = ecc->read_oob_raw;
+		ecc->write_page_raw = marvell_nfc_hw_ecc_hmg_write_page_raw;
+		ecc->write_page = marvell_nfc_hw_ecc_hmg_write_page;
+		ecc->write_oob_raw = marvell_nfc_hw_ecc_hmg_write_oob_raw;
+		ecc->write_oob = ecc->write_oob_raw;
+	} else {
+		chip->ecc.algo = NAND_ECC_BCH;
+		ecc->strength = 16;
+		ecc->read_page_raw = marvell_nfc_hw_ecc_bch_read_page_raw;
+		ecc->read_page = marvell_nfc_hw_ecc_bch_read_page;
+		ecc->read_oob_raw = marvell_nfc_hw_ecc_bch_read_oob_raw;
+		ecc->read_oob = marvell_nfc_hw_ecc_bch_read_oob;
+		ecc->write_page_raw = marvell_nfc_hw_ecc_bch_write_page_raw;
+		ecc->write_page = marvell_nfc_hw_ecc_bch_write_page;
+		ecc->write_oob_raw = marvell_nfc_hw_ecc_bch_write_oob_raw;
+		ecc->write_oob = marvell_nfc_hw_ecc_bch_write_oob;
+	}
+
+	return 0;
+}
+
+static int marvell_nand_ecc_init(struct mtd_info *mtd,
+				 struct nand_ecc_ctrl *ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int ret;
+
+	if ((ecc->mode != NAND_ECC_NONE) && (!ecc->size || !ecc->strength)) {
+		if (chip->ecc_step_ds && chip->ecc_strength_ds) {
+			ecc->size = chip->ecc_step_ds;
+			ecc->strength = chip->ecc_strength_ds;
+		} else {
+			dev_info(nfc->dev,
+				 "No minimum ECC strength, using 1b/512B\n");
+			ecc->size = 512;
+			ecc->strength = 1;
+		}
+	}
+
+	switch (ecc->mode) {
+	case NAND_ECC_HW:
+		ret = marvell_nand_hw_ecc_ctrl_init(mtd, ecc);
+		if (ret)
+			return ret;
+		break;
+	case NAND_ECC_NONE:
+		chip->ecc.algo = 0;
+	case NAND_ECC_SOFT:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
+static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,	/* Last 8 blocks in each chip */
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,	/* Last 8 blocks in each chip */
+	.pattern = bbt_mirror_pattern
+};
+
+static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, 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->ecc_clk) * 2;
+	const struct nand_sdr_timings *sdr;
+	struct marvell_nfc_timings nfc_tmg;
+	int read_delay;
+
+	sdr = nand_get_sdr_timings(conf);
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	/*
+	 * SDR timings are given in pico-seconds while NFC timings must be
+	 * expressed in NAND controller clock cycles, which is half of the
+	 * frequency of the accessible ECC clock retrieved by clk_get_rate().
+	 * This is not written anywhere in the datasheet but was observed
+	 * with an oscilloscope.
+	 *
+	 * NFC datasheet gives equations from which thoses calculations
+	 * are derived, they tend to be slightly more restrictives than the
+	 * given core timings and may improve the overall speed.
+	 */
+	nfc_tmg.tRP = TO_CYCLES(DIV_ROUND_UP(sdr->tRC_min, 2), period_ns) - 1;
+	nfc_tmg.tRH = nfc_tmg.tRP;
+	nfc_tmg.tWP = TO_CYCLES(DIV_ROUND_UP(sdr->tWC_min, 2), period_ns) - 1;
+	nfc_tmg.tWH = nfc_tmg.tWP;
+	nfc_tmg.tCS = TO_CYCLES(sdr->tCS_min, period_ns);
+	nfc_tmg.tCH = TO_CYCLES(sdr->tCH_min, period_ns) - 1;
+	nfc_tmg.tADL = TO_CYCLES(sdr->tADL_min, period_ns);
+	/*
+	 * Read delay is the time of propagation from SoC pins to NFC internal
+	 * logic. With non-EDO timings, this is MIN_RD_DEL_CNT clock cycles. In
+	 * EDO mode, an additional delay of tRH must be taken into account so
+	 * the data is sampled on the falling edge instead of the rising edge.
+	 */
+	read_delay = sdr->tRC_min >= 30000 ?
+		MIN_RD_DEL_CNT : MIN_RD_DEL_CNT + nfc_tmg.tRH;
+
+	nfc_tmg.tAR = TO_CYCLES(sdr->tAR_min, period_ns);
+	/*
+	 * tWHR and tRHW are supposed to be read to write delays (and vice
+	 * versa) but in some cases, ie. when doing a change column, they must
+	 * be greater than that to be sure tCCS delay is respected.
+	 */
+	nfc_tmg.tWHR = TO_CYCLES(max_t(int, sdr->tWHR_min, sdr->tCCS_min),
+				 period_ns) - 2,
+	nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min),
+				 period_ns);
+
+	/* Use WAIT_MODE (wait for RB line) instead of only relying on delays */
+	nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
+
+	if (chipnr < 0)
+		return 0;
+
+	marvell_nand->ndtr0 =
+		NDTR0_TRP(nfc_tmg.tRP) |
+		NDTR0_TRH(nfc_tmg.tRH) |
+		NDTR0_ETRP(nfc_tmg.tRP) |
+		NDTR0_TWP(nfc_tmg.tWP) |
+		NDTR0_TWH(nfc_tmg.tWH) |
+		NDTR0_TCS(nfc_tmg.tCS) |
+		NDTR0_TCH(nfc_tmg.tCH) |
+		NDTR0_RD_CNT_DEL(read_delay) |
+		NDTR0_SELCNTR |
+		NDTR0_TADL(nfc_tmg.tADL);
+
+	marvell_nand->ndtr1 =
+		NDTR1_TAR(nfc_tmg.tAR) |
+		NDTR1_TWHR(nfc_tmg.tWHR) |
+		NDTR1_TRHW(nfc_tmg.tRHW) |
+		NDTR1_WAIT_MODE |
+		NDTR1_TR(nfc_tmg.tR);
+
+	writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
+	writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
+
+	return 0;
+}
+
+static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
+				  struct device_node *np)
+{
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(dev);
+	struct marvell_nand_chip *marvell_nand;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	int nsels, ret, i;
+	u32 cs, rb;
+
+	/*
+	 * The legacy "num-cs" property indicates the number of CS on the only
+	 * chip connected to the controller (legacy bindings does not support
+	 * more than one chip). CS are only incremented one by one while the RB
+	 * pin is always the #0.
+	 *
+	 * When not using legacy bindings, a couple of "reg" and "marvell,rb"
+	 * properties must be filled. For each chip, expressed as a subnode,
+	 * "reg" points to the CS lines and "marvell,rb" to the RB line.
+	 */
+	if (pdata) {
+		nsels = 1;
+	} else if (nfc->caps->legacy_of_bindings) {
+		if (!of_get_property(np, "num-cs", &nsels)) {
+			dev_err(dev, "missing num-cs property\n");
+			return -EINVAL;
+		}
+	} else {
+		if (!of_get_property(np, "reg", &nsels)) {
+			dev_err(dev, "missing reg property\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!pdata)
+		nsels /= sizeof(u32);
+	if (!nsels) {
+		dev_err(dev, "invalid reg property size\n");
+		return -EINVAL;
+	}
+
+	/* Alloc the nand chip structure */
+	marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) +
+				    (nsels *
+				     sizeof(struct marvell_nand_chip_sel)),
+				    GFP_KERNEL);
+	if (!marvell_nand) {
+		dev_err(dev, "could not allocate chip structure\n");
+		return -ENOMEM;
+	}
+
+	marvell_nand->nsels = nsels;
+	marvell_nand->selected_die = -1;
+
+	for (i = 0; i < nsels; i++) {
+		if (pdata || nfc->caps->legacy_of_bindings) {
+			/*
+			 * Legacy bindings use the CS lines in natural
+			 * order (0, 1, ...)
+			 */
+			cs = i;
+		} else {
+			/* Retrieve CS id */
+			ret = of_property_read_u32_index(np, "reg", i, &cs);
+			if (ret) {
+				dev_err(dev, "could not retrieve reg property: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
+		if (cs >= nfc->caps->max_cs_nb) {
+			dev_err(dev, "invalid reg value: %u (max CS = %d)\n",
+				cs, nfc->caps->max_cs_nb);
+			return -EINVAL;
+		}
+
+		if (test_and_set_bit(cs, &nfc->assigned_cs)) {
+			dev_err(dev, "CS %d already assigned\n", cs);
+			return -EINVAL;
+		}
+
+		/*
+		 * The cs variable represents the chip select id, which must be
+		 * converted in bit fields for NDCB0 and NDCB2 to select the
+		 * right chip. Unfortunately, due to a lack of information on
+		 * the subject and incoherent documentation, the user should not
+		 * use CS1 and CS3 at all as asserting them is not supported in
+		 * a reliable way (due to multiplexing inside ADDR5 field).
+		 */
+		marvell_nand->sels[i].cs = cs;
+		switch (cs) {
+		case 0:
+		case 2:
+			marvell_nand->sels[i].ndcb0_csel = 0;
+			break;
+		case 1:
+		case 3:
+			marvell_nand->sels[i].ndcb0_csel = NDCB0_CSEL;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Retrieve RB id */
+		if (pdata || nfc->caps->legacy_of_bindings) {
+			/* Legacy bindings always use RB #0 */
+			rb = 0;
+		} else {
+			ret = of_property_read_u32_index(np, "marvell,rb", i,
+							 &rb);
+			if (ret) {
+				dev_err(dev,
+					"could not retrieve RB property: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
+		if (rb >= nfc->caps->max_rb_nb) {
+			dev_err(dev, "invalid reg value: %u (max RB = %d)\n",
+				rb, nfc->caps->max_rb_nb);
+			return -EINVAL;
+		}
+
+		marvell_nand->sels[i].rb = rb;
+	}
+
+	chip = &marvell_nand->chip;
+	chip->controller = &nfc->controller;
+	nand_set_flash_node(chip, np);
+
+	chip->exec_op = marvell_nfc_exec_op;
+	chip->select_chip = marvell_nfc_select_chip;
+	if (nfc->caps->is_nfcv2 &&
+	    !of_property_read_bool(np, "marvell,nand-keep-config"))
+		chip->setup_data_interface = marvell_nfc_setup_data_interface;
+
+	mtd = nand_to_mtd(chip);
+	mtd->dev.parent = dev;
+
+	/*
+	 * Default to HW ECC engine mode. If the nand-ecc-mode property is given
+	 * in the DT node, this entry will be overwritten in nand_scan_ident().
+	 */
+	chip->ecc.mode = NAND_ECC_HW;
+
+	ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
+	if (ret) {
+		dev_err(dev, "could not identify the nand chip\n");
+		return ret;
+	}
+
+	if (pdata && pdata->flash_bbt)
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	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_NO_OOB_BBM;
+		chip->bbt_td = &bbt_main_descr;
+		chip->bbt_md = &bbt_mirror_descr;
+	}
+
+	/*
+	 * With RA_START bit set in NDCR, columns takes two address cycles. This
+	 * means addressing a chip with more than 256 pages needs a fifth
+	 * address cycle. Addressing a chip using CS 2 or 3 should also needs
+	 * this additional cycle but due to insistance in the documentation and
+	 * lack of hardware to test this situation, this case has been dropped
+	 * and is not supported by this driver.
+	 */
+	marvell_nand->addr_cyc = 4;
+	if (chip->options & NAND_ROW_ADDR_3)
+		marvell_nand->addr_cyc = 5;
+
+	if (pdata) {
+		chip->ecc.size = pdata->ecc_step_size;
+		chip->ecc.strength = pdata->ecc_strength;
+	}
+
+	ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+	if (ret) {
+		dev_err(dev, "ECC init failed: %d\n", ret);
+		return ret;
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW) {
+		/*
+		 * Subpage write not available with hardware ECC, prohibit also
+		 * subpage read as in userspace subpage acces would still be
+		 * allowed and subpage write, if used, would lead to numerous
+		 * uncorrectable ECC errors.
+		 */
+		chip->options |= NAND_NO_SUBPAGE_WRITE;
+	}
+
+	if (pdata || nfc->caps->legacy_of_bindings) {
+		/*
+		 * We keep the MTD name unchanged to avoid breaking platforms
+		 * where the MTD cmdline parser is used and the bootloader
+		 * has not been updated to use the new naming scheme.
+		 */
+		mtd->name = "pxa3xx_nand-0";
+	} else if (!mtd->name) {
+		/*
+		 * If the new bindings are used and the bootloader has not been
+		 * updated to pass a new mtdparts parameter on the cmdline, you
+		 * should define the following property in your NAND node, ie:
+		 *
+		 *	label = "main-storage";
+		 *
+		 * This way, mtd->name will be set by the core when
+		 * nand_set_flash_node() is called.
+		 */
+		mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+					   "%s:nand.%d", dev_name(nfc->dev),
+					   marvell_nand->sels[0].cs);
+		if (!mtd->name) {
+			dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata)
+		/* Legacy bindings support only one chip */
+		ret = mtd_device_register(mtd, pdata->parts[0],
+					  pdata->nr_parts[0]);
+	else
+		ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(dev, "failed to register mtd device: %d\n", ret);
+		nand_release(mtd);
+		return ret;
+	}
+
+	list_add_tail(&marvell_nand->node, &nfc->chips);
+
+	return 0;
+}
+
+static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *nand_np;
+	int max_cs = nfc->caps->max_cs_nb;
+	int nchips;
+	int ret;
+
+	if (!np)
+		nchips = 1;
+	else
+		nchips = of_get_child_count(np);
+
+	if (nchips > max_cs) {
+		dev_err(dev, "too many NAND chips: %d (max = %d CS)\n", nchips,
+			max_cs);
+		return -EINVAL;
+	}
+
+	/*
+	 * Legacy bindings do not use child nodes to exhibit NAND chip
+	 * properties and layout. Instead, NAND properties are mixed with the
+	 * controller's and a single subnode presents the memory layout.
+	 */
+	if (nfc->caps->legacy_of_bindings) {
+		ret = marvell_nand_chip_init(dev, nfc, np);
+		return ret;
+	}
+
+	for_each_child_of_node(np, nand_np) {
+		ret = marvell_nand_chip_init(dev, nfc, nand_np);
+		if (ret) {
+			of_node_put(nand_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
+{
+	struct marvell_nand_chip *entry, *temp;
+
+	list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
+		nand_release(nand_to_mtd(&entry->chip));
+		list_del(&entry->node);
+	}
+}
+
+static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
+{
+	struct platform_device *pdev = container_of(nfc->dev,
+						    struct platform_device,
+						    dev);
+	struct dma_slave_config config = {};
+	struct resource *r;
+	dma_cap_mask_t mask;
+	struct pxad_param param;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_PXA_DMA)) {
+		dev_warn(nfc->dev,
+			 "DMA not enabled in configuration\n");
+		return -ENOTSUPP;
+	}
+
+	ret = dma_set_mask_and_coherent(nfc->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r) {
+		dev_err(nfc->dev, "No resource defined for data DMA\n");
+		return -ENXIO;
+	}
+
+	param.drcmr = r->start;
+	param.prio = PXAD_PRIO_LOWEST;
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	nfc->dma_chan =
+		dma_request_slave_channel_compat(mask, pxad_filter_fn,
+						 &param, nfc->dev,
+						 "data");
+	if (!nfc->dma_chan) {
+		dev_err(nfc->dev,
+			"Unable to request data DMA channel\n");
+		return -ENODEV;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -ENXIO;
+
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.src_addr = r->start + NDDB;
+	config.dst_addr = r->start + NDDB;
+	config.src_maxburst = 32;
+	config.dst_maxburst = 32;
+	ret = dmaengine_slave_config(nfc->dma_chan, &config);
+	if (ret < 0) {
+		dev_err(nfc->dev, "Failed to configure DMA channel\n");
+		return ret;
+	}
+
+	/*
+	 * DMA must act on length multiple of 32 and this length may be
+	 * bigger than the destination buffer. Use this buffer instead
+	 * for DMA transfers and then copy the desired amount of data to
+	 * the provided buffer.
+	 */
+	nfc->dma_buf = kmalloc(MAX_CHUNK_SIZE, GFP_DMA);
+	if (!nfc->dma_buf)
+		return -ENOMEM;
+
+	nfc->use_dma = true;
+
+	return 0;
+}
+
+static int marvell_nfc_init(struct marvell_nfc *nfc)
+{
+	struct device_node *np = nfc->dev->of_node;
+
+	/*
+	 * Some SoCs like A7k/A8k need to enable manually the NAND
+	 * controller, gated clocks and reset bits to avoid being bootloader
+	 * dependent. This is done through the use of the System Functions
+	 * registers.
+	 */
+	if (nfc->caps->need_system_controller) {
+		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_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_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
+		reg |= GENCONF_ND_CLK_CTRL_EN;
+		regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+	}
+
+	/* Configure the DMA if appropriate */
+	if (!nfc->caps->is_nfcv2)
+		marvell_nfc_init_dma(nfc);
+
+	/*
+	 * ECC operations and interruptions are only enabled when specifically
+	 * needed. ECC shall not be activated in the early stages (fails probe).
+	 * Arbiter flag, even if marked as "reserved", must be set (empirical).
+	 */
+	writel_relaxed(NDCR_RA_START | NDCR_ALL_INT | NDCR_ND_ARB_EN |
+		       (nfc->caps->is_nfcv2 ?
+			0 : NDCR_RD_ID_CNT(NFCV1_READID_LEN)),
+		       nfc->regs + NDCR);
+	writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
+	writel_relaxed(0, nfc->regs + NDECCCTRL);
+
+	return 0;
+}
+
+static int marvell_nfc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *r;
+	struct marvell_nfc *nfc;
+	int ret;
+	int irq;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(struct marvell_nfc),
+			   GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	nfc->dev = dev;
+	nand_hw_control_init(&nfc->controller);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(dev, r);
+	if (IS_ERR(nfc->regs))
+		return PTR_ERR(nfc->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "failed to retrieve irq\n");
+		return irq;
+	}
+
+	nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(nfc->ecc_clk))
+		return PTR_ERR(nfc->ecc_clk);
+
+	ret = clk_prepare_enable(nfc->ecc_clk);
+	if (ret)
+		return ret;
+
+	marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
+	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
+	ret = devm_request_irq(dev, irq, marvell_nfc_isr,
+			       0, "marvell-nfc", nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	/* Get NAND controller capabilities */
+	if (pdev->id_entry)
+		nfc->caps = (void *)pdev->id_entry->driver_data;
+	else
+		nfc->caps = of_device_get_match_data(&pdev->dev);
+
+	if (!nfc->caps) {
+		dev_err(dev, "Could not retrieve NFC caps\n");
+		ret = -EINVAL;
+		goto unprepare_clk;
+	}
+
+	/* Init the controller and then probe the chips */
+	ret = marvell_nfc_init(nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	platform_set_drvdata(pdev, nfc);
+
+	ret = marvell_nand_chips_init(dev, nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	return 0;
+
+unprepare_clk:
+	clk_disable_unprepare(nfc->ecc_clk);
+
+	return ret;
+}
+
+static int marvell_nfc_remove(struct platform_device *pdev)
+{
+	struct marvell_nfc *nfc = platform_get_drvdata(pdev);
+
+	marvell_nand_chips_cleanup(nfc);
+
+	if (nfc->use_dma) {
+		dmaengine_terminate_all(nfc->dma_chan);
+		dma_release_channel(nfc->dma_chan);
+	}
+
+	clk_disable_unprepare(nfc->ecc_clk);
+
+	return 0;
+}
+
+static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.need_system_controller = true,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada370_nfc_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_pxa3xx_nfc_caps = {
+	.max_cs_nb = 2,
+	.max_rb_nb = 1,
+	.use_dma = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada_8k_nfc_legacy_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.need_system_controller = true,
+	.legacy_of_bindings = true,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada370_nfc_legacy_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.legacy_of_bindings = true,
+};
+
+static const struct marvell_nfc_caps marvell_pxa3xx_nfc_legacy_caps = {
+	.max_cs_nb = 2,
+	.max_rb_nb = 1,
+	.legacy_of_bindings = true,
+};
+
+static const struct platform_device_id marvell_nfc_platform_ids[] = {
+	{
+		.name = "pxa3xx-nand",
+		.driver_data = (kernel_ulong_t)&marvell_pxa3xx_nfc_legacy_caps,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, marvell_nfc_platform_ids);
+
+static const struct of_device_id marvell_nfc_of_ids[] = {
+	{
+		.compatible = "marvell,armada-8k-nand-controller",
+		.data = &marvell_armada_8k_nfc_caps,
+	},
+	{
+		.compatible = "marvell,armada370-nand-controller",
+		.data = &marvell_armada370_nfc_caps,
+	},
+	{
+		.compatible = "marvell,pxa3xx-nand-controller",
+		.data = &marvell_pxa3xx_nfc_caps,
+	},
+	/* Support for old/deprecated bindings: */
+	{
+		.compatible = "marvell,armada-8k-nand",
+		.data = &marvell_armada_8k_nfc_legacy_caps,
+	},
+	{
+		.compatible = "marvell,armada370-nand",
+		.data = &marvell_armada370_nfc_legacy_caps,
+	},
+	{
+		.compatible = "marvell,pxa3xx-nand",
+		.data = &marvell_pxa3xx_nfc_legacy_caps,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, marvell_nfc_of_ids);
+
+static struct platform_driver marvell_nfc_driver = {
+	.driver	= {
+		.name		= "marvell-nfc",
+		.of_match_table = marvell_nfc_of_ids,
+	},
+	.id_table = marvell_nfc_platform_ids,
+	.probe = marvell_nfc_probe,
+	.remove	= marvell_nfc_remove,
+};
+module_platform_driver(marvell_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Marvell NAND controller driver");
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 03/12] mtd: nand: replace pxa3xx_nand driver by its rework called marvell_nand
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-07 20:18   ` [PATCH 01/12] dt-bindings: mtd: add Marvell NAND controller documentation Miquel Raynal
  2017-12-07 20:18   ` [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 04/12] dt-bindings: mtd: remove pxa3xx NAND controller documentation Miquel Raynal
                     ` (10 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Actually remove pxa3xx_nand.c to let marvell_nand.c be compiled instead.
Also change the defconfig files using it as well as some board files
depending on CONFIG_MTD_NAND_PXA3xx.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/configs/cm_x300_defconfig  |    2 +-
 arch/arm/configs/mvebu_v7_defconfig |    2 +-
 arch/arm/configs/pxa3xx_defconfig   |    3 +-
 arch/arm/configs/pxa_defconfig      |    2 +-
 arch/arm/configs/raumfeld_defconfig |    2 +-
 arch/arm/mach-mmp/ttc_dkb.c         |    4 +-
 arch/arm/mach-pxa/cm-x300.c         |    2 +-
 arch/arm/mach-pxa/colibri-pxa3xx.c  |    2 +-
 arch/arm/mach-pxa/colibri.h         |    2 +-
 arch/arm/mach-pxa/littleton.c       |    4 +-
 arch/arm/mach-pxa/mxm8x10.c         |    4 +-
 arch/arm/mach-pxa/zylonite.c        |    4 +-
 drivers/mtd/nand/Makefile           |    1 -
 drivers/mtd/nand/pxa3xx_nand.c      | 2104 -----------------------------------
 14 files changed, 16 insertions(+), 2122 deletions(-)
 delete mode 100644 drivers/mtd/nand/pxa3xx_nand.c

diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig
index c0418e03d180..5e349c625b71 100644
--- a/arch/arm/configs/cm_x300_defconfig
+++ b/arch/arm/configs/cm_x300_defconfig
@@ -49,7 +49,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PXA3xx=y
+CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index 69553704f2dc..4b6e4fd47e5d 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -57,7 +57,7 @@ CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PXA3xx=y
+CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_SRAM=y
 CONFIG_MTD_UBI=y
diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
index bfea6874b0a1..3e0de035ab77 100644
--- a/arch/arm/configs/pxa3xx_defconfig
+++ b/arch/arm/configs/pxa3xx_defconfig
@@ -32,8 +32,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PXA3xx=y
-CONFIG_MTD_NAND_PXA3xx_BUILTIN=y
+CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_GENERIC=y
diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig
index 830e817a028a..934af8601f7d 100644
--- a/arch/arm/configs/pxa_defconfig
+++ b/arch/arm/configs/pxa_defconfig
@@ -198,7 +198,7 @@ CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
 CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
 CONFIG_MTD_NAND_SHARPSL=m
-CONFIG_MTD_NAND_PXA3xx=m
+CONFIG_MTD_NAND_MARVELL=m
 CONFIG_MTD_NAND_CM_X270=m
 CONFIG_MTD_NAND_TMIO=m
 CONFIG_MTD_NAND_BRCMNAND=m
diff --git a/arch/arm/configs/raumfeld_defconfig b/arch/arm/configs/raumfeld_defconfig
index 77a56c23c6ef..2dd56e9a484e 100644
--- a/arch/arm/configs/raumfeld_defconfig
+++ b/arch/arm/configs/raumfeld_defconfig
@@ -33,7 +33,7 @@ CONFIG_NFTL=y
 CONFIG_NFTL_RW=y
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PXA3xx=y
+CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_ISL29003=y
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index d90c74fa614d..e0b6073c61a7 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -178,7 +178,7 @@ static struct mv_usb_platform_data ttc_usb_pdata = {
 #endif
 #endif
 
-#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx)
+#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
 static struct pxa3xx_nand_platform_data dkb_nand_info = {
 	.enable_arbiter = 1,
 	.num_cs = 1,
@@ -275,7 +275,7 @@ static void __init ttc_dkb_init(void)
 
 	/* on-chip devices */
 	pxa910_add_uart(1);
-#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx)
+#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
 	pxa910_add_nand(&dkb_nand_info);
 #endif
 
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 868448d2cd82..89326378dabf 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -391,7 +391,7 @@ static void __init cm_x300_init_ac97(void)
 static inline void cm_x300_init_ac97(void) {}
 #endif
 
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 static struct mtd_partition cm_x300_nand_partitions[] = {
 	[0] = {
 		.name        = "OBM",
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index b04431bb4ba7..c9c36f707555 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -110,7 +110,7 @@ void __init colibri_pxa3xx_init_lcd(int bl_pin)
 }
 #endif
 
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 static struct mtd_partition colibri_nand_partitions[] = {
 	{
 		.name        = "bootloader",
diff --git a/arch/arm/mach-pxa/colibri.h b/arch/arm/mach-pxa/colibri.h
index 673a131da875..d5ba74831916 100644
--- a/arch/arm/mach-pxa/colibri.h
+++ b/arch/arm/mach-pxa/colibri.h
@@ -46,7 +46,7 @@ static inline void colibri_pxa3xx_init_lcd(int bl_pin) {}
 extern void colibri_pxa3xx_init_eth(struct ax_plat_data *plat_data);
 #endif
 
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 extern void colibri_pxa3xx_init_nand(void);
 #else
 static inline void colibri_pxa3xx_init_nand(void) {}
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index fae38fdc8d8e..898961be36db 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -290,7 +290,7 @@ static void __init littleton_init_mmc(void)
 static inline void littleton_init_mmc(void) {}
 #endif
 
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 static struct mtd_partition littleton_nand_partitions[] = {
 	[0] = {
 		.name        = "Bootloader",
@@ -340,7 +340,7 @@ static void __init littleton_init_nand(void)
 }
 #else
 static inline void littleton_init_nand(void) {}
-#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
+#endif /* CONFIG_MTD_NAND_MARVELL || CONFIG_MTD_NAND_MARVELL_MODULE */
 
 #if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
 static struct led_info littleton_da9034_leds[] = {
diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c
index 9a22ae0ad8c9..7d7aab20b70a 100644
--- a/arch/arm/mach-pxa/mxm8x10.c
+++ b/arch/arm/mach-pxa/mxm8x10.c
@@ -359,7 +359,7 @@ void __init mxm_8x10_ac97_init(void)
 }
 
 /* NAND flash Support */
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 #define NAND_BLOCK_SIZE SZ_128K
 #define NB(x)           (NAND_BLOCK_SIZE * (x))
 static struct mtd_partition mxm_8x10_nand_partitions[] = {
@@ -402,7 +402,7 @@ static void __init mxm_8x10_nand_init(void)
 }
 #else
 static inline void mxm_8x10_nand_init(void) {}
-#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
+#endif /* CONFIG_MTD_NAND_MARVELL || CONFIG_MTD_NAND_MARVELL_MODULE */
 
 /* Ethernet support: Davicom DM9000 */
 static struct resource dm9k_resources[] = {
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 4268552d600d..a4577118d518 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -338,7 +338,7 @@ static void __init zylonite_init_keypad(void)
 static inline void zylonite_init_keypad(void) {}
 #endif
 
-#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+#if defined(CONFIG_MTD_NAND_MARVELL) || defined(CONFIG_MTD_NAND_MARVELL_MODULE)
 static struct mtd_partition zylonite_nand_partitions[] = {
 	[0] = {
 		.name        = "Bootloader",
@@ -388,7 +388,7 @@ static void __init zylonite_init_nand(void)
 }
 #else
 static inline void zylonite_init_nand(void) {}
-#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
+#endif /* CONFIG_MTD_NAND_MARVELL || CONFIG_MTD_NAND_MARVELL_MODULE */
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 static struct pxaohci_platform_data zylonite_ohci_info = {
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 921634ba400c..c882d5ef192a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -31,7 +31,6 @@ omap2_nand-objs := omap2.o
 obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
 obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
 obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
-obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_MARVELL)		+= marvell_nand.o
 obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
deleted file mode 100644
index 021374fe59dc..000000000000
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ /dev/null
@@ -1,2104 +0,0 @@
-/*
- * drivers/mtd/nand/pxa3xx_nand.c
- *
- * Copyright © 2005 Intel Corporation
- * Copyright © 2006 Marvell International Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_data/mtd-nand-pxa3xx.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-
-#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
-#define NAND_STOP_DELAY		msecs_to_jiffies(40)
-#define PAGE_CHUNK_SIZE		(2048)
-
-/*
- * Define a buffer size for the initial command that detects the flash device:
- * STATUS, READID and PARAM.
- * ONFI param page is 256 bytes, and there are three redundant copies
- * to be read. JEDEC param page is 512 bytes, and there are also three
- * redundant copies to be read.
- * Hence this buffer should be at least 512 x 3. Let's pick 2048.
- */
-#define INIT_BUFFER_SIZE	2048
-
-/* System control register and bit to enable NAND on some SoCs */
-#define GENCONF_SOC_DEVICE_MUX	0x208
-#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
-
-/* registers and bit definitions */
-#define NDCR		(0x00) /* Control register */
-#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
-#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
-#define NDSR		(0x14) /* Status Register */
-#define NDPCR		(0x18) /* Page Count Register */
-#define NDBDR0		(0x1C) /* Bad Block Register 0 */
-#define NDBDR1		(0x20) /* Bad Block Register 1 */
-#define NDECCCTRL	(0x28) /* ECC control */
-#define NDDB		(0x40) /* Data Buffer */
-#define NDCB0		(0x48) /* Command Buffer0 */
-#define NDCB1		(0x4C) /* Command Buffer1 */
-#define NDCB2		(0x50) /* Command Buffer2 */
-
-#define NDCR_SPARE_EN		(0x1 << 31)
-#define NDCR_ECC_EN		(0x1 << 30)
-#define NDCR_DMA_EN		(0x1 << 29)
-#define NDCR_ND_RUN		(0x1 << 28)
-#define NDCR_DWIDTH_C		(0x1 << 27)
-#define NDCR_DWIDTH_M		(0x1 << 26)
-#define NDCR_PAGE_SZ		(0x1 << 24)
-#define NDCR_NCSX		(0x1 << 23)
-#define NDCR_ND_MODE		(0x3 << 21)
-#define NDCR_NAND_MODE   	(0x0)
-#define NDCR_CLR_PG_CNT		(0x1 << 20)
-#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
-#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
-#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
-#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
-
-#define NDCR_RA_START		(0x1 << 15)
-#define NDCR_PG_PER_BLK		(0x1 << 14)
-#define NDCR_ND_ARB_EN		(0x1 << 12)
-#define NDCR_INT_MASK           (0xFFF)
-
-#define NDSR_MASK		(0xfff)
-#define NDSR_ERR_CNT_OFF	(16)
-#define NDSR_ERR_CNT_MASK       (0x1f)
-#define NDSR_ERR_CNT(sr)	((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
-#define NDSR_RDY                (0x1 << 12)
-#define NDSR_FLASH_RDY          (0x1 << 11)
-#define NDSR_CS0_PAGED		(0x1 << 10)
-#define NDSR_CS1_PAGED		(0x1 << 9)
-#define NDSR_CS0_CMDD		(0x1 << 8)
-#define NDSR_CS1_CMDD		(0x1 << 7)
-#define NDSR_CS0_BBD		(0x1 << 6)
-#define NDSR_CS1_BBD		(0x1 << 5)
-#define NDSR_UNCORERR		(0x1 << 4)
-#define NDSR_CORERR		(0x1 << 3)
-#define NDSR_WRDREQ		(0x1 << 2)
-#define NDSR_RDDREQ		(0x1 << 1)
-#define NDSR_WRCMDREQ		(0x1)
-
-#define NDCB0_LEN_OVRD		(0x1 << 28)
-#define NDCB0_ST_ROW_EN         (0x1 << 26)
-#define NDCB0_AUTO_RS		(0x1 << 25)
-#define NDCB0_CSEL		(0x1 << 24)
-#define NDCB0_EXT_CMD_TYPE_MASK	(0x7 << 29)
-#define NDCB0_EXT_CMD_TYPE(x)	(((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
-#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
-#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
-#define NDCB0_NC		(0x1 << 20)
-#define NDCB0_DBC		(0x1 << 19)
-#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
-#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
-#define NDCB0_CMD2_MASK		(0xff << 8)
-#define NDCB0_CMD1_MASK		(0xff)
-#define NDCB0_ADDR_CYC_SHIFT	(16)
-
-#define EXT_CMD_TYPE_DISPATCH	6 /* Command dispatch */
-#define EXT_CMD_TYPE_NAKED_RW	5 /* Naked read or Naked write */
-#define EXT_CMD_TYPE_READ	4 /* Read */
-#define EXT_CMD_TYPE_DISP_WR	4 /* Command dispatch with write */
-#define EXT_CMD_TYPE_FINAL	3 /* Final command */
-#define EXT_CMD_TYPE_LAST_RW	1 /* Last naked read/write */
-#define EXT_CMD_TYPE_MONO	0 /* Monolithic read/write */
-
-/*
- * This should be large enough to read 'ONFI' and 'JEDEC'.
- * Let's use 7 bytes, which is the maximum ID count supported
- * by the controller (see NDCR_RD_ID_CNT_MASK).
- */
-#define READ_ID_BYTES		7
-
-/* macros for registers read/write */
-#define nand_writel(info, off, val)					\
-	do {								\
-		dev_vdbg(&info->pdev->dev,				\
-			 "%s():%d nand_writel(0x%x, 0x%04x)\n",		\
-			 __func__, __LINE__, (val), (off));		\
-		writel_relaxed((val), (info)->mmio_base + (off));	\
-	} while (0)
-
-#define nand_readl(info, off)						\
-	({								\
-		unsigned int _v;					\
-		_v = readl_relaxed((info)->mmio_base + (off));		\
-		dev_vdbg(&info->pdev->dev,				\
-			 "%s():%d nand_readl(0x%04x) = 0x%x\n",		\
-			 __func__, __LINE__, (off), _v);		\
-		_v;							\
-	})
-
-/* error code and state */
-enum {
-	ERR_NONE	= 0,
-	ERR_DMABUSERR	= -1,
-	ERR_SENDCMD	= -2,
-	ERR_UNCORERR	= -3,
-	ERR_BBERR	= -4,
-	ERR_CORERR	= -5,
-};
-
-enum {
-	STATE_IDLE = 0,
-	STATE_PREPARED,
-	STATE_CMD_HANDLE,
-	STATE_DMA_READING,
-	STATE_DMA_WRITING,
-	STATE_DMA_DONE,
-	STATE_PIO_READING,
-	STATE_PIO_WRITING,
-	STATE_CMD_DONE,
-	STATE_READY,
-};
-
-enum pxa3xx_nand_variant {
-	PXA3XX_NAND_VARIANT_PXA,
-	PXA3XX_NAND_VARIANT_ARMADA370,
-	PXA3XX_NAND_VARIANT_ARMADA_8K,
-};
-
-struct pxa3xx_nand_host {
-	struct nand_chip	chip;
-	void			*info_data;
-
-	/* page size of attached chip */
-	int			use_ecc;
-	int			cs;
-
-	/* calculated from pxa3xx_nand_flash data */
-	unsigned int		col_addr_cycles;
-	unsigned int		row_addr_cycles;
-};
-
-struct pxa3xx_nand_info {
-	struct nand_hw_control	controller;
-	struct platform_device	 *pdev;
-
-	struct clk		*clk;
-	void __iomem		*mmio_base;
-	unsigned long		mmio_phys;
-	struct completion	cmd_complete, dev_ready;
-
-	unsigned int 		buf_start;
-	unsigned int		buf_count;
-	unsigned int		buf_size;
-	unsigned int		data_buff_pos;
-	unsigned int		oob_buff_pos;
-
-	/* DMA information */
-	struct scatterlist	sg;
-	enum dma_data_direction	dma_dir;
-	struct dma_chan		*dma_chan;
-	dma_cookie_t		dma_cookie;
-	int			drcmr_dat;
-
-	unsigned char		*data_buff;
-	unsigned char		*oob_buff;
-	dma_addr_t 		data_buff_phys;
-	int 			data_dma_ch;
-
-	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
-	unsigned int		state;
-
-	/*
-	 * This driver supports NFCv1 (as found in PXA SoC)
-	 * and NFCv2 (as found in Armada 370/XP SoC).
-	 */
-	enum pxa3xx_nand_variant variant;
-
-	int			cs;
-	int			use_ecc;	/* use HW ECC ? */
-	int			ecc_bch;	/* using BCH ECC? */
-	int			use_dma;	/* use DMA ? */
-	int			use_spare;	/* use spare ? */
-	int			need_wait;
-
-	/* Amount of real data per full chunk */
-	unsigned int		chunk_size;
-
-	/* Amount of spare data per full chunk */
-	unsigned int		spare_size;
-
-	/* Number of full chunks (i.e chunk_size + spare_size) */
-	unsigned int            nfullchunks;
-
-	/*
-	 * Total number of chunks. If equal to nfullchunks, then there
-	 * are only full chunks. Otherwise, there is one last chunk of
-	 * size (last_chunk_size + last_spare_size)
-	 */
-	unsigned int            ntotalchunks;
-
-	/* Amount of real data in the last chunk */
-	unsigned int		last_chunk_size;
-
-	/* Amount of spare data in the last chunk */
-	unsigned int		last_spare_size;
-
-	unsigned int		ecc_size;
-	unsigned int		ecc_err_cnt;
-	unsigned int		max_bitflips;
-	int 			retcode;
-
-	/*
-	 * Variables only valid during command
-	 * execution. step_chunk_size and step_spare_size is the
-	 * amount of real data and spare data in the current
-	 * chunk. cur_chunk is the current chunk being
-	 * read/programmed.
-	 */
-	unsigned int		step_chunk_size;
-	unsigned int		step_spare_size;
-	unsigned int            cur_chunk;
-
-	/* cached register value */
-	uint32_t		reg_ndcr;
-	uint32_t		ndtr0cs0;
-	uint32_t		ndtr1cs0;
-
-	/* generated NDCBx register values */
-	uint32_t		ndcb0;
-	uint32_t		ndcb1;
-	uint32_t		ndcb2;
-	uint32_t		ndcb3;
-};
-
-static bool use_dma = 1;
-module_param(use_dma, bool, 0444);
-MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
-
-struct pxa3xx_nand_timing {
-	unsigned int	tCH;  /* Enable signal hold time */
-	unsigned int	tCS;  /* Enable signal setup time */
-	unsigned int	tWH;  /* ND_nWE high duration */
-	unsigned int	tWP;  /* ND_nWE pulse time */
-	unsigned int	tRH;  /* ND_nRE high duration */
-	unsigned int	tRP;  /* ND_nRE pulse width */
-	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
-	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
-	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
-};
-
-struct pxa3xx_nand_flash {
-	uint32_t	chip_id;
-	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
-	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
-	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
-};
-
-static struct pxa3xx_nand_timing timing[] = {
-	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
-	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
-	{ 10, 25, 15,  25, 15,  30, 25000,  60, 10, },
-	{ 10, 35, 15,  25, 15,  25, 25000,  60, 10, },
-};
-
-static struct pxa3xx_nand_flash builtin_flash_types[] = {
-	{ 0x46ec, 16, 16, &timing[1] },
-	{ 0xdaec,  8,  8, &timing[1] },
-	{ 0xd7ec,  8,  8, &timing[1] },
-	{ 0xa12c,  8,  8, &timing[2] },
-	{ 0xb12c, 16, 16, &timing[2] },
-	{ 0xdc2c,  8,  8, &timing[2] },
-	{ 0xcc2c, 16, 16, &timing[2] },
-	{ 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' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,		/* Last 8 blocks in each chip */
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,		/* Last 8 blocks in each chip */
-	.pattern = bbt_mirror_pattern
-};
-
-#define NDTR0_tCH(c)	(min((c), 7) << 19)
-#define NDTR0_tCS(c)	(min((c), 7) << 16)
-#define NDTR0_tWH(c)	(min((c), 7) << 11)
-#define NDTR0_tWP(c)	(min((c), 7) << 8)
-#define NDTR0_tRH(c)	(min((c), 7) << 3)
-#define NDTR0_tRP(c)	(min((c), 7) << 0)
-
-#define NDTR1_tR(c)	(min((c), 65535) << 16)
-#define NDTR1_tWHR(c)	(min((c), 15) << 4)
-#define NDTR1_tAR(c)	(min((c), 15) << 0)
-
-/* convert nano-seconds to nand flash controller clock cycles */
-#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
-
-static const struct of_device_id pxa3xx_nand_dt_ids[] = {
-	{
-		.compatible = "marvell,pxa3xx-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
-	},
-	{
-		.compatible = "marvell,armada370-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
-	},
-	{
-		.compatible = "marvell,armada-8k-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA_8K,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
-
-static enum pxa3xx_nand_variant
-pxa3xx_nand_get_variant(struct platform_device *pdev)
-{
-	const struct of_device_id *of_id =
-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
-	if (!of_id)
-		return PXA3XX_NAND_VARIANT_PXA;
-	return (enum pxa3xx_nand_variant)of_id->data;
-}
-
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
-				   const struct pxa3xx_nand_timing *t)
-{
-	struct pxa3xx_nand_info *info = host->info_data;
-	unsigned long nand_clk = clk_get_rate(info->clk);
-	uint32_t ndtr0, ndtr1;
-
-	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
-		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
-		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
-		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
-		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
-		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
-
-	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
-		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
-		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
-
-	info->ndtr0cs0 = ndtr0;
-	info->ndtr1cs0 = ndtr1;
-	nand_writel(info, NDTR0CS0, ndtr0);
-	nand_writel(info, NDTR1CS0, ndtr1);
-}
-
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
-				       const struct nand_sdr_timings *t)
-{
-	struct pxa3xx_nand_info *info = host->info_data;
-	struct nand_chip *chip = &host->chip;
-	unsigned long nand_clk = clk_get_rate(info->clk);
-	uint32_t ndtr0, ndtr1;
-
-	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
-	u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
-	u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
-	u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
-	u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
-	u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
-	u32 tR = chip->chip_delay * 1000;
-	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
-	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
-
-	/* fallback to a default value if tR = 0 */
-	if (!tR)
-		tR = 20000;
-
-	ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
-		NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
-		NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
-		NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
-		NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
-		NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
-
-	ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
-		NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
-		NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
-
-	info->ndtr0cs0 = ndtr0;
-	info->ndtr1cs0 = ndtr1;
-	nand_writel(info, NDTR0CS0, ndtr0);
-	nand_writel(info, NDTR1CS0, ndtr1);
-}
-
-static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
-					   unsigned int *flash_width,
-					   unsigned int *dfc_width)
-{
-	struct nand_chip *chip = &host->chip;
-	struct pxa3xx_nand_info *info = host->info_data;
-	const struct pxa3xx_nand_flash *f = NULL;
-	int i, id, ntypes;
-	u8 idbuf[2];
-
-	ntypes = ARRAY_SIZE(builtin_flash_types);
-
-	nand_readid_op(chip, 0, idbuf, sizeof(idbuf));
-	id = idbuf[0] | (idbuf[1] << 8);
-
-	for (i = 0; i < ntypes; i++) {
-		f = &builtin_flash_types[i];
-
-		if (f->chip_id == id)
-			break;
-	}
-
-	if (i == ntypes) {
-		dev_err(&info->pdev->dev, "Error: timings not found\n");
-		return -EINVAL;
-	}
-
-	pxa3xx_nand_set_timing(host, f->timing);
-
-	*flash_width = f->flash_width;
-	*dfc_width = f->dfc_width;
-
-	return 0;
-}
-
-static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
-					 int mode)
-{
-	const struct nand_sdr_timings *timings;
-
-	mode = fls(mode) - 1;
-	if (mode < 0)
-		mode = 0;
-
-	timings = onfi_async_timing_mode_to_sdr_timings(mode);
-	if (IS_ERR(timings))
-		return PTR_ERR(timings);
-
-	pxa3xx_nand_set_sdr_timing(host, timings);
-
-	return 0;
-}
-
-static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	struct pxa3xx_nand_info *info = host->info_data;
-	unsigned int flash_width = 0, dfc_width = 0;
-	int mode, err;
-
-	mode = onfi_get_async_timing_mode(chip);
-	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
-		err = pxa3xx_nand_init_timings_compat(host, &flash_width,
-						      &dfc_width);
-		if (err)
-			return err;
-
-		if (flash_width == 16) {
-			info->reg_ndcr |= NDCR_DWIDTH_M;
-			chip->options |= NAND_BUSWIDTH_16;
-		}
-
-		info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
-	} else {
-		err = pxa3xx_nand_init_timings_onfi(host, mode);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/**
- * NOTE: it is a must to set ND_RUN firstly, then write
- * command buffer, otherwise, it does not work.
- * We enable all the interrupt at the same time, and
- * let pxa3xx_nand_irq to handle all logic.
- */
-static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
-{
-	uint32_t ndcr;
-
-	ndcr = info->reg_ndcr;
-
-	if (info->use_ecc) {
-		ndcr |= NDCR_ECC_EN;
-		if (info->ecc_bch)
-			nand_writel(info, NDECCCTRL, 0x1);
-	} else {
-		ndcr &= ~NDCR_ECC_EN;
-		if (info->ecc_bch)
-			nand_writel(info, NDECCCTRL, 0x0);
-	}
-
-	if (info->use_dma)
-		ndcr |= NDCR_DMA_EN;
-	else
-		ndcr &= ~NDCR_DMA_EN;
-
-	if (info->use_spare)
-		ndcr |= NDCR_SPARE_EN;
-	else
-		ndcr &= ~NDCR_SPARE_EN;
-
-	ndcr |= NDCR_ND_RUN;
-
-	/* clear status bits and run */
-	nand_writel(info, NDSR, NDSR_MASK);
-	nand_writel(info, NDCR, 0);
-	nand_writel(info, NDCR, ndcr);
-}
-
-static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
-{
-	uint32_t ndcr;
-	int timeout = NAND_STOP_DELAY;
-
-	/* wait RUN bit in NDCR become 0 */
-	ndcr = nand_readl(info, NDCR);
-	while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
-		ndcr = nand_readl(info, NDCR);
-		udelay(1);
-	}
-
-	if (timeout <= 0) {
-		ndcr &= ~NDCR_ND_RUN;
-		nand_writel(info, NDCR, ndcr);
-	}
-	if (info->dma_chan)
-		dmaengine_terminate_all(info->dma_chan);
-
-	/* clear status bits */
-	nand_writel(info, NDSR, NDSR_MASK);
-}
-
-static void __maybe_unused
-enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
-{
-	uint32_t ndcr;
-
-	ndcr = nand_readl(info, NDCR);
-	nand_writel(info, NDCR, ndcr & ~int_mask);
-}
-
-static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
-{
-	uint32_t ndcr;
-
-	ndcr = nand_readl(info, NDCR);
-	nand_writel(info, NDCR, ndcr | int_mask);
-}
-
-static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
-{
-	if (info->ecc_bch) {
-		u32 val;
-		int ret;
-
-		/*
-		 * According to the datasheet, when reading from NDDB
-		 * with BCH enabled, after each 32 bytes reads, we
-		 * have to make sure that the NDSR.RDDREQ bit is set.
-		 *
-		 * Drain the FIFO 8 32 bits reads at a time, and skip
-		 * the polling on the last read.
-		 */
-		while (len > 8) {
-			ioread32_rep(info->mmio_base + NDDB, data, 8);
-
-			ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
-							 val & NDSR_RDDREQ, 1000, 5000);
-			if (ret) {
-				dev_err(&info->pdev->dev,
-					"Timeout on RDDREQ while draining the FIFO\n");
-				return;
-			}
-
-			data += 32;
-			len -= 8;
-		}
-	}
-
-	ioread32_rep(info->mmio_base + NDDB, data, len);
-}
-
-static void handle_data_pio(struct pxa3xx_nand_info *info)
-{
-	switch (info->state) {
-	case STATE_PIO_WRITING:
-		if (info->step_chunk_size)
-			writesl(info->mmio_base + NDDB,
-				info->data_buff + info->data_buff_pos,
-				DIV_ROUND_UP(info->step_chunk_size, 4));
-
-		if (info->step_spare_size)
-			writesl(info->mmio_base + NDDB,
-				info->oob_buff + info->oob_buff_pos,
-				DIV_ROUND_UP(info->step_spare_size, 4));
-		break;
-	case STATE_PIO_READING:
-		if (info->step_chunk_size)
-			drain_fifo(info,
-				   info->data_buff + info->data_buff_pos,
-				   DIV_ROUND_UP(info->step_chunk_size, 4));
-
-		if (info->step_spare_size)
-			drain_fifo(info,
-				   info->oob_buff + info->oob_buff_pos,
-				   DIV_ROUND_UP(info->step_spare_size, 4));
-		break;
-	default:
-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
-				info->state);
-		BUG();
-	}
-
-	/* Update buffer pointers for multi-page read/write */
-	info->data_buff_pos += info->step_chunk_size;
-	info->oob_buff_pos += info->step_spare_size;
-}
-
-static void pxa3xx_nand_data_dma_irq(void *data)
-{
-	struct pxa3xx_nand_info *info = data;
-	struct dma_tx_state state;
-	enum dma_status status;
-
-	status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
-	if (likely(status == DMA_COMPLETE)) {
-		info->state = STATE_DMA_DONE;
-	} else {
-		dev_err(&info->pdev->dev, "DMA error on data channel\n");
-		info->retcode = ERR_DMABUSERR;
-	}
-	dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
-
-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
-	enable_int(info, NDCR_INT_MASK);
-}
-
-static void start_data_dma(struct pxa3xx_nand_info *info)
-{
-	enum dma_transfer_direction direction;
-	struct dma_async_tx_descriptor *tx;
-
-	switch (info->state) {
-	case STATE_DMA_WRITING:
-		info->dma_dir = DMA_TO_DEVICE;
-		direction = DMA_MEM_TO_DEV;
-		break;
-	case STATE_DMA_READING:
-		info->dma_dir = DMA_FROM_DEVICE;
-		direction = DMA_DEV_TO_MEM;
-		break;
-	default:
-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
-				info->state);
-		BUG();
-	}
-	info->sg.length = info->chunk_size;
-	if (info->use_spare)
-		info->sg.length += info->spare_size + info->ecc_size;
-	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
-
-	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
-				     DMA_PREP_INTERRUPT);
-	if (!tx) {
-		dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
-		return;
-	}
-	tx->callback = pxa3xx_nand_data_dma_irq;
-	tx->callback_param = info;
-	info->dma_cookie = dmaengine_submit(tx);
-	dma_async_issue_pending(info->dma_chan);
-	dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
-		__func__, direction, info->dma_cookie, info->sg.length);
-}
-
-static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
-{
-	struct pxa3xx_nand_info *info = data;
-
-	handle_data_pio(info);
-
-	info->state = STATE_CMD_DONE;
-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
-{
-	struct pxa3xx_nand_info *info = devid;
-	unsigned int status, is_completed = 0, is_ready = 0;
-	unsigned int ready, cmd_done;
-	irqreturn_t ret = IRQ_HANDLED;
-
-	if (info->cs == 0) {
-		ready           = NDSR_FLASH_RDY;
-		cmd_done        = NDSR_CS0_CMDD;
-	} else {
-		ready           = NDSR_RDY;
-		cmd_done        = NDSR_CS1_CMDD;
-	}
-
-	status = nand_readl(info, NDSR);
-
-	if (status & NDSR_UNCORERR)
-		info->retcode = ERR_UNCORERR;
-	if (status & NDSR_CORERR) {
-		info->retcode = ERR_CORERR;
-		if ((info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		     info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) &&
-		    info->ecc_bch)
-			info->ecc_err_cnt = NDSR_ERR_CNT(status);
-		else
-			info->ecc_err_cnt = 1;
-
-		/*
-		 * Each chunk composing a page is corrected independently,
-		 * and we need to store maximum number of corrected bitflips
-		 * to return it to the MTD layer in ecc.read_page().
-		 */
-		info->max_bitflips = max_t(unsigned int,
-					   info->max_bitflips,
-					   info->ecc_err_cnt);
-	}
-	if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
-		/* whether use dma to transfer data */
-		if (info->use_dma) {
-			disable_int(info, NDCR_INT_MASK);
-			info->state = (status & NDSR_RDDREQ) ?
-				      STATE_DMA_READING : STATE_DMA_WRITING;
-			start_data_dma(info);
-			goto NORMAL_IRQ_EXIT;
-		} else {
-			info->state = (status & NDSR_RDDREQ) ?
-				      STATE_PIO_READING : STATE_PIO_WRITING;
-			ret = IRQ_WAKE_THREAD;
-			goto NORMAL_IRQ_EXIT;
-		}
-	}
-	if (status & cmd_done) {
-		info->state = STATE_CMD_DONE;
-		is_completed = 1;
-	}
-	if (status & ready) {
-		info->state = STATE_READY;
-		is_ready = 1;
-	}
-
-	/*
-	 * Clear all status bit before issuing the next command, which
-	 * can and will alter the status bits and will deserve a new
-	 * interrupt on its own. This lets the controller exit the IRQ
-	 */
-	nand_writel(info, NDSR, status);
-
-	if (status & NDSR_WRCMDREQ) {
-		status &= ~NDSR_WRCMDREQ;
-		info->state = STATE_CMD_HANDLE;
-
-		/*
-		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
-		 * must be loaded by writing directly either 12 or 16
-		 * bytes directly to NDCB0, four bytes at a time.
-		 *
-		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
-		 * but each NDCBx register can be read.
-		 */
-		nand_writel(info, NDCB0, info->ndcb0);
-		nand_writel(info, NDCB0, info->ndcb1);
-		nand_writel(info, NDCB0, info->ndcb2);
-
-		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
-			nand_writel(info, NDCB0, info->ndcb3);
-	}
-
-	if (is_completed)
-		complete(&info->cmd_complete);
-	if (is_ready)
-		complete(&info->dev_ready);
-NORMAL_IRQ_EXIT:
-	return ret;
-}
-
-static inline int is_buf_blank(uint8_t *buf, size_t len)
-{
-	for (; len > 0; len--)
-		if (*buf++ != 0xff)
-			return 0;
-	return 1;
-}
-
-static void set_command_address(struct pxa3xx_nand_info *info,
-		unsigned int page_size, uint16_t column, int page_addr)
-{
-	/* small page addr setting */
-	if (page_size < PAGE_CHUNK_SIZE) {
-		info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
-				| (column & 0xFF);
-
-		info->ndcb2 = 0;
-	} else {
-		info->ndcb1 = ((page_addr & 0xFFFF) << 16)
-				| (column & 0xFFFF);
-
-		if (page_addr & 0xFF0000)
-			info->ndcb2 = (page_addr & 0xFF0000) >> 16;
-		else
-			info->ndcb2 = 0;
-	}
-}
-
-static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-
-	/* reset data and oob column point to handle data */
-	info->buf_start		= 0;
-	info->buf_count		= 0;
-	info->data_buff_pos	= 0;
-	info->oob_buff_pos	= 0;
-	info->step_chunk_size   = 0;
-	info->step_spare_size   = 0;
-	info->cur_chunk         = 0;
-	info->use_ecc		= 0;
-	info->use_spare		= 1;
-	info->retcode		= ERR_NONE;
-	info->ecc_err_cnt	= 0;
-	info->ndcb3		= 0;
-	info->need_wait		= 0;
-
-	switch (command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_PAGEPROG:
-		info->use_ecc = 1;
-		break;
-	case NAND_CMD_PARAM:
-		info->use_spare = 0;
-		break;
-	default:
-		info->ndcb1 = 0;
-		info->ndcb2 = 0;
-		break;
-	}
-
-	/*
-	 * If we are about to issue a read command, or about to set
-	 * the write address, then clean the data buffer.
-	 */
-	if (command == NAND_CMD_READ0 ||
-	    command == NAND_CMD_READOOB ||
-	    command == NAND_CMD_SEQIN) {
-
-		info->buf_count = mtd->writesize + mtd->oobsize;
-		memset(info->data_buff, 0xFF, info->buf_count);
-	}
-
-}
-
-static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
-		int ext_cmd_type, uint16_t column, int page_addr)
-{
-	int addr_cycle, exec_cmd;
-	struct pxa3xx_nand_host *host;
-	struct mtd_info *mtd;
-
-	host = info->host[info->cs];
-	mtd = nand_to_mtd(&host->chip);
-	addr_cycle = 0;
-	exec_cmd = 1;
-
-	if (info->cs != 0)
-		info->ndcb0 = NDCB0_CSEL;
-	else
-		info->ndcb0 = 0;
-
-	if (command == NAND_CMD_SEQIN)
-		exec_cmd = 0;
-
-	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
-				    + host->col_addr_cycles);
-
-	switch (command) {
-	case NAND_CMD_READOOB:
-	case NAND_CMD_READ0:
-		info->buf_start = column;
-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
-				| addr_cycle
-				| NAND_CMD_READ0;
-
-		if (command == NAND_CMD_READOOB)
-			info->buf_start += mtd->writesize;
-
-		if (info->cur_chunk < info->nfullchunks) {
-			info->step_chunk_size = info->chunk_size;
-			info->step_spare_size = info->spare_size;
-		} else {
-			info->step_chunk_size = info->last_chunk_size;
-			info->step_spare_size = info->last_spare_size;
-		}
-
-		/*
-		 * Multiple page read needs an 'extended command type' field,
-		 * which is either naked-read or last-read according to the
-		 * state.
-		 */
-		if (mtd->writesize == PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
-		} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
-					| NDCB0_LEN_OVRD
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-			info->ndcb3 = info->step_chunk_size +
-				info->step_spare_size;
-		}
-
-		set_command_address(info, mtd->writesize, column, page_addr);
-		break;
-
-	case NAND_CMD_SEQIN:
-
-		info->buf_start = column;
-		set_command_address(info, mtd->writesize, 0, page_addr);
-
-		/*
-		 * Multiple page programming needs to execute the initial
-		 * SEQIN command that sets the page address.
-		 */
-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
-				| addr_cycle
-				| command;
-			exec_cmd = 1;
-		}
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		if (is_buf_blank(info->data_buff,
-					(mtd->writesize + mtd->oobsize))) {
-			exec_cmd = 0;
-			break;
-		}
-
-		if (info->cur_chunk < info->nfullchunks) {
-			info->step_chunk_size = info->chunk_size;
-			info->step_spare_size = info->spare_size;
-		} else {
-			info->step_chunk_size = info->last_chunk_size;
-			info->step_spare_size = info->last_spare_size;
-		}
-
-		/* Second command setting for large pages */
-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			/*
-			 * Multiple page write uses the 'extended command'
-			 * field. This can be used to issue a command dispatch
-			 * or a naked-write depending on the current stage.
-			 */
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-					| NDCB0_LEN_OVRD
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-			info->ndcb3 = info->step_chunk_size +
-				      info->step_spare_size;
-
-			/*
-			 * This is the command dispatch that completes a chunked
-			 * page program operation.
-			 */
-			if (info->cur_chunk == info->ntotalchunks) {
-				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
-					| command;
-				info->ndcb1 = 0;
-				info->ndcb2 = 0;
-				info->ndcb3 = 0;
-			}
-		} else {
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-					| NDCB0_AUTO_RS
-					| NDCB0_ST_ROW_EN
-					| NDCB0_DBC
-					| (NAND_CMD_PAGEPROG << 8)
-					| NAND_CMD_SEQIN
-					| addr_cycle;
-		}
-		break;
-
-	case NAND_CMD_PARAM:
-		info->buf_count = INIT_BUFFER_SIZE;
-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
-				| NDCB0_ADDR_CYC(1)
-				| NDCB0_LEN_OVRD
-				| command;
-		info->ndcb1 = (column & 0xFF);
-		info->ndcb3 = INIT_BUFFER_SIZE;
-		info->step_chunk_size = INIT_BUFFER_SIZE;
-		break;
-
-	case NAND_CMD_READID:
-		info->buf_count = READ_ID_BYTES;
-		info->ndcb0 |= NDCB0_CMD_TYPE(3)
-				| NDCB0_ADDR_CYC(1)
-				| command;
-		info->ndcb1 = (column & 0xFF);
-
-		info->step_chunk_size = 8;
-		break;
-	case NAND_CMD_STATUS:
-		info->buf_count = 1;
-		info->ndcb0 |= NDCB0_CMD_TYPE(4)
-				| NDCB0_ADDR_CYC(1)
-				| command;
-
-		info->step_chunk_size = 8;
-		break;
-
-	case NAND_CMD_ERASE1:
-		info->ndcb0 |= NDCB0_CMD_TYPE(2)
-				| NDCB0_AUTO_RS
-				| NDCB0_ADDR_CYC(3)
-				| NDCB0_DBC
-				| (NAND_CMD_ERASE2 << 8)
-				| NAND_CMD_ERASE1;
-		info->ndcb1 = page_addr;
-		info->ndcb2 = 0;
-
-		break;
-	case NAND_CMD_RESET:
-		info->ndcb0 |= NDCB0_CMD_TYPE(5)
-				| command;
-
-		break;
-
-	case NAND_CMD_ERASE2:
-		exec_cmd = 0;
-		break;
-
-	default:
-		exec_cmd = 0;
-		dev_err(&info->pdev->dev, "non-supported command %x\n",
-				command);
-		break;
-	}
-
-	return exec_cmd;
-}
-
-static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-			 int column, int page_addr)
-{
-	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 exec_cmd;
-
-	/*
-	 * if this is a x16 device ,then convert the input
-	 * "byte" address into a "word" address appropriate
-	 * for indexing a word-oriented device
-	 */
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		column /= 2;
-
-	/*
-	 * There may be different NAND chip hooked to
-	 * different chip select, so check whether
-	 * chip select has been changed, if yes, reset the timing
-	 */
-	if (info->cs != host->cs) {
-		info->cs = host->cs;
-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
-	}
-
-	prepare_start_command(info, command);
-
-	info->state = STATE_PREPARED;
-	exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
-
-	if (exec_cmd) {
-		init_completion(&info->cmd_complete);
-		init_completion(&info->dev_ready);
-		info->need_wait = 1;
-		pxa3xx_nand_start(info);
-
-		if (!wait_for_completion_timeout(&info->cmd_complete,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
-			/* Stop State Machine for next command cycle */
-			pxa3xx_nand_stop(info);
-		}
-	}
-	info->state = STATE_IDLE;
-}
-
-static void nand_cmdfunc_extended(struct mtd_info *mtd,
-				  const unsigned command,
-				  int column, int page_addr)
-{
-	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 exec_cmd, ext_cmd_type;
-
-	/*
-	 * if this is a x16 device then convert the input
-	 * "byte" address into a "word" address appropriate
-	 * for indexing a word-oriented device
-	 */
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		column /= 2;
-
-	/*
-	 * There may be different NAND chip hooked to
-	 * different chip select, so check whether
-	 * chip select has been changed, if yes, reset the timing
-	 */
-	if (info->cs != host->cs) {
-		info->cs = host->cs;
-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
-	}
-
-	/* Select the extended command for the first command */
-	switch (command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-		ext_cmd_type = EXT_CMD_TYPE_MONO;
-		break;
-	case NAND_CMD_SEQIN:
-		ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
-		break;
-	case NAND_CMD_PAGEPROG:
-		ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
-		break;
-	default:
-		ext_cmd_type = 0;
-		break;
-	}
-
-	prepare_start_command(info, command);
-
-	/*
-	 * Prepare the "is ready" completion before starting a command
-	 * transaction sequence. If the command is not executed the
-	 * completion will be completed, see below.
-	 *
-	 * We can do that inside the loop because the command variable
-	 * is invariant and thus so is the exec_cmd.
-	 */
-	info->need_wait = 1;
-	init_completion(&info->dev_ready);
-	do {
-		info->state = STATE_PREPARED;
-
-		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
-					       column, page_addr);
-		if (!exec_cmd) {
-			info->need_wait = 0;
-			complete(&info->dev_ready);
-			break;
-		}
-
-		init_completion(&info->cmd_complete);
-		pxa3xx_nand_start(info);
-
-		if (!wait_for_completion_timeout(&info->cmd_complete,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
-			/* Stop State Machine for next command cycle */
-			pxa3xx_nand_stop(info);
-			break;
-		}
-
-		/* Only a few commands need several steps */
-		if (command != NAND_CMD_PAGEPROG &&
-		    command != NAND_CMD_READ0    &&
-		    command != NAND_CMD_READOOB)
-			break;
-
-		info->cur_chunk++;
-
-		/* Check if the sequence is complete */
-		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
-			break;
-
-		/*
-		 * After a splitted program command sequence has issued
-		 * the command dispatch, the command sequence is complete.
-		 */
-		if (info->cur_chunk == (info->ntotalchunks + 1) &&
-		    command == NAND_CMD_PAGEPROG &&
-		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
-			break;
-
-		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
-			/* Last read: issue a 'last naked read' */
-			if (info->cur_chunk == info->ntotalchunks - 1)
-				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
-			else
-				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
-
-		/*
-		 * If a splitted program command has no more data to transfer,
-		 * the command dispatch must be issued to complete.
-		 */
-		} else if (command == NAND_CMD_PAGEPROG &&
-			   info->cur_chunk == info->ntotalchunks) {
-				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
-		}
-	} while (1);
-
-	info->state = STATE_IDLE;
-}
-
-static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, const uint8_t *buf, int oob_required,
-		int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, uint8_t *buf, int oob_required,
-		int page)
-{
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	if (info->retcode == ERR_CORERR && info->use_ecc) {
-		mtd->ecc_stats.corrected += info->ecc_err_cnt;
-
-	} else if (info->retcode == ERR_UNCORERR) {
-		/*
-		 * for blank page (all 0xff), HW will calculate its ECC as
-		 * 0, which is different from the ECC information within
-		 * OOB, ignore such uncorrectable errors
-		 */
-		if (is_buf_blank(buf, mtd->writesize))
-			info->retcode = ERR_NONE;
-		else
-			mtd->ecc_stats.failed++;
-	}
-
-	return info->max_bitflips;
-}
-
-static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
-{
-	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;
-	char retval = 0xFF;
-
-	if (info->buf_start < info->buf_count)
-		/* Has just send a new command? */
-		retval = info->data_buff[info->buf_start++];
-
-	return retval;
-}
-
-static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
-{
-	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;
-	u16 retval = 0xFFFF;
-
-	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
-		retval = *((u16 *)(info->data_buff+info->buf_start));
-		info->buf_start += 2;
-	}
-	return retval;
-}
-
-static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	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 real_len = min_t(size_t, len, info->buf_count - info->buf_start);
-
-	memcpy(buf, info->data_buff + info->buf_start, real_len);
-	info->buf_start += real_len;
-}
-
-static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
-		const uint8_t *buf, int len)
-{
-	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 real_len = min_t(size_t, len, info->buf_count - info->buf_start);
-
-	memcpy(info->data_buff + info->buf_start, buf, real_len);
-	info->buf_start += real_len;
-}
-
-static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
-{
-	return;
-}
-
-static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
-{
-	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;
-
-	if (info->need_wait) {
-		info->need_wait = 0;
-		if (!wait_for_completion_timeout(&info->dev_ready,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Ready time out!!!\n");
-			return NAND_STATUS_FAIL;
-		}
-	}
-
-	/* pxa3xx_nand_send_command has waited for command complete */
-	if (this->state == FL_WRITING || this->state == FL_ERASING) {
-		if (info->retcode == ERR_NONE)
-			return 0;
-		else
-			return NAND_STATUS_FAIL;
-	}
-
-	return NAND_STATUS_READY;
-}
-
-static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	const struct nand_sdr_timings *timings;
-
-	/* Configure default flash values */
-	info->chunk_size = PAGE_CHUNK_SIZE;
-	info->reg_ndcr = 0x0; /* enable all interrupts */
-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
-	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
-	info->reg_ndcr |= NDCR_SPARE_EN;
-
-	/* use the common timing to make a try */
-	timings = onfi_async_timing_mode_to_sdr_timings(0);
-	if (IS_ERR(timings))
-		return PTR_ERR(timings);
-
-	pxa3xx_nand_set_sdr_timing(host, timings);
-	return 0;
-}
-
-static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
-	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
-	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
-}
-
-static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
-{
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	uint32_t ndcr = nand_readl(info, NDCR);
-
-	/* Set an initial chunk size */
-	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
-	info->reg_ndcr = ndcr &
-		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
-	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
-	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
-}
-
-static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
-{
-	struct platform_device *pdev = info->pdev;
-	struct dma_slave_config	config;
-	dma_cap_mask_t mask;
-	struct pxad_param param;
-	int ret;
-
-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-	if (info->data_buff == NULL)
-		return -ENOMEM;
-	if (use_dma == 0)
-		return 0;
-
-	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	sg_init_one(&info->sg, info->data_buff, info->buf_size);
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	param.prio = PXAD_PRIO_LOWEST;
-	param.drcmr = info->drcmr_dat;
-	info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
-							  &param, &pdev->dev,
-							  "data");
-	if (!info->dma_chan) {
-		dev_err(&pdev->dev, "unable to request data dma channel\n");
-		return -ENODEV;
-	}
-
-	memset(&config, 0, sizeof(config));
-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.src_addr = info->mmio_phys + NDDB;
-	config.dst_addr = info->mmio_phys + NDDB;
-	config.src_maxburst = 32;
-	config.dst_maxburst = 32;
-	ret = dmaengine_slave_config(info->dma_chan, &config);
-	if (ret < 0) {
-		dev_err(&info->pdev->dev,
-			"dma channel configuration failed: %d\n",
-			ret);
-		return ret;
-	}
-
-	/*
-	 * Now that DMA buffers are allocated we turn on
-	 * DMA proper for I/O operations.
-	 */
-	info->use_dma = 1;
-	return 0;
-}
-
-static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
-{
-	if (info->use_dma) {
-		dmaengine_terminate_all(info->dma_chan);
-		dma_release_channel(info->dma_chan);
-	}
-	kfree(info->data_buff);
-}
-
-static int pxa_ecc_init(struct pxa3xx_nand_info *info,
-			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;
-		info->chunk_size = 2048;
-		info->spare_size = 40;
-		info->ecc_size = 24;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = 512;
-		ecc->strength = 1;
-
-	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
-		info->nfullchunks = 1;
-		info->ntotalchunks = 1;
-		info->chunk_size = 512;
-		info->spare_size = 8;
-		info->ecc_size = 8;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = 512;
-		ecc->strength = 1;
-
-	/*
-	 * Required ECC: 4-bit correction per 512 bytes
-	 * Select: 16-bit correction per 2048 bytes
-	 */
-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 1;
-		info->ntotalchunks = 1;
-		info->chunk_size = 2048;
-		info->spare_size = 32;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-
-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 2;
-		info->ntotalchunks = 2;
-		info->chunk_size = 2048;
-		info->spare_size = 32;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-
-	/*
-	 * Required ECC: 8-bit correction per 512 bytes
-	 * Select: 16-bit correction per 1024 bytes
-	 */
-	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 4;
-		info->ntotalchunks = 5;
-		info->chunk_size = 1024;
-		info->spare_size = 0;
-		info->last_chunk_size = 0;
-		info->last_spare_size = 64;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-	} else {
-		dev_err(&info->pdev->dev,
-			"ECC strength %d at page size %d is not supported\n",
-			strength, page_size);
-		return -ENODEV;
-	}
-
-	dev_info(&info->pdev->dev, "ECC strength %d, ECC step size %d\n",
-		 ecc->strength, ecc->size);
-	return 0;
-}
-
-static int pxa3xx_nand_scan(struct mtd_info *mtd)
-{
-	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;
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	int ret;
-	uint16_t ecc_strength, ecc_step;
-
-	if (pdata->keep_config) {
-		pxa3xx_nand_detect_config(info);
-	} else {
-		ret = pxa3xx_nand_config_ident(info);
-		if (ret)
-			return ret;
-	}
-
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	/* Device detection must be done with ECC disabled */
-	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-	    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
-		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;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	if (!pdata->keep_config) {
-		ret = pxa3xx_nand_init(host);
-		if (ret) {
-			dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
-	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_NO_OOB_BBM;
-		chip->bbt_td = &bbt_main_descr;
-		chip->bbt_md = &bbt_mirror_descr;
-	}
-
-	/*
-	 * If the page size is bigger than the FIFO size, let's check
-	 * we are given the right variant and then switch to the extended
-	 * (aka splitted) command handling,
-	 */
-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) {
-			chip->cmdfunc = nand_cmdfunc_extended;
-		} else {
-			dev_err(&info->pdev->dev,
-				"unsupported page size on this variant\n");
-			return -ENODEV;
-		}
-	}
-
-	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;
-	}
-
-	/* Set default ECC strength requirements on non-ONFI devices */
-	if (ecc_strength < 1 && ecc_step < 1) {
-		ecc_strength = 1;
-		ecc_step = 512;
-	}
-
-	ret = pxa_ecc_init(info, mtd, ecc_strength,
-			   ecc_step, mtd->writesize);
-	if (ret)
-		return ret;
-
-	/* calculate addressing information */
-	if (mtd->writesize >= 2048)
-		host->col_addr_cycles = 2;
-	else
-		host->col_addr_cycles = 1;
-
-	/* release the initial buffer */
-	kfree(info->data_buff);
-
-	/* allocate the real data + oob buffer */
-	info->buf_size = mtd->writesize + mtd->oobsize;
-	ret = pxa3xx_nand_init_buff(info);
-	if (ret)
-		return ret;
-	info->oob_buff = info->data_buff + mtd->writesize;
-
-	if ((mtd->size >> chip->page_shift) > 65536)
-		host->row_addr_cycles = 3;
-	else
-		host->row_addr_cycles = 2;
-
-	if (!pdata->keep_config)
-		pxa3xx_nand_config_tail(info);
-
-	return nand_scan_tail(mtd);
-}
-
-static int alloc_nand_resource(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct pxa3xx_nand_platform_data *pdata;
-	struct pxa3xx_nand_info *info;
-	struct pxa3xx_nand_host *host;
-	struct nand_chip *chip = NULL;
-	struct mtd_info *mtd;
-	struct resource *r;
-	int ret, irq, cs;
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata->num_cs <= 0) {
-		dev_err(&pdev->dev, "invalid number of chip selects\n");
-		return -ENODEV;
-	}
-
-	info = devm_kzalloc(&pdev->dev,
-			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
-			    GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->pdev = pdev;
-	info->variant = pxa3xx_nand_get_variant(pdev);
-	for (cs = 0; cs < pdata->num_cs; cs++) {
-		host = (void *)&info[1] + sizeof(*host) * cs;
-		chip = &host->chip;
-		nand_set_controller_data(chip, host);
-		mtd = nand_to_mtd(chip);
-		info->host[cs] = host;
-		host->cs = cs;
-		host->info_data = info;
-		mtd->dev.parent = &pdev->dev;
-		/* FIXME: all chips use the same device tree partitions */
-		nand_set_flash_node(chip, np);
-
-		nand_set_controller_data(chip, host);
-		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
-		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
-		chip->controller        = &info->controller;
-		chip->waitfunc		= pxa3xx_nand_waitfunc;
-		chip->select_chip	= pxa3xx_nand_select_chip;
-		chip->read_word		= pxa3xx_nand_read_word;
-		chip->read_byte		= pxa3xx_nand_read_byte;
-		chip->read_buf		= pxa3xx_nand_read_buf;
-		chip->write_buf		= pxa3xx_nand_write_buf;
-		chip->options		|= NAND_NO_SUBPAGE_WRITE;
-		chip->cmdfunc		= nand_cmdfunc;
-		chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
-		chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
-	}
-
-	nand_hw_control_init(chip->controller);
-	info->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(info->clk)) {
-		ret = PTR_ERR(info->clk);
-		dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
-		return ret;
-	}
-	ret = clk_prepare_enable(info->clk);
-	if (ret < 0)
-		return ret;
-
-	if (!np && use_dma) {
-		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-		if (r == NULL) {
-			dev_err(&pdev->dev,
-				"no resource defined for data DMA\n");
-			ret = -ENXIO;
-			goto fail_disable_clk;
-		}
-		info->drcmr_dat = r->start;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "no IRQ resource defined\n");
-		ret = -ENXIO;
-		goto fail_disable_clk;
-	}
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-	if (IS_ERR(info->mmio_base)) {
-		ret = PTR_ERR(info->mmio_base);
-		dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
-		goto fail_disable_clk;
-	}
-	info->mmio_phys = r->start;
-
-	/* Allocate a buffer to allow flash detection */
-	info->buf_size = INIT_BUFFER_SIZE;
-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-	if (info->data_buff == NULL) {
-		ret = -ENOMEM;
-		goto fail_disable_clk;
-	}
-
-	/* initialize all interrupts to be disabled */
-	disable_int(info, NDSR_MASK);
-
-	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
-				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
-				   pdev->name, info);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
-		goto fail_free_buf;
-	}
-
-	platform_set_drvdata(pdev, info);
-
-	return 0;
-
-fail_free_buf:
-	free_irq(irq, info);
-	kfree(info->data_buff);
-fail_disable_clk:
-	clk_disable_unprepare(info->clk);
-	return ret;
-}
-
-static int pxa3xx_nand_remove(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
-	struct pxa3xx_nand_platform_data *pdata;
-	int irq, cs;
-
-	if (!info)
-		return 0;
-
-	pdata = dev_get_platdata(&pdev->dev);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq >= 0)
-		free_irq(irq, info);
-	pxa3xx_nand_free_buff(info);
-
-	/*
-	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
-	 * In order to prevent a lockup of the system bus, the DFI bus
-	 * arbitration is granted to SMC upon driver removal. This is done by
-	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
-	 * access to the bus anymore.
-	 */
-	nand_writel(info, NDCR,
-		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
-		    NFCV1_NDCR_ARB_CNTL);
-	clk_disable_unprepare(info->clk);
-
-	for (cs = 0; cs < pdata->num_cs; cs++)
-		nand_release(nand_to_mtd(&info->host[cs]->chip));
-	return 0;
-}
-
-static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_platform_data *pdata;
-	struct device_node *np = pdev->dev.of_node;
-	const struct of_device_id *of_id =
-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
-
-	if (!of_id)
-		return 0;
-
-	/*
-	 * Some SoCs like A7k/A8k need to enable manually the NAND
-	 * controller to avoid being bootloader dependent. This is done
-	 * through the use of a single bit in the System Functions registers.
-	 */
-	if (pxa3xx_nand_get_variant(pdev) == PXA3XX_NAND_VARIANT_ARMADA_8K) {
-		struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle(
-			pdev->dev.of_node, "marvell,system-controller");
-		u32 reg;
-
-		if (IS_ERR(sysctrl_base))
-			return PTR_ERR(sysctrl_base);
-
-		regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, &reg);
-		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN;
-		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
-	}
-
-	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
-
-	if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
-		pdata->enable_arbiter = 1;
-	if (of_get_property(np, "marvell,nand-keep-config", NULL))
-		pdata->keep_config = 1;
-	of_property_read_u32(np, "num-cs", &pdata->num_cs);
-
-	pdev->dev.platform_data = pdata;
-
-	return 0;
-}
-
-static int pxa3xx_nand_probe(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_platform_data *pdata;
-	struct pxa3xx_nand_info *info;
-	int ret, cs, probe_success, dma_available;
-
-	dma_available = IS_ENABLED(CONFIG_ARM) &&
-		(IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
-	if (use_dma && !dma_available) {
-		use_dma = 0;
-		dev_warn(&pdev->dev,
-			 "This platform can't do DMA on this device\n");
-	}
-
-	ret = pxa3xx_nand_probe_dt(pdev);
-	if (ret)
-		return ret;
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (!pdata) {
-		dev_err(&pdev->dev, "no platform data defined\n");
-		return -ENODEV;
-	}
-
-	ret = alloc_nand_resource(pdev);
-	if (ret)
-		return ret;
-
-	info = platform_get_drvdata(pdev);
-	probe_success = 0;
-	for (cs = 0; cs < pdata->num_cs; cs++) {
-		struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
-
-		/*
-		 * The mtd name matches the one used in 'mtdparts' kernel
-		 * parameter. This name cannot be changed or otherwise
-		 * user's mtd partitions configuration would get broken.
-		 */
-		mtd->name = "pxa3xx_nand-0";
-		info->cs = cs;
-		ret = pxa3xx_nand_scan(mtd);
-		if (ret) {
-			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
-				cs);
-			continue;
-		}
-
-		ret = mtd_device_register(mtd, pdata->parts[cs],
-					  pdata->nr_parts[cs]);
-		if (!ret)
-			probe_success = 1;
-	}
-
-	if (!probe_success) {
-		pxa3xx_nand_remove(pdev);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pxa3xx_nand_suspend(struct device *dev)
-{
-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
-
-	if (info->state) {
-		dev_err(dev, "driver busy, state = %d\n", info->state);
-		return -EAGAIN;
-	}
-
-	clk_disable(info->clk);
-	return 0;
-}
-
-static int pxa3xx_nand_resume(struct device *dev)
-{
-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
-	int ret;
-
-	ret = clk_enable(info->clk);
-	if (ret < 0)
-		return ret;
-
-	/* We don't want to handle interrupt without calling mtd routine */
-	disable_int(info, NDCR_INT_MASK);
-
-	/*
-	 * Directly set the chip select to a invalid value,
-	 * then the driver would reset the timing according
-	 * to current chip select at the beginning of cmdfunc
-	 */
-	info->cs = 0xff;
-
-	/*
-	 * As the spec says, the NDSR would be updated to 0x1800 when
-	 * doing the nand_clk disable/enable.
-	 * To prevent it damaging state machine of the driver, clear
-	 * all status before resume
-	 */
-	nand_writel(info, NDSR, NDSR_MASK);
-
-	return 0;
-}
-#else
-#define pxa3xx_nand_suspend	NULL
-#define pxa3xx_nand_resume	NULL
-#endif
-
-static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
-	.suspend	= pxa3xx_nand_suspend,
-	.resume		= pxa3xx_nand_resume,
-};
-
-static struct platform_driver pxa3xx_nand_driver = {
-	.driver = {
-		.name	= "pxa3xx-nand",
-		.of_match_table = pxa3xx_nand_dt_ids,
-		.pm	= &pxa3xx_nand_pm_ops,
-	},
-	.probe		= pxa3xx_nand_probe,
-	.remove		= pxa3xx_nand_remove,
-};
-
-module_platform_driver(pxa3xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("PXA3xx NAND controller driver");
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 04/12] dt-bindings: mtd: remove pxa3xx NAND controller documentation
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (2 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 03/12] mtd: nand: replace pxa3xx_nand driver by its rework called marvell_nand Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 05/12] mtd: nand: remove useless fields from pxa3xx NAND platform data Miquel Raynal
                     ` (9 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

The deprecated pxa3xx_nand.c driver does not exist anymore, it has been
replaced by marvell_nand.c which has its own up-to-date documentation.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 .../devicetree/bindings/mtd/pxa3xx-nand.txt        | 50 ----------------------
 1 file changed, 50 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt

diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
deleted file mode 100644
index d4ee4da58463..000000000000
--- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-PXA3xx NAND DT bindings
-
-Required properties:
-
- - compatible:		Should be set to one of the following:
-			marvell,pxa3xx-nand
-			marvell,armada370-nand
-			marvell,armada-8k-nand
- - reg: 		The register base for the controller
- - interrupts:		The interrupt to map
- - #address-cells:	Set to <1> if the node includes partitions
- - marvell,system-controller: Set to retrieve the syscon node that handles
-			NAND controller related registers (only required
-			with marvell,armada-8k-nand compatible).
-
-Optional properties:
-
- - dmas:			dma data channel, see dma.txt binding doc
- - marvell,nand-enable-arbiter:	Set to enable the bus arbiter
- - marvell,nand-keep-config:	Set to keep the NAND controller config as set
-				by the bootloader
- - num-cs:			Number of chipselect lines to use
- - nand-on-flash-bbt: 		boolean to enable on flash bbt option if
-				not present false
- - nand-ecc-strength:           number of bits to correct per ECC step
- - nand-ecc-step-size:          number of data bytes covered by a single ECC step
-
-The following ECC strength and step size are currently supported:
-
- - nand-ecc-strength = <1>, nand-ecc-step-size = <512>
- - nand-ecc-strength = <4>, nand-ecc-step-size = <512>
- - nand-ecc-strength = <8>, nand-ecc-step-size = <512>
-
-Example:
-
-	nand0: nand@43100000 {
-		compatible = "marvell,pxa3xx-nand";
-		reg = <0x43100000 90>;
-		interrupts = <45>;
-		dmas = <&pdma 97 0>;
-		dma-names = "data";
-		#address-cells = <1>;
-
-		marvell,nand-enable-arbiter;
-		marvell,nand-keep-config;
-		num-cs = <1>;
-
-		/* partitions (optional) */
-	};
-
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 05/12] mtd: nand: remove useless fields from pxa3xx NAND platform data
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (3 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 04/12] dt-bindings: mtd: remove pxa3xx NAND controller documentation Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 06/12] ARM: dts: armada-370-xp: use reworked NAND controller driver Miquel Raynal
                     ` (8 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

The "enable arbiter" bit is available only for pxa3xx based platforms
but it was experimentally shown that even if this bit is reserved,
some Marvell platforms (64-bit) actually need it to be set. The driver
always set this bit regardless of this property, which is harmless.
Then this property is not needed.

The "num_cs" field is always 1 and for a good reason, the old driver
(pxa3xx_nand.c) could only handle one. The new driver that replaces it
(marvell_nand.c) can handle more, but better use device tree for such
description. As there is only one available chip select, there is no
need for an array of partitions neither an array of partition numbers.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/mach-pxa/cm-x300.c                   |  6 ++--
 arch/arm/mach-pxa/colibri-pxa3xx.c            |  6 ++--
 arch/arm/mach-pxa/littleton.c                 |  6 ++--
 arch/arm/mach-pxa/mxm8x10.c                   |  6 ++--
 arch/arm/mach-pxa/raumfeld.c                  |  6 ++--
 arch/arm/mach-pxa/zylonite.c                  |  6 ++--
 drivers/mtd/nand/marvell_nand.c               |  3 +-
 include/linux/platform_data/mtd-nand-pxa3xx.h | 43 ++++++++-------------------
 8 files changed, 25 insertions(+), 57 deletions(-)

diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 89326378dabf..23bb273f3ff3 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -429,11 +429,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
-	.enable_arbiter	= 1,
 	.keep_config	= 1,
-	.num_cs		= 1,
-	.parts[0]	= cm_x300_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(cm_x300_nand_partitions),
+	.parts		= cm_x300_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(cm_x300_nand_partitions),
 };
 
 static void __init cm_x300_init_nand(void)
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index c9c36f707555..adec6e013fe6 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -138,11 +138,9 @@ static struct mtd_partition colibri_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data colibri_nand_info = {
-	.enable_arbiter	= 1,
 	.keep_config	= 1,
-	.num_cs		= 1,
-	.parts[0]	= colibri_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(colibri_nand_partitions),
+	.parts		= colibri_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(colibri_nand_partitions),
 };
 
 void __init colibri_pxa3xx_init_nand(void)
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 898961be36db..7e120e884165 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -328,10 +328,8 @@ static struct mtd_partition littleton_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data littleton_nand_info = {
-	.enable_arbiter	= 1,
-	.num_cs		= 1,
-	.parts[0]	= littleton_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(littleton_nand_partitions),
+	.parts		= littleton_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(littleton_nand_partitions),
 };
 
 static void __init littleton_init_nand(void)
diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c
index 7d7aab20b70a..328689052668 100644
--- a/arch/arm/mach-pxa/mxm8x10.c
+++ b/arch/arm/mach-pxa/mxm8x10.c
@@ -389,11 +389,9 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = {
-	.enable_arbiter	= 1,
 	.keep_config	= 1,
-	.num_cs		= 1,
-	.parts[0]	= mxm_8x10_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(mxm_8x10_nand_partitions)
+	.parts		= mxm_8x10_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(mxm_8x10_nand_partitions)
 };
 
 static void __init mxm_8x10_nand_init(void)
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 9d662fed03ec..af72e79a7ffa 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -346,11 +346,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data raumfeld_nand_info = {
-	.enable_arbiter	= 1,
 	.keep_config	= 1,
-	.num_cs		= 1,
-	.parts[0]	= raumfeld_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(raumfeld_nand_partitions),
+	.parts		= raumfeld_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(raumfeld_nand_partitions),
 };
 
 /**
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index a4577118d518..0534949d63f6 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -376,10 +376,8 @@ static struct mtd_partition zylonite_nand_partitions[] = {
 };
 
 static struct pxa3xx_nand_platform_data zylonite_nand_info = {
-	.enable_arbiter	= 1,
-	.num_cs		= 1,
-	.parts[0]	= zylonite_nand_partitions,
-	.nr_parts[0]	= ARRAY_SIZE(zylonite_nand_partitions),
+	.parts		= zylonite_nand_partitions,
+	.nr_parts	= ARRAY_SIZE(zylonite_nand_partitions),
 };
 
 static void __init zylonite_init_nand(void)
diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c
index 2525d9b2f4fa..75fbb3ea4977 100644
--- a/drivers/mtd/nand/marvell_nand.c
+++ b/drivers/mtd/nand/marvell_nand.c
@@ -2579,8 +2579,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
 
 	if (pdata)
 		/* Legacy bindings support only one chip */
-		ret = mtd_device_register(mtd, pdata->parts[0],
-					  pdata->nr_parts[0]);
+		ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
 	else
 		ret = mtd_device_register(mtd, NULL, 0);
 	if (ret) {
diff --git a/include/linux/platform_data/mtd-nand-pxa3xx.h b/include/linux/platform_data/mtd-nand-pxa3xx.h
index b42ad83cbc20..4fd0f592a2d2 100644
--- a/include/linux/platform_data/mtd-nand-pxa3xx.h
+++ b/include/linux/platform_data/mtd-nand-pxa3xx.h
@@ -6,41 +6,22 @@
 #include <linux/mtd/partitions.h>
 
 /*
- * Current pxa3xx_nand controller has two chip select which
- * both be workable.
- *
- * Notice should be taken that:
- * When you want to use this feature, you should not enable the
- * keep configuration feature, for two chip select could be
- * attached with different nand chip. The different page size
- * and timing requirement make the keep configuration impossible.
+ * Current pxa3xx_nand controller has two chip select which both be workable but
+ * historically all platforms remaining on platform data used only one. Switch
+ * to device tree if you need more.
  */
-
-/* The max num of chip select current support */
-#define NUM_CHIP_SELECT		(2)
 struct pxa3xx_nand_platform_data {
-
-	/* the data flash bus is shared between the Static Memory
-	 * Controller and the Data Flash Controller,  the arbiter
-	 * controls the ownership of the bus
-	 */
-	int	enable_arbiter;
-
-	/* allow platform code to keep OBM/bootloader defined NFC config */
-	int	keep_config;
-
-	/* indicate how many chip selects will be used */
-	int	num_cs;
-
-	/* use an flash-based bad block table */
-	bool	flash_bbt;
-
-	/* requested ECC strength and ECC step size */
+	/* Keep OBM/bootloader NFC timing configuration */
+	bool keep_config;
+	/* Use a flash-based bad block table */
+	bool flash_bbt;
+	/* Requested ECC strength and ECC step size */
 	int ecc_strength, ecc_step_size;
-
-	const struct mtd_partition		*parts[NUM_CHIP_SELECT];
-	unsigned int				nr_parts[NUM_CHIP_SELECT];
+	/* Partitions */
+	const struct mtd_partition *parts;
+	unsigned int nr_parts;
 };
 
 extern void pxa3xx_set_nand_info(struct pxa3xx_nand_platform_data *info);
+
 #endif /* __ASM_ARCH_PXA3XX_NAND_H */
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 06/12] ARM: dts: armada-370-xp: use reworked NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (4 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 05/12] mtd: nand: remove useless fields from pxa3xx NAND platform data Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 07/12] ARM: dts: armada-375: " Miquel Raynal
                     ` (7 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore
as the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/boot/dts/armada-370-db.dts                |  57 ++++----
 arch/arm/boot/dts/armada-370-dlink-dns327l.dts     | 120 ++++++++--------
 arch/arm/boot/dts/armada-370-mirabox.dts           |  51 ++++---
 arch/arm/boot/dts/armada-370-netgear-rn102.dts     |  90 ++++++------
 arch/arm/boot/dts/armada-370-netgear-rn104.dts     |  90 ++++++------
 arch/arm/boot/dts/armada-370-rd.dts                |  52 ++++---
 arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi |  64 +++++----
 arch/arm/boot/dts/armada-370-xp.dtsi               |   6 +-
 arch/arm/boot/dts/armada-xp-db-dxbc2.dts           |   2 +-
 arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts      |   2 +-
 arch/arm/boot/dts/armada-xp-db.dts                 |   2 +-
 arch/arm/boot/dts/armada-xp-gp.dts                 |   2 +-
 arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts    |   2 +-
 arch/arm/boot/dts/armada-xp-linksys-mamba.dts      | 156 +++++++++++----------
 arch/arm/boot/dts/armada-xp-netgear-rn2120.dts     |  90 ++++++------
 15 files changed, 434 insertions(+), 352 deletions(-)

diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index c4eef7323367..640f87a11834 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -142,33 +142,6 @@
 			usb@51000 {
 				status = "okay";
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				partitions {
-					compatible = "fixed-partitions";
-					#address-cells = <1>;
-					#size-cells = <1>;
-
-					partition@0 {
-						label = "U-Boot";
-						reg = <0 0x800000>;
-					};
-					partition@800000 {
-						label = "Linux";
-						reg = <0x800000 0x800000>;
-					};
-					partition@1000000 {
-						label = "Filesystem";
-						reg = <0x1000000 0x3f000000>;
-					};
-				};
-			};
 		};
 	};
 
@@ -276,3 +249,33 @@
 	};
 };
 
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
index db7f3aa38670..bb9be4d2b17e 100644
--- a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
+++ b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
@@ -81,61 +81,6 @@
 			usb@50000 {
 				status = "okay";
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					/* 1.0 MiB */
-					reg = <0x0000000 0x100000>;
-					read-only;
-				};
-
-				partition@100000 {
-					label = "u-boot-env";
-					/* 128 KiB */
-					reg = <0x100000 0x20000>;
-					read-only;
-				};
-
-				partition@120000 {
-					label = "uImage";
-					/* 7 MiB */
-					reg = <0x120000 0x700000>;
-				};
-
-				partition@820000 {
-					label = "ubifs";
-					/* ~ 84 MiB */
-					reg = <0x820000 0x54e0000>;
-				};
-
-				/* Hardcoded into stock bootloader */
-				partition@5d00000 {
-					label = "failsafe-uImage";
-					/* 5 MiB */
-					reg = <0x5d00000 0x500000>;
-				};
-
-				partition@6200000 {
-					label = "failsafe-fs";
-					/* 29 MiB */
-					reg = <0x6200000 0x1d00000>;
-				};
-
-				partition@7f00000 {
-					label = "bbt";
-					/* 1 MiB for BBT */
-					reg = <0x7f00000 0x100000>;
-				};
-			};
 		};
 	};
 
@@ -356,3 +301,68 @@
 	clock-frequency = <100000>;
 	status = "okay";
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				/* 1.0 MiB */
+				reg = <0x0000000 0x100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "u-boot-env";
+				/* 128 KiB */
+				reg = <0x100000 0x20000>;
+				read-only;
+			};
+
+			partition@120000 {
+				label = "uImage";
+				/* 7 MiB */
+				reg = <0x120000 0x700000>;
+			};
+
+			partition@820000 {
+				label = "ubifs";
+				/* ~ 84 MiB */
+				reg = <0x820000 0x54e0000>;
+			};
+
+			/* Hardcoded into stock bootloader */
+			partition@5d00000 {
+				label = "failsafe-uImage";
+				/* 5 MiB */
+				reg = <0x5d00000 0x500000>;
+			};
+
+			partition@6200000 {
+				label = "failsafe-fs";
+				/* 29 MiB */
+				reg = <0x6200000 0x1d00000>;
+			};
+
+			partition@7f00000 {
+				label = "bbt";
+				/* 1 MiB for BBT */
+				reg = <0x7f00000 0x100000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 702f58c9642d..af4db48ca2eb 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -145,27 +145,6 @@
 					reg = <0x25>;
 				};
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				partition@0 {
-					label = "U-Boot";
-					reg = <0 0x400000>;
-				};
-				partition@400000 {
-					label = "Linux";
-					reg = <0x400000 0x400000>;
-				};
-				partition@800000 {
-					label = "Filesystem";
-					reg = <0x800000 0x3f800000>;
-				};
-			};
 		};
 	};
 };
@@ -210,3 +189,33 @@
 	};
 };
 
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x400000>;
+			};
+			partition@400000 {
+				label = "Linux";
+				reg = <0x400000 0x400000>;
+			};
+			partition@800000 {
+				label = "Filesystem";
+				reg = <0x800000 0x3f800000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index b1a96e95e921..01bbb7d21cbc 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -118,46 +118,6 @@
 					pwm_polarity = <0>;
 				};
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				/* Use Hardware BCH ECC */
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					reg = <0x0000000 0x180000>;  /* 1.5MB */
-					read-only;
-				};
-
-				partition@180000 {
-					label = "u-boot-env";
-					reg = <0x180000 0x20000>;    /* 128KB */
-					read-only;
-				};
-
-				partition@200000 {
-					label = "uImage";
-					reg = <0x0200000 0x600000>;    /* 6MB */
-				};
-
-				partition@800000 {
-					label = "minirootfs";
-					reg = <0x0800000 0x400000>;    /* 4MB */
-				};
-
-				/* Last MB is for the BBT, i.e. not writable */
-				partition@c00000 {
-					label = "ubifs";
-					reg = <0x0c00000 0x7400000>; /* 116MB */
-				};
-			};
 		};
 	};
 
@@ -301,3 +261,53 @@
 		marvell,function = "gpio";
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		/* Use Hardware BCH ECC */
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x180000>;  /* 1.5MB */
+				read-only;
+			};
+
+			partition@180000 {
+				label = "u-boot-env";
+				reg = <0x180000 0x20000>;    /* 128KB */
+				read-only;
+			};
+
+			partition@200000 {
+				label = "uImage";
+				reg = <0x0200000 0x600000>;    /* 6MB */
+			};
+
+			partition@800000 {
+				label = "minirootfs";
+				reg = <0x0800000 0x400000>;    /* 4MB */
+			};
+
+			/* Last MB is for the BBT, i.e. not writable */
+			partition@c00000 {
+				label = "ubifs";
+				reg = <0x0c00000 0x7400000>; /* 116MB */
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index d67e7aa42b54..725181300575 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -127,46 +127,6 @@
 					reg = <0x23>;
 				};
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				/* Use Hardware BCH ECC */
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					reg = <0x0000000 0x180000>;  /* 1.5MB */
-					read-only;
-				};
-
-				partition@180000 {
-					label = "u-boot-env";
-					reg = <0x180000 0x20000>;    /* 128KB */
-					read-only;
-				};
-
-				partition@200000 {
-					label = "uImage";
-					reg = <0x0200000 0x600000>;    /* 6MB */
-				};
-
-				partition@800000 {
-					label = "minirootfs";
-					reg = <0x0800000 0x400000>;    /* 4MB */
-				};
-
-				/* Last MB is for the BBT, i.e. not writable */
-				partition@c00000 {
-					label = "ubifs";
-					reg = <0x0c00000 0x7400000>; /* 116MB */
-				};
-			};
 		};
 	};
 
@@ -313,3 +273,53 @@
 		marvell,function = "gpio";
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		/* Use Hardware BCH ECC */
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x180000>;  /* 1.5MB */
+				read-only;
+			};
+
+			partition@180000 {
+				label = "u-boot-env";
+				reg = <0x180000 0x20000>;    /* 128KB */
+				read-only;
+			};
+
+			partition@200000 {
+				label = "uImage";
+				reg = <0x0200000 0x600000>;    /* 6MB */
+			};
+
+			partition@800000 {
+				label = "minirootfs";
+				reg = <0x0800000 0x400000>;    /* 4MB */
+			};
+
+			/* Last MB is for the BBT, i.e. not writable */
+			partition@c00000 {
+				label = "ubifs";
+				reg = <0x0c00000 0x7400000>; /* 116MB */
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index 8b2fa9a49967..4301867bc973 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -148,27 +148,6 @@
 					default-state = "keep";
 				};
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				partition@0 {
-					label = "U-Boot";
-					reg = <0 0x800000>;
-				};
-				partition@800000 {
-					label = "Linux";
-					reg = <0x800000 0x800000>;
-				};
-				partition@1000000 {
-					label = "Filesystem";
-					reg = <0x1000000 0x3f000000>;
-				};
-			};
 		};
 	};
 
@@ -293,3 +272,34 @@
 		marvell,function = "gpio";
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
index e9a5b952afc0..b13d18fad40a 100644
--- a/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
@@ -69,33 +69,6 @@
 					interrupts = <110>;
 				};
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					reg = <0x0 0x300000>;
-				};
-				partition@300000 {
-					label = "device-tree";
-					reg = <0x300000 0x20000>;
-				};
-				partition@320000 {
-					label = "linux";
-					reg = <0x320000 0x2000000>;
-				};
-				partition@2320000 {
-					label = "rootfs";
-					reg = <0x2320000 0xdce0000>;
-				};
-			};
 		};
 
 	};
@@ -230,3 +203,40 @@
 		marvell,function = "gpio";
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0 0x300000>;
+			};
+			partition@300000 {
+				label = "device-tree";
+				reg = <0x300000 0x20000>;
+			};
+			partition@320000 {
+				label = "linux";
+				reg = <0x320000 0x2000000>;
+			};
+			partition@2320000 {
+				label = "rootfs";
+				reg = <0x2320000 0xdce0000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 09495e87b038..b6bead81c438 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -281,11 +281,11 @@
 				status = "disabled";
 			};
 
-			nand: nand@d0000 {
-				compatible = "marvell,armada370-nand";
+			nand_controller: nand-controller@d0000 {
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <113>;
 				clocks = <&coredivclk 0>;
 				status = "disabled";
diff --git a/arch/arm/boot/dts/armada-xp-db-dxbc2.dts b/arch/arm/boot/dts/armada-xp-db-dxbc2.dts
index 1b1ff17fdd9c..eb63cc8bcacc 100644
--- a/arch/arm/boot/dts/armada-xp-db-dxbc2.dts
+++ b/arch/arm/boot/dts/armada-xp-db-dxbc2.dts
@@ -107,9 +107,9 @@
 
 &nand {
 	status = "okay";
+	label = "pxa3xx_nand-0";
 	num-cs = <1>;
 	marvell,nand-keep-config;
-	marvell,nand-enable-arbiter;
 	nand-on-flash-bbt;
 	nand-ecc-strength = <4>;
 	nand-ecc-step-size = <512>;
diff --git a/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts b/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts
index 06fce35d7491..ee830687c2a8 100644
--- a/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts
+++ b/arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts
@@ -106,9 +106,9 @@
 
 &nand {
 	status = "okay";
+	label = "pxa3xx_nand-0";
 	num-cs = <1>;
 	marvell,nand-keep-config;
-	marvell,nand-enable-arbiter;
 	nand-on-flash-bbt;
 	nand-ecc-strength = <4>;
 	nand-ecc-step-size = <512>;
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 065282c21789..6acf9cd65f5a 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -182,9 +182,9 @@
 
 			nand@d0000 {
 				status = "okay";
+				label = "pxa3xx_nand-0";
 				num-cs = <1>;
 				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
 				nand-on-flash-bbt;
 
 				partitions {
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index ac9eab8ac186..9f3317cd4773 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -199,9 +199,9 @@
 
 			nand@d0000 {
 				status = "okay";
+				label = "pxa3xx_nand-0";
 				num-cs = <1>;
 				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
 				nand-on-flash-bbt;
 			};
 		};
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
index ce0afba1ce58..398fe027b2a7 100644
--- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -120,9 +120,9 @@
 
 			nand@d0000 {
 				status = "okay";
+				label = "pxa3xx_nand-0";
 				num-cs = <1>;
 				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
 				nand-on-flash-bbt;
 
 				partitions {
diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 6d705f518254..4c09314a3260 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -196,79 +196,6 @@
 			bm@c8000 {
 				status = "okay";
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					reg = <0x0000000 0x100000>;  /* 1MB */
-					read-only;
-				};
-
-				partition@100000 {
-					label = "u_env";
-					reg = <0x100000 0x40000>;    /* 256KB */
-				};
-
-				partition@140000 {
-					label = "s_env";
-					reg = <0x140000 0x40000>;    /* 256KB */
-				};
-
-				partition@900000 {
-					label = "devinfo";
-					reg = <0x900000 0x100000>;   /* 1MB */
-					read-only;
-				};
-
-				/* kernel1 overlaps with rootfs1 by design */
-				partition@a00000 {
-					label = "kernel1";
-					reg = <0xa00000 0x2800000>;  /* 40MB */
-				};
-
-				partition@d00000 {
-					label = "rootfs1";
-					reg = <0xd00000 0x2500000>;  /* 37MB */
-				};
-
-				/* kernel2 overlaps with rootfs2 by design */
-				partition@3200000 {
-					label = "kernel2";
-					reg = <0x3200000 0x2800000>; /* 40MB */
-				};
-
-				partition@3500000 {
-					label = "rootfs2";
-					reg = <0x3500000 0x2500000>; /* 37MB */
-				};
-
-				/*
-				 * 38MB, last MB is for the BBT, not writable
-				 */
-				partition@5a00000 {
-					label = "syscfg";
-					reg = <0x5a00000 0x2600000>;
-				};
-
-				/*
-				 * Unused area between "s_env" and "devinfo".
-				 * Moved here because otherwise the renumbered
-				 * partitions would break the bootloader
-				 * supplied bootargs
-				 */
-				partition@180000 {
-					label = "unused_area";
-					reg = <0x180000 0x780000>;   /* 7.5MB */
-				};
-			};
 		};
 
 		bm-bppi {
@@ -465,3 +392,86 @@
 		};
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x100000>;  /* 1MB */
+				read-only;
+			};
+
+			partition@100000 {
+				label = "u_env";
+				reg = <0x100000 0x40000>;    /* 256KB */
+			};
+
+			partition@140000 {
+				label = "s_env";
+				reg = <0x140000 0x40000>;    /* 256KB */
+			};
+
+			partition@900000 {
+				label = "devinfo";
+				reg = <0x900000 0x100000>;   /* 1MB */
+				read-only;
+			};
+
+			/* kernel1 overlaps with rootfs1 by design */
+			partition@a00000 {
+				label = "kernel1";
+				reg = <0xa00000 0x2800000>;  /* 40MB */
+			};
+
+			partition@d00000 {
+				label = "rootfs1";
+				reg = <0xd00000 0x2500000>;  /* 37MB */
+			};
+
+			/* kernel2 overlaps with rootfs2 by design */
+			partition@3200000 {
+				label = "kernel2";
+				reg = <0x3200000 0x2800000>; /* 40MB */
+			};
+
+			partition@3500000 {
+				label = "rootfs2";
+				reg = <0x3500000 0x2500000>; /* 37MB */
+			};
+
+			/*
+			 * 38MB, last MB is for the BBT, not writable
+			 */
+			partition@5a00000 {
+				label = "syscfg";
+				reg = <0x5a00000 0x2600000>;
+			};
+
+			/*
+			 * Unused area between "s_env" and "devinfo".
+			 * Moved here because otherwise the renumbered
+			 * partitions would break the bootloader
+			 * supplied bootargs
+			 */
+			partition@180000 {
+				label = "unused_area";
+				reg = <0x180000 0x780000>;   /* 7.5MB */
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 40c6fe21e720..e9e4c7a8fba9 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -154,46 +154,6 @@
 				nr-ports = <2>;
 				status = "okay";
 			};
-
-			nand@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				/* Use Hardware BCH ECC */
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "u-boot";
-					reg = <0x0000000 0x180000>;  /* 1.5MB */
-					read-only;
-				};
-
-				partition@180000 {
-					label = "u-boot-env";
-					reg = <0x180000 0x20000>;    /* 128KB */
-					read-only;
-				};
-
-				partition@200000 {
-					label = "uImage";
-					reg = <0x0200000 0x600000>;    /* 6MB */
-				};
-
-				partition@800000 {
-					label = "minirootfs";
-					reg = <0x0800000 0x400000>;    /* 4MB */
-				};
-
-				/* Last MB is for the BBT, i.e. not writable */
-				partition@c00000 {
-					label = "ubifs";
-					reg = <0x0c00000 0x7400000>; /* 116MB */
-				};
-			};
 		};
 	};
 
@@ -382,3 +342,53 @@
 		marvell,function = "gpio";
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+
+		/* Use Hardware BCH ECC */
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "u-boot";
+				reg = <0x0000000 0x180000>;  /* 1.5MB */
+				read-only;
+			};
+
+			partition@180000 {
+				label = "u-boot-env";
+				reg = <0x180000 0x20000>;    /* 128KB */
+				read-only;
+			};
+
+			partition@200000 {
+				label = "uImage";
+				reg = <0x0200000 0x600000>;    /* 6MB */
+			};
+
+			partition@800000 {
+				label = "minirootfs";
+				reg = <0x0800000 0x400000>;    /* 4MB */
+			};
+
+			/* Last MB is for the BBT, i.e. not writable */
+			partition@c00000 {
+				label = "ubifs";
+				reg = <0x0c00000 0x7400000>; /* 116MB */
+			};
+		};
+	};
+};
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 07/12] ARM: dts: armada-375: use reworked NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (5 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 06/12] ARM: dts: armada-370-xp: use reworked NAND controller driver Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 08/12] ARM: dts: armada-38x: " Miquel Raynal
                     ` (6 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore
as the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/boot/dts/armada-375-db.dts | 50 ++++++++++++++++++++++---------------
 arch/arm/boot/dts/armada-375.dtsi   |  6 ++---
 2 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts
index bcdbb8ba1d65..d33cca4e315d 100644
--- a/arch/arm/boot/dts/armada-375-db.dts
+++ b/arch/arm/boot/dts/armada-375-db.dts
@@ -140,28 +140,38 @@
 	nr-ports = <2>;
 };
 
-&nand {
+&nand_controller {
+	status = "okay";
 	pinctrl-0 = <&nand_pins>;
 	pinctrl-names = "default";
-	status = "okay";
-	num-cs = <1>;
-	marvell,nand-keep-config;
-	marvell,nand-enable-arbiter;
-	nand-on-flash-bbt;
-	nand-ecc-strength = <4>;
-	nand-ecc-step-size = <512>;
-
-	partition@0 {
-		label = "U-Boot";
-		reg = <0 0x800000>;
-	};
-	partition@800000 {
-		label = "Linux";
-		reg = <0x800000 0x800000>;
-	};
-	partition@1000000 {
-		label = "Filesystem";
-		reg = <0x1000000 0x3f000000>;
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index 2cb1bcd30976..46471173c7c1 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -539,11 +539,11 @@
 				status = "disabled";
 			};
 
-			nand: nand@d0000 {
-				compatible = "marvell,armada370-nand";
+			nand_controller: nand-controller@d0000 {
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&gateclk 11>;
 				status = "disabled";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 08/12] ARM: dts: armada-38x: use reworked NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (6 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 07/12] ARM: dts: armada-375: " Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 09/12] ARM: dts: armada-39x: " Miquel Raynal
                     ` (5 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/boot/dts/armada-385-db-ap.dts          |  69 ++++++------
 arch/arm/boot/dts/armada-385-linksys-caiman.dts | 129 +++++++++++-----------
 arch/arm/boot/dts/armada-385-linksys-cobra.dts  | 129 +++++++++++-----------
 arch/arm/boot/dts/armada-385-linksys-rango.dts  | 141 ++++++++++++------------
 arch/arm/boot/dts/armada-385-linksys-shelby.dts | 129 +++++++++++-----------
 arch/arm/boot/dts/armada-385-linksys.dtsi       |  16 ++-
 arch/arm/boot/dts/armada-388-db.dts             |  55 +++++----
 arch/arm/boot/dts/armada-38x.dtsi               |   6 +-
 8 files changed, 356 insertions(+), 318 deletions(-)

diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
index 25d2d720dc0e..c741708dabdb 100644
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -166,39 +166,6 @@
 				status = "okay";
 			};
 
-			nfc: flash@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-
-				partitions {
-					compatible = "fixed-partitions";
-					#address-cells = <1>;
-					#size-cells = <1>;
-
-					partition@0 {
-						label = "U-Boot";
-						reg = <0x00000000 0x00800000>;
-						read-only;
-					};
-
-					partition@800000 {
-						label = "uImage";
-						reg = <0x00800000 0x00400000>;
-						read-only;
-					};
-
-					partition@c00000 {
-						label = "Root";
-						reg = <0x00c00000 0x3f400000>;
-					};
-				};
-			};
-
 			usb3@f0000 {
 				status = "okay";
 				usb-phy = <&usb3_phy>;
@@ -263,3 +230,39 @@
 		spi-max-frequency = <54000000>;
 	};
 };
+
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0x00000000 0x00800000>;
+				read-only;
+			};
+
+			partition@800000 {
+				label = "uImage";
+				reg = <0x00800000 0x00400000>;
+				read-only;
+			};
+
+			partition@c00000 {
+				label = "Root";
+				reg = <0x00c00000 0x3f400000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-385-linksys-caiman.dts b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
index ee669ae61011..e769bcf7a9d1 100644
--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
@@ -105,67 +105,72 @@
 
 &nand {
 	/* 128MiB */
-
-	partition@0 {
-		label = "u-boot";
-		reg = <0x0000000 0x200000>;  /* 2MiB */
-		read-only;
-	};
-
-	partition@100000 {
-		label = "u_env";
-		reg = <0x200000 0x40000>;    /* 256KiB */
-	};
-
-	partition@140000 {
-		label = "s_env";
-		reg = <0x240000 0x40000>;    /* 256KiB */
-	};
-
-	partition@900000 {
-		label = "devinfo";
-		reg = <0x900000 0x100000>;   /* 1MiB */
-		read-only;
-	};
-
-	/* kernel1 overlaps with rootfs1 by design */
-	partition@a00000 {
-		label = "kernel1";
-		reg = <0xa00000 0x2800000>;  /* 40MiB */
-	};
-
-	partition@1000000 {
-		label = "rootfs1";
-		reg = <0x1000000 0x2200000>;  /* 34MiB */
-	};
-
-	/* kernel2 overlaps with rootfs2 by design */
-	partition@3200000 {
-		label = "kernel2";
-		reg = <0x3200000 0x2800000>; /* 40MiB */
-	};
-
-	partition@3800000 {
-		label = "rootfs2";
-		reg = <0x3800000 0x2200000>; /* 34MiB */
-	};
-
-	/*
-	 * 38MiB, last MiB is for the BBT, not writable
-	 */
-	partition@5a00000 {
-		label = "syscfg";
-		reg = <0x5a00000 0x2600000>;
-	};
-
-	/*
-	 * Unused area between "s_env" and "devinfo".
-	 * Moved here because otherwise the renumbered
-	 * partitions would break the bootloader
-	 * supplied bootargs
-	 */
-	partition@180000 {
-		label = "unused_area";
-		reg = <0x280000 0x680000>;   /* 6.5MiB */
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "u-boot";
+			reg = <0x0000000 0x200000>;  /* 2MiB */
+			read-only;
+		};
+
+		partition@100000 {
+			label = "u_env";
+			reg = <0x200000 0x40000>;    /* 256KiB */
+		};
+
+		partition@140000 {
+			label = "s_env";
+			reg = <0x240000 0x40000>;    /* 256KiB */
+		};
+
+		partition@900000 {
+			label = "devinfo";
+			reg = <0x900000 0x100000>;   /* 1MiB */
+			read-only;
+		};
+
+		/* kernel1 overlaps with rootfs1 by design */
+		partition@a00000 {
+			label = "kernel1";
+			reg = <0xa00000 0x2800000>;  /* 40MiB */
+		};
+
+		partition@1000000 {
+			label = "rootfs1";
+			reg = <0x1000000 0x2200000>;  /* 34MiB */
+		};
+
+		/* kernel2 overlaps with rootfs2 by design */
+		partition@3200000 {
+			label = "kernel2";
+			reg = <0x3200000 0x2800000>; /* 40MiB */
+		};
+
+		partition@3800000 {
+			label = "rootfs2";
+			reg = <0x3800000 0x2200000>; /* 34MiB */
+		};
+
+		/*
+		 * 38MiB, last MiB is for the BBT, not writable
+		 */
+		partition@5a00000 {
+			label = "syscfg";
+			reg = <0x5a00000 0x2600000>;
+		};
+
+		/*
+		 * Unused area between "s_env" and "devinfo".
+		 * Moved here because otherwise the renumbered
+		 * partitions would break the bootloader
+		 * supplied bootargs
+		 */
+		partition@180000 {
+			label = "unused_area";
+			reg = <0x280000 0x680000>;   /* 6.5MiB */
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/armada-385-linksys-cobra.dts b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
index 5169ca89c55a..690be217838c 100644
--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
@@ -105,67 +105,72 @@
 
 &nand {
 	/* 128MiB */
-
-	partition@0 {
-		label = "u-boot";
-		reg = <0x0000000 0x200000>;  /* 2MiB */
-		read-only;
-	};
-
-	partition@100000 {
-		label = "u_env";
-		reg = <0x200000 0x40000>;    /* 256KiB */
-	};
-
-	partition@140000 {
-		label = "s_env";
-		reg = <0x240000 0x40000>;    /* 256KiB */
-	};
-
-	partition@900000 {
-		label = "devinfo";
-		reg = <0x900000 0x100000>;   /* 1MiB */
-		read-only;
-	};
-
-	/* kernel1 overlaps with rootfs1 by design */
-	partition@a00000 {
-		label = "kernel1";
-		reg = <0xa00000 0x2800000>;  /* 40MiB */
-	};
-
-	partition@1000000 {
-		label = "rootfs1";
-		reg = <0x1000000 0x2200000>;  /* 34MiB */
-	};
-
-	/* kernel2 overlaps with rootfs2 by design */
-	partition@3200000 {
-		label = "kernel2";
-		reg = <0x3200000 0x2800000>; /* 40MiB */
-	};
-
-	partition@3800000 {
-		label = "rootfs2";
-		reg = <0x3800000 0x2200000>; /* 34MiB */
-	};
-
-	/*
-	 * 38MiB, last MiB is for the BBT, not writable
-	 */
-	partition@5a00000 {
-		label = "syscfg";
-		reg = <0x5a00000 0x2600000>;
-	};
-
-	/*
-	 * Unused area between "s_env" and "devinfo".
-	 * Moved here because otherwise the renumbered
-	 * partitions would break the bootloader
-	 * supplied bootargs
-	 */
-	partition@180000 {
-		label = "unused_area";
-		reg = <0x280000 0x680000>;   /* 6.5MiB */
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "u-boot";
+			reg = <0x0000000 0x200000>;  /* 2MiB */
+			read-only;
+		};
+
+		partition@100000 {
+			label = "u_env";
+			reg = <0x200000 0x40000>;    /* 256KiB */
+		};
+
+		partition@140000 {
+			label = "s_env";
+			reg = <0x240000 0x40000>;    /* 256KiB */
+		};
+
+		partition@900000 {
+			label = "devinfo";
+			reg = <0x900000 0x100000>;   /* 1MiB */
+			read-only;
+		};
+
+		/* kernel1 overlaps with rootfs1 by design */
+		partition@a00000 {
+			label = "kernel1";
+			reg = <0xa00000 0x2800000>;  /* 40MiB */
+		};
+
+		partition@1000000 {
+			label = "rootfs1";
+			reg = <0x1000000 0x2200000>;  /* 34MiB */
+		};
+
+		/* kernel2 overlaps with rootfs2 by design */
+		partition@3200000 {
+			label = "kernel2";
+			reg = <0x3200000 0x2800000>; /* 40MiB */
+		};
+
+		partition@3800000 {
+			label = "rootfs2";
+			reg = <0x3800000 0x2200000>; /* 34MiB */
+		};
+
+		/*
+		 * 38MiB, last MiB is for the BBT, not writable
+		 */
+		partition@5a00000 {
+			label = "syscfg";
+			reg = <0x5a00000 0x2600000>;
+		};
+
+		/*
+		 * Unused area between "s_env" and "devinfo".
+		 * Moved here because otherwise the renumbered
+		 * partitions would break the bootloader
+		 * supplied bootargs
+		 */
+		partition@180000 {
+			label = "unused_area";
+			reg = <0x280000 0x680000>;   /* 6.5MiB */
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/armada-385-linksys-rango.dts b/arch/arm/boot/dts/armada-385-linksys-rango.dts
index da8a0f3d432b..93570c6bfe85 100644
--- a/arch/arm/boot/dts/armada-385-linksys-rango.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-rango.dts
@@ -113,74 +113,79 @@
 
 &nand {
 	/* AMD/Spansion S34ML02G2 256MiB, OEM Layout */
-
-	partition@0 {
-		label = "u-boot";
-		reg = <0x0000000 0x200000>;  /* 2MiB */
-		read-only;
-	};
-
-	partition@200000 {
-		label = "u_env";
-		reg = <0x200000 0x20000>;    /* 128KiB */
-	};
-
-	partition@220000 {
-		label = "s_env";
-		reg = <0x220000 0x40000>;    /* 256KiB */
-	};
-
-	partition@7e0000 {
-		label = "devinfo";
-		reg = <0x7e0000 0x40000>;   /* 256KiB */
-		read-only;
-	};
-
-	partition@820000 {
-		label = "sysdiag";
-		reg = <0x820000 0x1e0000>;   /* 1920KiB */
-		read-only;
-	};
-
-	/* kernel1 overlaps with rootfs1 by design */
-	partition@a00000 {
-		label = "kernel1";
-		reg = <0xa00000 0x5000000>;  /* 80MiB */
-	};
-
-	partition@1000000 {
-		label = "rootfs1";
-		reg = <0x1000000 0x4a00000>;  /* 74MiB */
-	};
-
-	/* kernel2 overlaps with rootfs2 by design */
-	partition@5a00000 {
-		label = "kernel2";
-		reg = <0x5a00000 0x5000000>; /* 80MiB */
-	};
-
-	partition@6000000 {
-		label = "rootfs2";
-		reg = <0x6000000 0x4a00000>; /* 74MiB */
-	};
-
-	/*
-	 * 86MiB, last MiB is for the BBT, not writable
-	 */
-	partition@aa00000 {
-		label = "syscfg";
-		reg = <0xaa00000 0x5600000>;
-	};
-
-	/*
-	 * Unused area between "s_env" and "devinfo".
-	 * Moved here because otherwise the renumbered
-	 * partitions would break the bootloader
-	 * supplied bootargs
-	 */
-	partition@180000 {
-		label = "unused_area";
-		reg = <0x260000 0x5c0000>;   /* 5.75MiB */
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "u-boot";
+			reg = <0x0000000 0x200000>;  /* 2MiB */
+			read-only;
+		};
+
+		partition@200000 {
+			label = "u_env";
+			reg = <0x200000 0x20000>;    /* 128KiB */
+		};
+
+		partition@220000 {
+			label = "s_env";
+			reg = <0x220000 0x40000>;    /* 256KiB */
+		};
+
+		partition@7e0000 {
+			label = "devinfo";
+			reg = <0x7e0000 0x40000>;   /* 256KiB */
+			read-only;
+		};
+
+		partition@820000 {
+			label = "sysdiag";
+			reg = <0x820000 0x1e0000>;   /* 1920KiB */
+			read-only;
+		};
+
+		/* kernel1 overlaps with rootfs1 by design */
+		partition@a00000 {
+			label = "kernel1";
+			reg = <0xa00000 0x5000000>;  /* 80MiB */
+		};
+
+		partition@1000000 {
+			label = "rootfs1";
+			reg = <0x1000000 0x4a00000>;  /* 74MiB */
+		};
+
+		/* kernel2 overlaps with rootfs2 by design */
+		partition@5a00000 {
+			label = "kernel2";
+			reg = <0x5a00000 0x5000000>; /* 80MiB */
+		};
+
+		partition@6000000 {
+			label = "rootfs2";
+			reg = <0x6000000 0x4a00000>; /* 74MiB */
+		};
+
+		/*
+		 * 86MiB, last MiB is for the BBT, not writable
+		 */
+		partition@aa00000 {
+			label = "syscfg";
+			reg = <0xaa00000 0x5600000>;
+		};
+
+		/*
+		 * Unused area between "s_env" and "devinfo".
+		 * Moved here because otherwise the renumbered
+		 * partitions would break the bootloader
+		 * supplied bootargs
+		 */
+		partition@180000 {
+			label = "unused_area";
+			reg = <0x260000 0x5c0000>;   /* 5.75MiB */
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/armada-385-linksys-shelby.dts b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
index 94aa35bc0bff..4694556700ff 100644
--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
@@ -105,67 +105,72 @@
 
 &nand {
 	/* 128MiB */
-
-	partition@0 {
-		label = "u-boot";
-		reg = <0x0000000 0x200000>;  /* 2MiB */
-		read-only;
-	};
-
-	partition@100000 {
-		label = "u_env";
-		reg = <0x200000 0x40000>;    /* 256KiB */
-	};
-
-	partition@140000 {
-		label = "s_env";
-		reg = <0x240000 0x40000>;    /* 256KiB */
-	};
-
-	partition@900000 {
-		label = "devinfo";
-		reg = <0x900000 0x100000>;   /* 1MiB */
-		read-only;
-	};
-
-	/* kernel1 overlaps with rootfs1 by design */
-	partition@a00000 {
-		label = "kernel1";
-		reg = <0xa00000 0x2800000>;  /* 40MiB */
-	};
-
-	partition@1000000 {
-		label = "rootfs1";
-		reg = <0x1000000 0x2200000>;  /* 34MiB */
-	};
-
-	/* kernel2 overlaps with rootfs2 by design */
-	partition@3200000 {
-		label = "kernel2";
-		reg = <0x3200000 0x2800000>; /* 40MiB */
-	};
-
-	partition@3800000 {
-		label = "rootfs2";
-		reg = <0x3800000 0x2200000>; /* 34MiB */
-	};
-
-	/*
-	 * 38MiB, last MiB is for the BBT, not writable
-	 */
-	partition@5a00000 {
-		label = "syscfg";
-		reg = <0x5a00000 0x2600000>;
-	};
-
-	/*
-	 * Unused area between "s_env" and "devinfo".
-	 * Moved here because otherwise the renumbered
-	 * partitions would break the bootloader
-	 * supplied bootargs
-	 */
-	partition@180000 {
-		label = "unused_area";
-		reg = <0x280000 0x680000>;   /* 6.5MiB */
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "u-boot";
+			reg = <0x0000000 0x200000>;  /* 2MiB */
+			read-only;
+		};
+
+		partition@100000 {
+			label = "u_env";
+			reg = <0x200000 0x40000>;    /* 256KiB */
+		};
+
+		partition@140000 {
+			label = "s_env";
+			reg = <0x240000 0x40000>;    /* 256KiB */
+		};
+
+		partition@900000 {
+			label = "devinfo";
+			reg = <0x900000 0x100000>;   /* 1MiB */
+			read-only;
+		};
+
+		/* kernel1 overlaps with rootfs1 by design */
+		partition@a00000 {
+			label = "kernel1";
+			reg = <0xa00000 0x2800000>;  /* 40MiB */
+		};
+
+		partition@1000000 {
+			label = "rootfs1";
+			reg = <0x1000000 0x2200000>;  /* 34MiB */
+		};
+
+		/* kernel2 overlaps with rootfs2 by design */
+		partition@3200000 {
+			label = "kernel2";
+			reg = <0x3200000 0x2800000>; /* 40MiB */
+		};
+
+		partition@3800000 {
+			label = "rootfs2";
+			reg = <0x3800000 0x2200000>; /* 34MiB */
+		};
+
+		/*
+		 * 38MiB, last MiB is for the BBT, not writable
+		 */
+		partition@5a00000 {
+			label = "syscfg";
+			reg = <0x5a00000 0x2600000>;
+		};
+
+		/*
+		 * Unused area between "s_env" and "devinfo".
+		 * Moved here because otherwise the renumbered
+		 * partitions would break the bootloader
+		 * supplied bootargs
+		 */
+		partition@180000 {
+			label = "unused_area";
+			reg = <0x280000 0x680000>;   /* 6.5MiB */
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index e1f355ffc8f7..214630b06f0e 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -169,13 +169,19 @@
 	};
 };
 
-&nand {
+&nand_controller {
 	/* 128MiB or 256MiB */
 	status = "okay";
-	num-cs = <1>;
-	marvell,nand-keep-config;
-	marvell,nand-enable-arbiter;
-	nand-on-flash-bbt;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nand: nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+	};
 };
 
 &mdio {
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
index a4ec1fa37529..61bfed5adaaa 100644
--- a/arch/arm/boot/dts/armada-388-db.dts
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -128,29 +128,6 @@
 				status = "okay";
 			};
 
-			flash@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "U-Boot";
-					reg = <0 0x800000>;
-				};
-				partition@800000 {
-					label = "Linux";
-					reg = <0x800000 0x800000>;
-				};
-				partition@1000000 {
-					label = "Filesystem";
-					reg = <0x1000000 0x3f000000>;
-				};
-			};
-
 			sdhci@d8000 {
 				broken-cd;
 				wp-inverted;
@@ -202,3 +179,35 @@
 	};
 };
 
+&nand_controller {
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 00ff549d4e39..28669188f69d 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -583,11 +583,11 @@
 				status = "okay";
 			};
 
-			nand: flash@d0000 {
-				compatible = "marvell,armada370-nand";
+			nand_controller: nand-controller@d0000 {
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&coredivclk 0>;
 				status = "disabled";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 09/12] ARM: dts: armada-39x: use reworked NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (7 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 08/12] ARM: dts: armada-38x: " Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 10/12] ARM: dts: pxa: " Miquel Raynal
                     ` (4 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/boot/dts/armada-390-db.dts | 66 +++++++++++++++++----------------
 arch/arm/boot/dts/armada-395-gp.dts | 74 +++++++++++++++++++------------------
 arch/arm/boot/dts/armada-398-db.dts | 60 +++++++++++++++++-------------
 arch/arm/boot/dts/armada-39x.dtsi   |  6 +--
 4 files changed, 112 insertions(+), 94 deletions(-)

diff --git a/arch/arm/boot/dts/armada-390-db.dts b/arch/arm/boot/dts/armada-390-db.dts
index c718a5242595..2135a48cd385 100644
--- a/arch/arm/boot/dts/armada-390-db.dts
+++ b/arch/arm/boot/dts/armada-390-db.dts
@@ -86,37 +86,6 @@
 				status = "okay";
 			};
 
-			flash@d0000 {
-				status = "okay";
-				pinctrl-0 = <&nand_pins>;
-				pinctrl-names = "default";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <8>;
-				nand-ecc-step-size = <512>;
-
-				partitions {
-					compatible = "fixed-partitions";
-					#address-cells = <1>;
-					#size-cells = <1>;
-
-					partition@0 {
-						label = "U-Boot";
-						reg = <0 0x800000>;
-					};
-					partition@800000 {
-						label = "Linux";
-						reg = <0x800000 0x800000>;
-					};
-					partition@1000000 {
-						label = "Filesystem";
-						reg = <0x1000000 0x3f000000>;
-					};
-				};
-			};
-
 			/* CON98 */
 			usb3@f8000 {
 				status = "okay";
@@ -173,3 +142,38 @@
 		};
 	};
 };
+
+&nand_controller {
+	status = "okay";
+	pinctrl-0 = <&nand_pins>;
+	pinctrl-names = "default";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <8>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-395-gp.dts b/arch/arm/boot/dts/armada-395-gp.dts
index ef491b524fd6..d3422f77d057 100644
--- a/arch/arm/boot/dts/armada-395-gp.dts
+++ b/arch/arm/boot/dts/armada-395-gp.dts
@@ -88,41 +88,6 @@
 				status = "okay";
 			};
 
-			flash@d0000 {
-				status = "okay";
-				pinctrl-0 = <&nand_pins>;
-				pinctrl-names = "default";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partitions {
-					compatible = "fixed-partitions";
-					#address-cells = <1>;
-					#size-cells = <1>;
-
-					partition@0 {
-						label = "U-Boot";
-						reg = <0x00000000 0x00600000>;
-						read-only;
-					};
-
-					partition@800000 {
-						label = "uImage";
-						reg = <0x00600000 0x00400000>;
-						read-only;
-					};
-
-					partition@1000000 {
-						label = "Root";
-						reg = <0x00a00000 0x3f600000>;
-					};
-				};
-			};
-
 			/* CON18 */
 			sdhci@d8000 {
 				clock-frequency = <200000000>;
@@ -161,3 +126,42 @@
 		};
 	};
 };
+
+&nand_controller {
+	status = "okay";
+	pinctrl-0 = <&nand_pins>;
+	pinctrl-names = "default";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0x00000000 0x00600000>;
+				read-only;
+			};
+
+			partition@800000 {
+				label = "uImage";
+				reg = <0x00600000 0x00400000>;
+				read-only;
+			};
+
+			partition@1000000 {
+				label = "Root";
+				reg = <0x00a00000 0x3f600000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-398-db.dts b/arch/arm/boot/dts/armada-398-db.dts
index f0e0379f7619..e73e5e453fd7 100644
--- a/arch/arm/boot/dts/armada-398-db.dts
+++ b/arch/arm/boot/dts/armada-398-db.dts
@@ -88,31 +88,6 @@
 				status = "okay";
 			};
 
-			flash@d0000 {
-				status = "okay";
-				pinctrl-0 = <&nand_pins>;
-				pinctrl-names = "default";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <8>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "U-Boot";
-					reg = <0 0x800000>;
-				};
-				partition@800000 {
-					label = "Linux";
-					reg = <0x800000 0x800000>;
-				};
-				partition@1000000 {
-					label = "Filesystem";
-					reg = <0x1000000 0x3f000000>;
-				};
-			};
-
 			usb3@f8000 {
 				status = "okay";
 			};
@@ -159,3 +134,38 @@
 		};
 	};
 };
+
+&nand_controller {
+	status = "okay";
+	pinctrl-0 = <&nand_pins>;
+	pinctrl-names = "default";
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		marvell,nand-keep-config;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <8>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x800000>;
+			};
+			partition@800000 {
+				label = "Linux";
+				reg = <0x800000 0x800000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi
index 5218bd2a248d..a8322de3f0b3 100644
--- a/arch/arm/boot/dts/armada-39x.dtsi
+++ b/arch/arm/boot/dts/armada-39x.dtsi
@@ -404,11 +404,11 @@
 				interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			flash@d0000 {
-				compatible = "marvell,armada370-nand";
+			nand_controller: nand-controller@d0000 {
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&coredivclk 0>;
 				status = "disabled";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 10/12] ARM: dts: pxa: use reworked NAND controller driver
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (8 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 09/12] ARM: dts: armada-39x: " Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
  2017-12-07 20:18   ` [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K Miquel Raynal
                     ` (3 subsequent siblings)
  13 siblings, 0 replies; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm/boot/dts/pxa3xx.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi
index 55c75b67351c..982d1a62661d 100644
--- a/arch/arm/boot/dts/pxa3xx.dtsi
+++ b/arch/arm/boot/dts/pxa3xx.dtsi
@@ -117,15 +117,15 @@
 			status = "disabled";
 		};
 
-		nand0: nand@43100000 {
-			compatible = "marvell,pxa3xx-nand";
+		nand_controller: nand-controller@43100000 {
+			compatible = "marvell,pxa3xx-nand-controller";
 			reg = <0x43100000 90>;
 			interrupts = <45>;
 			clocks = <&clks CLK_NAND>;
 			dmas = <&pdma 97 3>;
 			dma-names = "data";
 			#address-cells = <1>;
-			#size-cells = <1>;	
+			#size-cells = <0>;
 			status = "disabled";
 		};
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (9 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 10/12] ARM: dts: pxa: " Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
       [not found]     ` <20171207201814.30411-12-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-07 20:18   ` [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K Miquel Raynal
                     ` (2 subsequent siblings)
  13 siblings, 1 reply; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm64/boot/dts/marvell/armada-7040-db.dts     | 52 +++++++++++++---------
 .../boot/dts/marvell/armada-cp110-master.dtsi      |  8 ++--
 2 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
index 52b5341cb270..758452c10612 100644
--- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
@@ -156,36 +156,48 @@
 	};
 };
 
-&cpm_nand {
+&cpm_nand_controller {
 	/*
 	 * SPI on CPM and NAND have common pins on this board. We can
-	 * use only one at a time. To enable the NAND (whihch will
+	 * use only one at a time. To enable the NAND (which will
 	 * disable the SPI), the "status = "okay";" line have to be
 	 * added here.
 	 */
-	num-cs = <1>;
 	pinctrl-0 = <&nand_pins>, <&nand_rb>;
 	pinctrl-names = "default";
-	nand-ecc-strength = <4>;
-	nand-ecc-step-size = <512>;
-	marvell,nand-enable-arbiter;
-	nand-on-flash-bbt;
-
-	partition@0 {
-		label = "U-Boot";
-		reg = <0 0x200000>;
-	};
-	partition@200000 {
-		label = "Linux";
-		reg = <0x200000 0xe00000>;
-	};
-	partition@1000000 {
-		label = "Filesystem";
-		reg = <0x1000000 0x3f000000>;
+
+	nand@0 {
+		reg = <0>;
+		label = "pxa3xx_nand-0";
+		marvell,rb = <0>;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x200000>;
+			};
+
+			partition@200000 {
+				label = "Linux";
+				reg = <0x200000 0xe00000>;
+			};
+
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+
+		};
 	};
 };
 
-
 &cpm_spi1 {
 	status = "okay";
 
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
index e3b64d03fbd8..8a3cff9a7343 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
@@ -309,17 +309,17 @@
 				status = "disabled";
 			};
 
-			cpm_nand: nand@720000 {
+			cpm_nand_controller: nand@720000 {
 				/*
 				 * Due to the limiation of the pin available
 				 * this controller is only usable on the CPM
 				 * for A7K and on the CPS for A8K.
 				 */
-				compatible = "marvell,armada-8k-nand",
-					     "marvell,armada370-nand";
+				compatible = "marvell,armada-8k-nand-controller",
+					     "marvell,armada370-nand-controller";
 				reg = <0x720000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&cpm_clk 1 2>;
 				marvell,system-controller = <&cpm_syscon0>;
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (10 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K Miquel Raynal
@ 2017-12-07 20:18   ` Miquel Raynal
       [not found]     ` <20171207201814.30411-13-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-12-09 23:27   ` [PATCH 00/12] Marvell NAND controller rework with ->exec_op() Ezequiel Garcia
  2017-12-14  6:09   ` Boris Brezillon
  13 siblings, 1 reply; 32+ messages in thread
From: Miquel Raynal @ 2017-12-07 20:18 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Antoine Tenart, Nadav Haklai, Miquel Raynal,
	Ofer Heifetz, Hanna Hawa, Neta Zur Hershkovits

Use the new bindings of the reworked Marvell NAND controller driver.
Also adapt the nand controller node organization to distinguish which
property is relevant for the controller, and which one is NAND chip
specific. Expose the partitions as a subnode of the NAND chip.

Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
the driver activates the arbiter by default for all boards (either
needed or harmless).

Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm64/boot/dts/marvell/armada-8040-db.dts     | 46 +++++++++++++---------
 .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi | 10 ++---
 2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
index b1f6cccc5081..c25ac3fa9aec 100644
--- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
@@ -272,27 +272,35 @@
  * Proper NAND usage will require DPR-76 to be in position 1-2, which disables
  * MDIO signal of CP1.
  */
-&cps_nand {
-	num-cs = <1>;
+&cps_nand_controller {
 	pinctrl-0 = <&nand_pins>, <&nand_rb>;
 	pinctrl-names = "default";
-	nand-ecc-strength = <4>;
-	nand-ecc-step-size = <512>;
-	marvell,nand-enable-arbiter;
-	marvell,system-controller = <&cps_syscon0>;
-	nand-on-flash-bbt;
-
-	partition@0 {
-		label = "U-Boot";
-		reg = <0 0x200000>;
-	};
-	partition@200000 {
-		label = "Linux";
-		reg = <0x200000 0xe00000>;
-	};
-	partition@1000000 {
-		label = "Filesystem";
-		reg = <0x1000000 0x3f000000>;
+
+	nand@0 {
+		reg = <0>;
+		marvell,rb = <0>;
+		nand-on-flash-bbt;
+		nand-ecc-strength = <4>;
+		nand-ecc-step-size = <512>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0 0x200000>;
+			};
+			partition@200000 {
+				label = "Linux";
+				reg = <0x200000 0xe00000>;
+			};
+			partition@1000000 {
+				label = "Filesystem";
+				reg = <0x1000000 0x3f000000>;
+			};
+		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
index cb1fb49ccf81..8610163bb1a4 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
@@ -310,20 +310,20 @@
 				status = "disabled";
 			};
 
-			cps_nand: nand@720000 {
+			cps_nand_controller: nand@720000 {
 				/*
 				 * Due to the limiation of the pin available
 				 * this controller is only usable on the CPM
 				 * for A7K and on the CPS for A8K.
 				 */
-				compatible = "marvell,armada370-nand",
-					     "marvell,armada-8k-nand";
+				compatible = "marvell,armada-8k-nand-controller",
+					     "marvell,armada370-nand-controller";
 				reg = <0x720000 0x54>;
 				#address-cells = <1>;
-				#size-cells = <1>;
+				#size-cells = <0>;
 				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&cps_clk 1 2>;
-				marvell,system-controller = <&cpm_syscon0>;
+				marvell,system-controller = <&cps_syscon0>;
 				status = "disabled";
 			};
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH 01/12] dt-bindings: mtd: add Marvell NAND controller documentation
       [not found]     ` <20171207201814.30411-2-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-08 20:56       ` Boris Brezillon
  0 siblings, 0 replies; 32+ messages in thread
From: Boris Brezillon @ 2017-12-08 20:56 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Marek Vasut, Richard Weinberger,
	Cyrille Pitchen, Rob Herring, Mark Rutland, Jason Cooper,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Russell King, Daniel Mack, Haojian Zhuang, Robert Jarzmik,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

On Thu,  7 Dec 2017 21:18:03 +0100
Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Document the legacy and the new bindings for Marvell NAND controller.
> 
> The pxa3xx_nand.c driver does only support legacy bindings, which are
> incomplete and inaccurate. A rework of this controller (called
> marvell_nand.c) does support both.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
>  .../devicetree/bindings/mtd/marvell-nand.txt       | 84 ++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/marvell-nand.txt
> 
> diff --git a/Documentation/devicetree/bindings/mtd/marvell-nand.txt b/Documentation/devicetree/bindings/mtd/marvell-nand.txt
> new file mode 100644
> index 000000000000..0b3d5e0bab83
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/marvell-nand.txt
> @@ -0,0 +1,84 @@
> +Marvell NAND Flash Controller (NFC)
> +
> +Required properties:
> +- compatible: can be one of the following:
> +    * "marvell,armada-8k-nand-controller"
> +    * "marvell,armada370-nand-controller"
> +    * "marvell,pxa3xx-nand-controller"
> +    * "marvell,armada-8k-nand" (deprecated)
> +    * "marvell,armada370-nand" (deprecated)
> +    * "marvell,pxa3xx-nand" (deprecated)
> +- reg: NAND flash controller memory area.
> +- #address-cells: shall be set to 1. Encode the NAND CS.
> +- #size-cells: shall be set to 0.
> +- interrupts: shall define the NAND controller interrupt.
> +- clocks: shall reference the NAND controller clock.
> +- marvell,system-controller: Set to retrieve the syscon node that handles
> +  NAND controller related registers (only required with the
> +  "marvell,armada-8k-nand[-controller]" compatibles).
> +
> +Optional properties:
> +- label: see partition.txt. New platforms shall omit this property.
> +- dmas: shall reference DMA channel associated to the NAND controller.
> +- dma-names: shall be "rxtx".
> +
> +Optional children nodes:
> +Children nodes represent the available NAND chips.
> +
> +Required properties:
> +- reg: shall contain the native Chip Select ids (0-3)
> +- marvell,rb: shall contain the native Ready/Busy ids (0-1)
> +
> +Optional properties:
> +- marvell,nand-keep-config: orders the driver not to take the timings
> +  from the core and leaving them completely untouched. Bootloader
> +  timings will then be used.
> +- nand-on-flash-bbt: see nand.txt.
> +- nand-ecc-mode: see nand.txt. Will use hardware ECC if not specified.
> +- nand-ecc-algo: see nand.txt. This property may be added when using
> +  hardware ECC for clarification but will be ignored by the driver
> +  because ECC mode is chosen depending on the page size and the strength
> +  required by the NAND chip. This value may be overwritten with
> +  nand-ecc-strength property.
> +- nand-ecc-strength: see nand.txt.
> +- nand-ecc-step-size: see nand.txt. This has no effect and will be
> +  ignored by the driver when using hardware ECC because Marvell's NAND
> +  flash controller does use fixed strength (1-bit for Hamming, 16-bit
> +  for BCH), so the step size will shrink or grow in order to fit the
> +  required strength. Step sizes are not completely random for all and
> +  follow certain patterns described in AN-379, "Marvell SoC NFC ECC".
> +
> +See Documentation/devicetree/bindings/mtd/nand.txt for more details on
> +generic bindings.
> +
> +
> +Example:
> +nand_controller: nand-controller@d0000 {
> +	compatible = "marvell,armada370-nand-controller";
> +	reg = <0xd0000 0x54>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
> +	clocks = <&coredivclk 0>;
> +
> +	nand@0 {
> +		reg = <0>;
> +		marvell,rb = <0>;
> +		nand-ecc-mode = "hw";
> +		marvell,nand-keep-config;
> +		nand-on-flash-bbt;
> +		nand-ecc-strength = <4>;
> +		nand-ecc-step-size = <512>;
> +
> +		partitions {
> +			compatible = "fixed-partitions";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			partition@0 {
> +				label = "Rootfs";
> +				reg = <0x00000000 0x40000000>;
> +			};
> +		};
> +	};
> +};

Maybe you should also give an example for the old bindings.
BTW, given your properties description, it's not clear which properties
are deprecated. Maybe you should split the doc in 2 sections: one
describing the new bindings, and the other one describing the deprecated
bindings.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (11 preceding siblings ...)
  2017-12-07 20:18   ` [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K Miquel Raynal
@ 2017-12-09 23:27   ` Ezequiel Garcia
  2017-12-14  6:09   ` Boris Brezillon
  13 siblings, 0 replies; 32+ messages in thread
From: Ezequiel Garcia @ 2017-12-09 23:27 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas

Miquel,

On 7 December 2017 at 17:18, Miquel Raynal
<miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> Hi,
>
> After the addition of the NAND framework ->exec_op() interface (see [1]
> for the series preparing it and [2] for the last version of the
> core-side implementation of ->exec_op() itself), this series replaces
> the current Marvell NAND controller driver pxa3xx_nand.c with a rework
> called marvell_nand.c.
>

Nice to see this effort!

Unfortunately, I don't much time to spend reviewing this, but I'm super
happy to see a new driver fixing all the nasty issues the current one has.

Cheers,
-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver
       [not found]     ` <20171207201814.30411-3-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-11 16:27       ` Ezequiel Garcia
       [not found]         ` <CAAEAJfC89bRugBsK8jrK=6fdq76yzjThA74UCAhAaVuonLLNvg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Ezequiel Garcia @ 2017-12-11 16:27 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas

On 7 December 2017 at 17:18, Miquel Raynal
<miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> Add marvell_nand driver which aims at replacing the existing pxa3xx_nand
> driver.
>
> The new driver intends to be easier to understand and follows the brand
> new NAND framework rules by implementing hooks for every pattern the
> controller might support and referencing them inside a parser object
> that will be given to the core at each ->exec_op() call.
>
> Raw accessors are implemented, useful to test/debug memory/filesystem
> corruptions. Userspace binaries contained in the mtd-utils package may
> now be used and their output trusted.
>
> Timings may not be kept from the bootloader anymore, the timings used
> for instance in U-Boot were not optimal and it supposed to have NAND
> support (and initialized) in the bootloader.
>
> Thanks to the improved timings, implementation of ONFI mode 5 support
> (with EDO managed by adding a delay on data sampling), merging the
> commands together and optimizing writes in the command registers, the
> new driver may achieve faster throughputs in both directions.
> Measurements show an improvement of about +23% read throughput and +24%
> write throughput. These measurements have been done with an
> Armada-385-DB-AP (4kiB NAND pages forced in 4-bit strength BCH ECC
> correction) using the userspace tool 'flash_speed' from the MTD test
> suite.
>
> Besides these important topics, the new driver addresses several
> unsolved known issues in the old driver which:
> - did not work with ECC soft neither with ECC none ;
> - relied on naked read/write (which is unchanged) while the NFCv1
>   embedded in the pxa3xx platforms do not implement it, so several
>   NAND commands did not actually ever work without any notice (like
>   reading the ONFI PARAM_PAGE or SET/GET_FEATURES) ;
> - wrote the OOB data correctly, but was not able to read it correctly
>   past the first OOB data chunk ;
> - did not displayed ECC bytes ;
> - used device tree bindings that did not allow more than one NAND chip,
>   and did not allow to choose the correct chip select if not
>   incrementing from 0. Plus, the Ready/Busy line used had to be 0.
>
> Old device tree bindings are still supported but deprecated. A more
> hierarchical view has to be used to keep the controller and the NAND
> chip structures clearly separated both inside the device tree and also
> in the driver code.
>

So, is this driver fully compatible with the current pxa3xx-nand driver?

Have you tested with U-Boot's driver (based on the pxa3xx-nand)?

I recally some subtle issues with the fact that U-Boot and Linux had
to agree about the BBT format.

> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
>  drivers/mtd/nand/Kconfig        |   12 +
>  drivers/mtd/nand/Makefile       |    1 +
>  drivers/mtd/nand/marvell_nand.c | 2951 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 2964 insertions(+)
>  create mode 100644 drivers/mtd/nand/marvell_nand.c
>
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 859eb7790c46..9e141e03f5c2 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -323,6 +323,18 @@ config MTD_NAND_PXA3xx
>           platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
>           platforms (7K, 8K) (NFCv2).
>
> +config MTD_NAND_MARVELL
> +       tristate "NAND controller support on Marvell boards"
> +       depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
> +                  COMPILE_TEST
> +       depends on HAS_IOMEM
> +       help
> +         This enables the NAND flash controller driver for Marvell boards,
> +         including:
> +         - PXA3xx processors (NFCv1)
> +         - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
> +         - 64-bit Aramda platforms (7k, 8k) (NFCv2)
> +
>  config MTD_NAND_SLC_LPC32XX
>         tristate "NXP LPC32xx SLC Controller"
>         depends on ARCH_LPC32XX
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index 118a1349aad3..921634ba400c 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_MTD_NAND_OMAP2)          += omap2_nand.o
>  obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)  += omap_elm.o
>  obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
>  obj-$(CONFIG_MTD_NAND_PXA3xx)          += pxa3xx_nand.o
> +obj-$(CONFIG_MTD_NAND_MARVELL)         += marvell_nand.o
>  obj-$(CONFIG_MTD_NAND_TMIO)            += tmio_nand.o
>  obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
>  obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
> diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c
> new file mode 100644
> index 000000000000..2525d9b2f4fa
> --- /dev/null
> +++ b/drivers/mtd/nand/marvell_nand.c
> @@ -0,0 +1,2951 @@
> +/*
> + * Marvell NAND flash controller driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Copyright (C) 2017 Marvell
> + * Author: Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/mtd/rawnand.h>
> +#include <linux/of_platform.h>
> +#include <linux/iopoll.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +#include <asm/unaligned.h>
> +
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/dma/pxa-dma.h>
> +#include <linux/platform_data/mtd-nand-pxa3xx.h>
> +
> +/* Data FIFO granularity, FIFO reads/writes must be a multiple of this length */
> +#define FIFO_DEPTH             8
> +#define FIFO_REP(x)            (x / sizeof(u32))
> +#define BCH_SEQ_READS          (32 / FIFO_DEPTH)
> +/* NFC does not support transfers of larger chunks at a time */
> +#define MAX_CHUNK_SIZE         2112
> +/* NFCv1 cannot read more that 7 bytes of ID */
> +#define NFCV1_READID_LEN       7
> +/* Polling is done at a pace of POLL_PERIOD us until POLL_TIMEOUT is reached */
> +#define POLL_PERIOD            0
> +#define POLL_TIMEOUT           100000
> +/* Interrupt maximum wait period in ms */
> +#define IRQ_TIMEOUT            1000
> +/* Latency in clock cycles between SoC pins and NFC logic */
> +#define MIN_RD_DEL_CNT         3
> +/* Maximum number of contiguous address cycles */
> +#define MAX_ADDRESS_CYC_NFCV1  5
> +#define MAX_ADDRESS_CYC_NFCV2  7
> +/* System control registers/bits to enable the NAND controller on some SoCs */
> +#define GENCONF_SOC_DEVICE_MUX 0x208
> +#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
> +#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
> +#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
> +#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
> +#define GENCONF_CLK_GATING_CTRL        0x220
> +#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
> +#define GENCONF_ND_CLK_CTRL    0x700
> +#define GENCONF_ND_CLK_CTRL_EN BIT(0)
> +
> +/* NAND controller data flash control register */
> +#define NDCR                   0x00
> +/* NAND interface timing parameter 0 register */
> +#define NDTR0                  0x04
> +/* NAND interface timing parameter 1 register */
> +#define NDTR1                  0x0C
> +/* NAND controller status register */
> +#define NDSR                   0x14
> +/* NAND ECC control register */
> +#define NDECCCTRL              0x28
> +/* NAND controller data buffer register */
> +#define NDDB                   0x40
> +/* NAND controller command buffer 0 register */
> +#define NDCB0                  0x48
> +/* NAND controller command buffer 1 register */
> +#define NDCB1                  0x4C
> +/* NAND controller command buffer 2 register */
> +#define NDCB2                  0x50
> +/* NAND controller command buffer 3 register */
> +#define NDCB3                  0x54
> +
> +/* Data flash control register bitfields */
> +#define NDCR_ALL_INT           GENMASK(11, 0)
> +#define NDCR_CS1_CMDDM         BIT(7)
> +#define NDCR_CS0_CMDDM         BIT(8)
> +#define NDCR_RDYM              BIT(11)
> +#define NDCR_ND_ARB_EN         BIT(12)
> +#define NDCR_RA_START          BIT(15)
> +#define NDCR_RD_ID_CNT(x)      (min_t(unsigned int, x, 0x7) << 16)
> +#define NDCR_PAGE_SZ(x)                (x >= 2048 ? BIT(24) : 0)
> +#define NDCR_DWIDTH_M          BIT(26)
> +#define NDCR_DWIDTH_C          BIT(27)
> +#define NDCR_ND_RUN            BIT(28)
> +#define NDCR_DMA_EN            BIT(29)
> +#define NDCR_ECC_EN            BIT(30)
> +#define NDCR_SPARE_EN          BIT(31)
> +
> +/* NAND interface timing parameter registers bitfields */
> +#define NDTR0_TRP(x)           ((min_t(unsigned int, x, 0xF) & 0x7) << 0)
> +#define NDTR0_TRH(x)           (min_t(unsigned int, x, 0x7) << 3)
> +#define NDTR0_ETRP(x)          ((min_t(unsigned int, x, 0xF) & 0x8) << 3)
> +#define NDTR0_SEL_NRE_EDGE     BIT(7)
> +#define NDTR0_TWP(x)           (min_t(unsigned int, x, 0x7) << 8)
> +#define NDTR0_TWH(x)           (min_t(unsigned int, x, 0x7) << 11)
> +#define NDTR0_TCS(x)           (min_t(unsigned int, x, 0x7) << 16)
> +#define NDTR0_TCH(x)           (min_t(unsigned int, x, 0x7) << 19)
> +#define NDTR0_RD_CNT_DEL(x)    (min_t(unsigned int, x, 0xF) << 22)
> +#define NDTR0_SELCNTR          BIT(26)
> +#define NDTR0_TADL(x)          (min_t(unsigned int, x, 0x1F) << 27)
> +
> +#define NDTR1_TAR(x)           (min_t(unsigned int, x, 0xF) << 0)
> +#define NDTR1_TWHR(x)          (min_t(unsigned int, x, 0xF) << 4)
> +#define NDTR1_TRHW(x)          (min_t(unsigned int, x / 16, 0x3) << 8)
> +#define NDTR1_PRESCALE         BIT(14)
> +#define NDTR1_WAIT_MODE                BIT(15)
> +#define NDTR1_TR(x)            (min_t(unsigned int, x, 0xFFFF) << 16)
> +
> +/* NAND controller status register bitfields */
> +#define NDSR_WRCMDREQ          BIT(0)
> +#define NDSR_RDDREQ            BIT(1)
> +#define NDSR_WRDREQ            BIT(2)
> +#define NDSR_CORERR            BIT(3)
> +#define NDSR_UNCERR            BIT(4)
> +#define NDSR_CMDD(cs)          BIT(8 - cs)
> +#define NDSR_RDY(rb)           BIT(11 + rb)
> +#define NDSR_ERRCNT(x)         ((x >> 16) & 0x1F)
> +
> +/* NAND ECC control register bitfields */
> +#define NDECCTRL_BCH_EN                BIT(0)
> +
> +/* NAND controller command buffer registers bitfields */
> +#define NDCB0_CMD1(x)          ((x & 0xFF) << 0)
> +#define NDCB0_CMD2(x)          ((x & 0xFF) << 8)
> +#define NDCB0_ADDR_CYC(x)      ((x & 0x7) << 16)
> +#define NDCB0_DBC              BIT(19)
> +#define NDCB0_CMD_TYPE(x)      ((x & 0x7) << 21)
> +#define NDCB0_CSEL             BIT(24)
> +#define NDCB0_RDY_BYP          BIT(27)
> +#define NDCB0_LEN_OVRD         BIT(28)
> +#define NDCB0_CMD_XTYPE(x)     ((x & 0x7) << 29)
> +
> +#define NDCB1_COLS(x)          ((x & 0xFFFF) << 0)
> +#define NDCB1_ADDRS(x)         (x << 16)
> +
> +#define NDCB2_ADDR5(x)         (((x >> 16) & 0xFF) << 0)
> +
> +#define NDCB3_ADDR6(x)         ((x & 0xFF) << 16)
> +#define NDCB3_ADDR7(x)         ((x & 0xFF) << 24)
> +
> +/* NAND controller command buffer 0 register 'type' and 'xtype' fields */
> +#define TYPE_READ              0
> +#define TYPE_WRITE             1
> +#define TYPE_ERASE             2
> +#define TYPE_READ_ID           3
> +#define TYPE_STATUS            4
> +#define TYPE_RESET             5
> +#define TYPE_NAKED_CMD         6
> +#define TYPE_NAKED_ADDR                7
> +#define TYPE_MASK              7
> +#define XTYPE_MONOLITHIC_RW    0
> +#define XTYPE_LAST_NAKED_RW    1
> +#define XTYPE_FINAL_COMMAND    3
> +#define XTYPE_READ             4
> +#define XTYPE_WRITE_DISPATCH   4
> +#define XTYPE_NAKED_RW         5
> +#define XTYPE_COMMAND_DISPATCH 6
> +#define XTYPE_MASK             7
> +
> +/*
> + * Marvell ECC engine works differently than the others, in order to limit the
> + * size of the IP, hardware engineers choose to set a fixed strength at 16 bits
> + * per subpage, and depending on a the desired strength needed by the NAND chip,
> + * a particular layout mixing data/spare/ecc is defined, with a possible last
> + * chunk smaller that the others.
> + *
> + * @writesize:         Full page size on which the layout applies
> + * @chunk:             Desired ECC chunk size on which the layout applies
> + * @strength:          Desired ECC strength (per chunk size bytes) on which the
> + *                     layout applies
> + * @full_chunk_cnt:    Number of full-sized chunks, which is the number of
> + *                     repetitions of the pattern:
> + *                     (data_bytes + spare_bytes + ecc_bytes).
> + * @data_bytes:                Number of data bytes per chunk
> + * @spare_bytes:       Number of spare bytes per chunk
> + * @ecc_bytes:         Number of ecc bytes per chunk
> + * @last_chunk_cnt:    If there is a last chunk with a different size than
> + *                     the first ones, the next fields may not be empty
> + * @last_data_bytes:   Number of data bytes in the last chunk
> + * @last_spare_bytes:  Number of spare bytes in the last chunk
> + * @last_ecc_bytes:    Number of ecc bytes in the last chunk
> + */
> +struct marvell_hw_ecc_layout {
> +       /* Constraints */
> +       int writesize;
> +       int chunk;
> +       int strength;
> +       /* Corresponding layout */
> +       int full_chunk_cnt;
> +       int data_bytes;
> +       int spare_bytes;
> +       int ecc_bytes;
> +       int last_chunk_cnt;
> +       int last_data_bytes;
> +       int last_spare_bytes;
> +       int last_ecc_bytes;
> +};
> +
> +#define MARVELL_LAYOUT(ws, dc, ds, fcc, db, sb, eb, lcc, ldb, lsb, leb) \
> +       {                                                               \
> +               .writesize = ws,                                        \
> +               .chunk = dc,                                            \
> +               .strength = ds,                                         \
> +               .full_chunk_cnt = fcc,                                  \
> +               .data_bytes = db,                                       \
> +               .spare_bytes = sb,                                      \
> +               .ecc_bytes = eb,                                        \
> +               .last_chunk_cnt = lcc,                                  \
> +               .last_data_bytes = ldb,                                 \
> +               .last_spare_bytes = lsb,                                \
> +               .last_ecc_bytes = leb,                                  \
> +       }
> +
> +/* Layouts explained in AN-379_Marvell_SoC_NFC_ECC */
> +static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
> +       MARVELL_LAYOUT(  512,   512,  1,  1,  512,  8,  8,  0,  0,  0,  0),
> +       MARVELL_LAYOUT( 2048,   512,  1,  1, 2048, 40, 24,  0,  0,  0,  0),
> +       MARVELL_LAYOUT( 2048,   512,  4,  1, 2048, 32, 30,  0,  0,  0,  0),
> +       MARVELL_LAYOUT( 4096,   512,  4,  2, 2048, 32, 30,  0,  0,  0,  0),
> +       MARVELL_LAYOUT( 4096,   512,  8,  4, 1024,  0, 30,  1,  0, 64, 30),
> +};
> +
> +/*
> + * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
> + * is made by a field in NDCB0 register, and in another field in NDCB2 register.
> + * The datasheet describes the logic with an error: ADDR5 field is once
> + * declared at the beginning of NDCB2, and another time at its end. Because the
> + * ADDR5 field of NDCB2 may be used by other bytes, it would be more logical
> + * to use the last bit of this field instead of the first ones.
> + *
> + * @cs:                        Wanted CE lane.
> + * @ndcb0_csel:                Value of the NDCB0 register with or without the flag
> + *                     selecting the wanted CE lane. This is set once when
> + *                     the Device Tree is probed.
> + * @rb:                        Ready/Busy pin for the flash chip
> + */
> +struct marvell_nand_chip_sel {
> +       unsigned int cs;
> +       u32 ndcb0_csel;
> +       unsigned int rb;
> +};
> +
> +/*
> + * NAND chip structure: stores NAND chip device related information
> + *
> + * @chip:              Base NAND chip structure
> + * @node:              Used to store NAND chips into a list
> + * @layout             NAND layout when using hardware ECC
> + * @ndtr0              Timing registers 0 value for this NAND chip
> + * @ndtr1              Timing registers 1 value for this NAND chip
> + * @selected_die:      Current active CS
> + * @nsels:             Number of CS lines required by the NAND chip
> + * @sels:              Array of CS lines descriptions
> + */
> +struct marvell_nand_chip {
> +       struct nand_chip chip;
> +       struct list_head node;
> +       const struct marvell_hw_ecc_layout *layout;
> +       u32 ndtr0;
> +       u32 ndtr1;
> +       int addr_cyc;
> +       int selected_die;
> +       unsigned int nsels;
> +       struct marvell_nand_chip_sel sels[0];
> +};
> +
> +static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip)
> +{
> +       return container_of(chip, struct marvell_nand_chip, chip);
> +}
> +
> +static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
> +                                                       *nand)
> +{
> +       return &nand->sels[nand->selected_die];
> +}
> +
> +/*
> + * NAND controller capabilities for distinction between compatible strings
> + *
> + * @max_cs_nb:         Number of Chip Select lines available
> + * @max_rb_nb:         Number of Ready/Busy lines available
> + * @need_system_controller: Indicates if the SoC needs to have access to the
> + *                      system controller (ie. to enable the NAND controller)
> + * @legacy_of_bindings:        Indicates if DT parsing must be done using the old
> + *                     fashion way
> + * @is_nfcv2:          NFCv2 has numerous enhancements compared to NFCv1, ie.
> + *                     BCH error detection and correction algorithm,
> + *                     NDCB3 register has been added
> + * @use_dma:           Use dma for data transfers
> + */
> +struct marvell_nfc_caps {
> +       unsigned int max_cs_nb;
> +       unsigned int max_rb_nb;
> +       bool need_system_controller;
> +       bool legacy_of_bindings;
> +       bool is_nfcv2;
> +       bool use_dma;
> +};
> +
> +/*
> + * NAND controller structure: stores Marvell NAND controller information
> + *
> + * @controller:                Base controller structure
> + * @dev:               Parent device (used to print error messages)
> + * @regs:              NAND controller registers
> + * @ecc_clk:           ECC block clock, two times the NAND controller clock
> + * @complete:          Completion object to wait for NAND controller events
> + * @assigned_cs:       Bitmask describing already assigned CS lines
> + * @chips:             List containing all the NAND chips attached to
> + *                     this NAND controller
> + * @caps:              NAND controller capabilities for each compatible string
> + * @buf:               Controller local buffer to store a part of the read
> + *                     buffer when the read operation was not 8 bytes aligned
> + *                     as is the FIFO.
> + * @buf_pos:           Position in the 'buf' buffer
> + * @dma_chan:          DMA channel (NFCv1 only)
> + * @dma_buf:           32-bit aligned buffer for DMA transfers (NFCv1 only)
> + */
> +struct marvell_nfc {
> +       struct nand_hw_control controller;
> +       struct device *dev;
> +       void __iomem *regs;
> +       struct clk *ecc_clk;
> +       struct completion complete;
> +       unsigned long assigned_cs;
> +       struct list_head chips;
> +       struct nand_chip *selected_chip;
> +       const struct marvell_nfc_caps *caps;
> +
> +       /*
> +        * Buffer handling: @buf will be accessed byte-per-byter but also
> +        * int-per-int when exchanging data with the NAND controller FIFO,
> +        * 32-bit alignment is then required.
> +        */
> +       u8 buf[FIFO_DEPTH] __aligned(sizeof(u32));
> +       int buf_pos;
> +
> +       /* DMA (NFCv1 only) */
> +       bool use_dma;
> +       struct dma_chan *dma_chan;
> +       u8 *dma_buf;
> +};
> +
> +static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
> +{
> +       return container_of(ctrl, struct marvell_nfc, controller);
> +}
> +
> +/*
> + * NAND controller timings expressed in NAND Controller clock cycles
> + *
> + * @tRP:               ND_nRE pulse width
> + * @tRH:               ND_nRE high duration
> + * @tWP:               ND_nWE pulse time
> + * @tWH:               ND_nWE high duration
> + * @tCS:               Enable signal setup time
> + * @tCH:               Enable signal hold time
> + * @tADL:              Address to write data delay
> + * @tAR:               ND_ALE low to ND_nRE low delay
> + * @tWHR:              ND_nWE high to ND_nRE low for status read
> + * @tRHW:              ND_nRE high duration, read to write delay
> + * @tR:                        ND_nWE high to ND_nRE low for read
> + */
> +struct marvell_nfc_timings {
> +       /* NDTR0 fields */
> +       unsigned int tRP;
> +       unsigned int tRH;
> +       unsigned int tWP;
> +       unsigned int tWH;
> +       unsigned int tCS;
> +       unsigned int tCH;
> +       unsigned int tADL;
> +       /* NDTR1 fields */
> +       unsigned int tAR;
> +       unsigned int tWHR;
> +       unsigned int tRHW;
> +       unsigned int tR;
> +};
> +
> +/*
> + * Derives a duration in numbers of clock cycles.
> + *
> + * @ps: Duration in pico-seconds
> + * @period_ns:  Clock period in nano-seconds
> + *
> + * Convert the duration in nano-seconds, then divide by the period and
> + * return the number of clock periods.
> + */
> +#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns))
> +
> +/*
> + * NAND driver structure filled during the parsing of the ->exec_op() subop
> + * subset of instructions.
> + *
> + * @ndcb:              Array for the values of the NDCBx registers
> + * @cle_ale_delay_ns:  Optional delay after the last CMD or ADDR cycle
> + * @rdy_timeout_ms:    Timeout for waits on Ready/Busy pin
> + * @rdy_delay_ns:      Optional delay after waiting for the RB pin
> + * @data_delay_ns:     Optional delay after the data xfer
> + * @data_instr_idx:    Index of the data instruction in the subop
> + * @data_instr:                Pointer to the data instruction in the subop
> + */
> +struct marvell_nfc_op {
> +       u32 ndcb[4];
> +       unsigned int cle_ale_delay_ns;
> +       unsigned int rdy_timeout_ms;
> +       unsigned int rdy_delay_ns;
> +       unsigned int data_delay_ns;
> +       unsigned int data_instr_idx;
> +       const struct nand_op_instr *data_instr;
> +};
> +
> +/*
> + * Internal helper to conditionnally apply a delay (from the above structure,
> + * most of the time).
> + */
> +static void cond_delay(unsigned int ns)
> +{
> +       if (!ns)
> +               return;
> +
> +       if (ns < 10000)
> +               ndelay(ns);
> +       else
> +               udelay(DIV_ROUND_UP(ns, 1000));
> +}
> +
> +/*
> + * Internal helper to mimic core functions whithout having to distinguish if
> + * this is the first read operation on the page or not and hence choose the
> + * right function.
> + */
> +int read_page_data(struct nand_chip *chip, unsigned int page,
> +                  unsigned int column, void *buf, unsigned int len)
> +{
> +       if (!column)
> +               return nand_read_page_op(chip, page, column, buf, len);
> +       else
> +               return nand_change_read_column_op(chip, column, buf, len,
> +                                                 false);
> +}
> +
> +/*
> + * The controller has many flags that could generate interrupts, most of them
> + * are disabled and polling is used. For the very slow signals, using interrupts
> + * may relax the CPU charge.
> + */
> +static void marvell_nfc_disable_int(struct marvell_nfc *nfc, u32 int_mask)
> +{
> +       u32 reg;
> +
> +       /* Writing 1 disables the interrupt */
> +       reg = readl_relaxed(nfc->regs + NDCR);
> +       writel_relaxed(reg | int_mask, nfc->regs + NDCR);
> +}
> +
> +static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
> +{
> +       u32 reg;
> +
> +       /* Writing 0 enables the interrupt */
> +       reg = readl_relaxed(nfc->regs + NDCR);
> +       writel_relaxed(reg & ~int_mask, nfc->regs + NDCR);
> +}
> +
> +static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
> +{
> +       writel_relaxed(int_mask, nfc->regs + NDSR);
> +}
> +
> +/*
> + * The core may ask the controller to use only 8-bit accesses while usually
> + * using 16-bit accesses. Later function may blindly call this one with a
> + * boolean to indicate if 8-bit accesses must be enabled of disabled without
> + * knowing if 16-bit accesses are actually in use.
> + */
> +static void marvell_nfc_force_byte_access(struct nand_chip *chip,
> +                                         bool force_8bit)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr;
> +
> +       if (!(chip->options & NAND_BUSWIDTH_16))
> +               return;
> +
> +       ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       if (force_8bit)
> +               ndcr &= ~(NDCR_DWIDTH_M | NDCR_DWIDTH_C);
> +       else
> +               ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
> +
> +       writel_relaxed(ndcr, nfc->regs + NDCR);
> +}
> +
> +static int marvell_nfc_wait_ndrun(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 val;
> +       int ret;
> +
> +       /*
> +        * The command is being processed, wait for the ND_RUN bit to be
> +        * cleared by the NFC. If not, we must clear it by hand.
> +        */
> +       ret = readl_relaxed_poll_timeout(nfc->regs + NDCR, val,
> +                                        (val & NDCR_ND_RUN) == 0,
> +                                        POLL_PERIOD, POLL_TIMEOUT);
> +       if (ret) {
> +               dev_err(nfc->dev, "Timeout on NAND controller run mode\n");
> +               writel_relaxed(readl_relaxed(nfc->regs + NDCR) & ~NDCR_ND_RUN,
> +                              nfc->regs + NDCR);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +/*
> + * Any time a command has to be sent to the controller, the following sequence
> + * has to be followed:
> + * - call marvell_nfc_prepare_cmd()
> + *      -> activate the ND_RUN bit that will kind of 'start a job'
> + *      -> wait the signal indicating the NFC is waiting for a command
> + * - send the command (cmd and address cycles)
> + * - enventually send or receive the data
> + * - call marvell_nfc_end_cmd() with the corresponding flag
> + *      -> wait the flag to be triggered or cancel the job with a timeout
> + *
> + * The following functions are helpers to do this job and keep in the
> + * specialized functions the code that really does the operations.
> + */
> +static int marvell_nfc_prepare_cmd(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr, val;
> +       int ret;
> +
> +       /* Poll ND_RUN and clear NDSR before issuing any command */
> +       ret = marvell_nfc_wait_ndrun(chip);
> +       if (ret) {
> +               dev_err(nfc->dev, "Last operation did not suceed\n");
> +               return ret;
> +       }
> +
> +       ndcr = readl_relaxed(nfc->regs + NDCR);
> +       writel_relaxed(readl_relaxed(nfc->regs + NDSR), nfc->regs + NDSR);
> +
> +       /* Assert ND_RUN bit and wait the NFC to be ready */
> +       writel_relaxed(ndcr | NDCR_ND_RUN, nfc->regs + NDCR);
> +       ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
> +                                        val & NDSR_WRCMDREQ,
> +                                        POLL_PERIOD, POLL_TIMEOUT);
> +       if (ret) {
> +               dev_err(nfc->dev, "Timeout on WRCMDRE\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       /* Command may be written, clear WRCMDREQ status bit */
> +       writel_relaxed(NDSR_WRCMDREQ, nfc->regs + NDSR);
> +
> +       return 0;
> +}
> +
> +static void marvell_nfc_send_cmd(struct nand_chip *chip,
> +                                struct marvell_nfc_op *nfc_op)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +
> +       dev_dbg(nfc->dev,
> +               "NDCB0: 0x%08x\nNDCB1: 0x%08x\nNDCB2: 0x%08x\nNDCB3: 0x%08x\n",
> +               nfc_op->ndcb[0], nfc_op->ndcb[1], nfc_op->ndcb[2],
> +               nfc_op->ndcb[3]);
> +
> +       writel_relaxed(to_nand_sel(marvell_nand)->ndcb0_csel | nfc_op->ndcb[0],
> +                      nfc->regs + NDCB0);
> +       writel_relaxed(nfc_op->ndcb[1], nfc->regs + NDCB0);
> +       writel(nfc_op->ndcb[2], nfc->regs + NDCB0);
> +
> +       /*
> +        * Write NDCB0 four times only if LEN_OVRD is set or if ADDR6 or ADDR7
> +        * fields are used (only available on NFCv2).
> +        */
> +       if (nfc_op->ndcb[0] & NDCB0_LEN_OVRD ||
> +           (nfc_op->ndcb[0] & NDCB0_ADDR_CYC(6)) == NDCB0_ADDR_CYC(6)) {
> +               if (nfc->caps->is_nfcv2)
> +                       writel(nfc_op->ndcb[3], nfc->regs + NDCB0);
> +               else
> +                       dev_err(nfc->dev,
> +                               "NDCB3 does not exist on NFCv1 and should not be written\n");
> +       }
> +}
> +
> +static int marvell_nfc_end_cmd(struct nand_chip *chip, int flag,
> +                              const char *label)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 val;
> +       int ret;
> +
> +       ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
> +                                        val & flag,
> +                                        POLL_PERIOD, POLL_TIMEOUT);
> +
> +       if (ret) {
> +               dev_err(nfc->dev, "Timeout on %s (NDSR: 0x%08x)\n",
> +                       label, val);
> +               if (nfc->dma_chan)
> +                       dmaengine_terminate_all(nfc->dma_chan);
> +               return ret;
> +       }
> +
> +       /*
> +        * DMA function uses this helper to poll on CMDD bits without wanting
> +        * them to be bleared.
> +        */
> +       if (nfc->use_dma && (readl(nfc->regs + NDCR) & NDCR_DMA_EN))
> +               return 0;
> +
> +       writel_relaxed(flag, nfc->regs + NDSR);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       int cs_flag = NDSR_CMDD(to_nand_sel(marvell_nand)->ndcb0_csel);
> +
> +       return marvell_nfc_end_cmd(chip, cs_flag, "CMDD");
> +}
> +
> +static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       int ret;
> +
> +       /* Timeout is expressed in ms */
> +       if (!timeout_ms)
> +               timeout_ms = IRQ_TIMEOUT;
> +
> +       init_completion(&nfc->complete);
> +
> +       marvell_nfc_enable_int(nfc, NDCR_RDYM);
> +       ret = wait_for_completion_timeout(&nfc->complete,
> +                                         msecs_to_jiffies(timeout_ms));
> +       marvell_nfc_disable_int(nfc, NDCR_RDYM);
> +       marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
> +       if (!ret) {
> +               dev_err(nfc->dev, "Timeout waiting for RB signal\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
> +static void marvell_nfc_select_chip(struct mtd_info *mtd, 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;
> +
> +       if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die)
> +               return;
> +
> +       if (die_nr < 0 || die_nr >= marvell_nand->nsels) {
> +               nfc->selected_chip = NULL;
> +               marvell_nand->selected_die = -1;
> +               return;
> +       }
> +
> +       /*
> +        * Do not change the timing registers when using the DT property
> +        * marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
> +        * marvell_nand structure are supposedly empty.
> +        */
> +       if (marvell_nand->ndtr0 && marvell_nand->ndtr1) {
> +               writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
> +               writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
> +       }
> +
> +       ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       /* Ensure controller is not blocked; also clear some fields */
> +       ndcr &= ~(NDCR_ND_RUN | NDCR_DWIDTH_M | NDCR_DWIDTH_C |
> +                 NDCR_PAGE_SZ(2048));
> +
> +       /* Adapt bus width */
> +       if (chip->options & NAND_BUSWIDTH_16)
> +               ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
> +
> +       /* Page size as seen by the controller, either 512B or 2kiB */
> +       ndcr |= NDCR_PAGE_SZ(mtd->writesize);
> +
> +       /* Update the control register */
> +       writel_relaxed(ndcr,  nfc->regs + NDCR);
> +
> +       /* Also reset the interrupt status register */
> +       marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
> +
> +       nfc->selected_chip = chip;
> +       marvell_nand->selected_die = die_nr;
> +}
> +
> +static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
> +{
> +       struct marvell_nfc *nfc = dev_id;
> +       u32 st = readl_relaxed(nfc->regs + NDSR);
> +       u32 ien = (~readl_relaxed(nfc->regs + NDCR)) & NDCR_ALL_INT;
> +
> +       /*
> +        * RDY interrupt mask is one bit in NDCR while there are two status
> +        * bit in NDSR (RDY[cs0/cs2] and RDY[cs1/cs3]).
> +        */
> +       if (st & NDSR_RDY(1))
> +               st |= NDSR_RDY(0);
> +
> +       if (!(st & ien))
> +               return IRQ_NONE;
> +
> +       marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
> +
> +       if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
> +               complete(&nfc->complete);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/* HW ECC related functions */
> +static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       if (!(ndcr & NDCR_ECC_EN)) {
> +               writel(ndcr | NDCR_ECC_EN, nfc->regs + NDCR);
> +
> +               /*
> +                * When enabling BCH, set threshold to 0 to always know the
> +                * number of corrected bitflips.
> +                */
> +               if (chip->ecc.algo == NAND_ECC_BCH)
> +                       writel(NDECCTRL_BCH_EN, nfc->regs + NDECCCTRL);
> +       }
> +}
> +
> +static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       if (ndcr & NDCR_ECC_EN) {
> +               writel_relaxed(ndcr & ~NDCR_ECC_EN, nfc->regs + NDCR);
> +               if (chip->ecc.algo == NAND_ECC_BCH)
> +                       writel_relaxed(0, nfc->regs + NDECCCTRL);
> +       }
> +}
> +
> +/*
> + * Enable/disable spare area
> + *
> + * NFCv1 needs it (see Hamming related functions). NFCv2 uses LEN_OVRD and thus
> + * does not need this bit to be set.
> + */
> +static void marvell_nfc_enable_spare(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       if (!(ndcr & NDCR_SPARE_EN))
> +               writel(ndcr | NDCR_SPARE_EN, nfc->regs + NDCR);
> +}
> +
> +static void marvell_nfc_disable_spare(struct nand_chip *chip)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       u32 ndcr = readl_relaxed(nfc->regs + NDCR);
> +
> +       if (ndcr & NDCR_SPARE_EN)
> +               writel_relaxed(ndcr & ~NDCR_SPARE_EN, nfc->regs + NDCR);
> +}
> +
> +/* DMA related helpers */
> +static void marvell_nfc_enable_dma(struct marvell_nfc *nfc)
> +{
> +       u32 reg;
> +
> +       reg = readl_relaxed(nfc->regs + NDCR);
> +       writel_relaxed(reg | NDCR_DMA_EN, nfc->regs + NDCR);
> +}
> +
> +static void marvell_nfc_disable_dma(struct marvell_nfc *nfc)
> +{
> +       u32 reg;
> +
> +       reg = readl_relaxed(nfc->regs + NDCR);
> +       writel_relaxed(reg & ~NDCR_DMA_EN, nfc->regs + NDCR);
> +}
> +
> +/* Read/write PIO/DMA accessors */
> +static int marvell_nfc_xfer_data_dma(struct marvell_nfc *nfc,
> +                                    enum dma_data_direction direction,
> +                                    unsigned int len)
> +{
> +       unsigned int dma_len = min_t(int, ALIGN(len, 32), MAX_CHUNK_SIZE);
> +       struct dma_async_tx_descriptor *tx;
> +       struct scatterlist sg;
> +       dma_cookie_t cookie;
> +       int ret;
> +
> +       marvell_nfc_enable_dma(nfc);
> +       /* Prepare the DMA transfer */
> +       sg_init_one(&sg, nfc->dma_buf, dma_len);
> +       dma_map_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
> +       tx = dmaengine_prep_slave_sg(nfc->dma_chan, &sg, 1,
> +                                    direction == DMA_FROM_DEVICE ?
> +                                    DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
> +                                    DMA_PREP_INTERRUPT);
> +       if (!tx) {
> +               dev_err(nfc->dev, "Could not prepare DMA S/G list\n");
> +               return -ENXIO;
> +       }
> +
> +       /* Do the task and wait for it to finish */
> +       cookie = dmaengine_submit(tx);
> +       ret = dma_submit_error(cookie);
> +       if (ret)
> +               return -EIO;
> +
> +       dma_async_issue_pending(nfc->dma_chan);
> +       ret = marvell_nfc_wait_cmdd(nfc->selected_chip);
> +       dma_unmap_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
> +       marvell_nfc_disable_dma(nfc);
> +       if (ret) {
> +               dev_err(nfc->dev, "Timeout waiting for DMA (status: %d)\n",
> +                       dmaengine_tx_status(nfc->dma_chan, cookie, NULL));
> +               dmaengine_terminate_all(nfc->dma_chan);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_xfer_data_in_pio(struct marvell_nfc *nfc, u8 *in,
> +                                       unsigned int len)
> +{
> +       unsigned int last_len = len % FIFO_DEPTH;
> +       unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
> +       int i;
> +
> +       for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
> +               ioread32_rep(nfc->regs + NDDB, in + i, FIFO_REP(FIFO_DEPTH));
> +
> +       if (last_len) {
> +               ioread32_rep(nfc->regs + NDDB, nfc->buf, FIFO_REP(FIFO_DEPTH));
> +               memcpy(in + last_full_offset, nfc->buf, last_len);
> +       }
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_xfer_data_out_pio(struct marvell_nfc *nfc, const u8 *out,
> +                                        unsigned int len)
> +{
> +       unsigned int last_len = len % FIFO_DEPTH;
> +       unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
> +       int i;
> +
> +       for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
> +               iowrite32_rep(nfc->regs + NDDB, out + i, FIFO_REP(FIFO_DEPTH));
> +
> +       if (last_len) {
> +               memcpy(nfc->buf, out + last_full_offset, last_len);
> +               iowrite32_rep(nfc->regs + NDDB, nfc->buf, FIFO_REP(FIFO_DEPTH));
> +       }
> +
> +       return 0;
> +}
> +
> +static void marvell_nfc_hw_ecc_correct(struct nand_chip *chip,
> +                                      u8 *data, int data_len,
> +                                      u8 *oob, int oob_len,
> +                                      unsigned int *max_bitflips)
> +{
> +       struct mtd_info *mtd = nand_to_mtd(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       int bf = 0;
> +       u32 ndsr;
> +
> +       ndsr = readl_relaxed(nfc->regs + NDSR);
> +
> +       /* Check uncorrectable error flag */
> +       if (ndsr & NDSR_UNCERR) {
> +               writel_relaxed(ndsr, nfc->regs + NDSR);
> +
> +               /*
> +                * Blank pages (all 0xFF) with no ECC are recognized as bad
> +                * because hardware ECC engine expects non-empty ECC values
> +                * in that case, so whenever an uncorrectable error occurs,
> +                * check if the page is actually blank or not.
> +                *
> +                * It is important to check the emptyness only on oob_len,
> +                * which only covers the spare bytes because after a read with
> +                * ECC enabled, the ECC bytes in the buffer have been set by the
> +                * ECC engine, so they are not 0xFF.
> +                */
> +               if (!data)
> +                       data_len = 0;
> +               if (!oob)
> +                       oob_len = 0;
> +               bf = nand_check_erased_ecc_chunk(data, data_len, NULL, 0,
> +                                                oob, oob_len,
> +                                                chip->ecc.strength);
> +               if (bf < 0) {
> +                       mtd->ecc_stats.failed++;
> +                       return;
> +               }
> +       }
> +
> +       /* Check correctable error flag */
> +       if (ndsr & NDSR_CORERR) {
> +               writel_relaxed(ndsr, nfc->regs + NDSR);
> +
> +               if (chip->ecc.algo == NAND_ECC_BCH)
> +                       bf = NDSR_ERRCNT(ndsr);
> +               else
> +                       bf = 1;
> +       }
> +
> +       /*
> +        * Derive max_bitflips either from the number of bitflips detected by
> +        * the hardware ECC engine or by nand_check_erased_ecc_chunk().
> +        */
> +       mtd->ecc_stats.corrected += bf;
> +       *max_bitflips = max_t(unsigned int, *max_bitflips, bf);
> +}
> +
> +/* Hamming read helpers */
> +static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip, u8 *buf,
> +                                              bool oob_required, bool raw,
> +                                              int page)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       struct marvell_nfc_op nfc_op = {
> +               .ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
> +                          NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
> +                          NDCB0_DBC |
> +                          NDCB0_CMD1(NAND_CMD_READ0) |
> +                          NDCB0_CMD2(NAND_CMD_READSTART),
> +               .ndcb[1] = NDCB1_ADDRS(page),
> +               .ndcb[2] = NDCB2_ADDR5(page),
> +       };
> +       unsigned int oob_bytes = 0;
> +       int ret;
> +
> +       /* NFCv2 needs more information about the operation being executed */
> +       if (nfc->caps->is_nfcv2)
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       if (oob_required) {
> +               marvell_nfc_enable_spare(chip);
> +               oob_bytes = lt->spare_bytes;
> +               if (raw)
> +                       oob_bytes += lt->ecc_bytes;
> +       }
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
> +                                 "RDDREQ while draining FIFO (data/oob)");
> +       if (ret)
> +               return ret;
> +
> +       /* Read the page then the OOB area */
> +       if (nfc->use_dma) {
> +               marvell_nfc_xfer_data_dma(nfc, DMA_FROM_DEVICE,
> +                                         lt->data_bytes + oob_bytes);
> +               memcpy(buf, nfc->dma_buf, lt->data_bytes);
> +               memcpy(chip->oob_poi + (raw ? 0 : lt->ecc_bytes),
> +                      nfc->dma_buf + lt->data_bytes, oob_bytes);
> +       } else {
> +               marvell_nfc_xfer_data_in_pio(nfc, buf, lt->data_bytes);
> +               marvell_nfc_xfer_data_in_pio(nfc, chip->oob_poi, oob_bytes);
> +       }
> +
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       if (oob_required)
> +               marvell_nfc_disable_spare(chip);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
> +                                               struct nand_chip *chip, u8 *buf,
> +                                               int oob_required, int page)
> +{
> +       return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, oob_required,
> +                                                  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)
> +{
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int max_bf = 0;
> +
> +       /*
> +        * Reading/Writing a given page must always be performed with the same
> +        * configuration regarding the state of the SPARE_EN bit or ECC bytes
> +        * will not be present at the same location (writing only data, without
> +        * SPARE_EN will put the ECC bytes at the beginning of the OOB area,
> +        * while writing with the SPARE_EN bit (hence, also writing free OOB
> +        * bytes) will put first the spare bytes then, at the end of the OOB
> +        * area, the ECC bytes. Choices has been made to always read/write OOB
> +        * area (padding with 0xFF is handled by the core for writes).
> +        */
> +
> +       marvell_nfc_enable_hw_ecc(chip);
> +       marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, true, false, page);
> +       marvell_nfc_hw_ecc_correct(chip, buf, lt->data_bytes, NULL, 0, &max_bf);
> +       marvell_nfc_disable_hw_ecc(chip);
> +
> +       /*
> +        * Re-read the OOB area in raw mode to get the ECC bytes if the OOB area
> +        * is needed.
> +        */
> +       if (oob_required)
> +               chip->ecc.read_oob_raw(mtd, chip, page);
> +
> +       return max_bf;
> +}
> +
> +/*
> + * Spare area in Hamming layouts is not protected by the ECC engine (even if
> + * 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)
> +{
> +       /* Invalidate page cache */
> +       chip->pagebuf = -1;
> +
> +       return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf, true,
> +                                                  true, page);
> +}
> +
> +/* Hamming write helpers */
> +static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
> +                                               const u8 *buf,
> +                                               bool oob_required, bool raw,
> +                                               int page)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       struct marvell_nfc_op nfc_op = {
> +               .ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) |
> +                          NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
> +                          NDCB0_CMD1(NAND_CMD_SEQIN) |
> +                          NDCB0_CMD2(NAND_CMD_PAGEPROG) |
> +                          NDCB0_DBC,
> +               .ndcb[1] = NDCB1_ADDRS(page),
> +               .ndcb[2] = NDCB2_ADDR5(page),
> +       };
> +       int oob_bytes = 0;
> +       int ret;
> +
> +       /* NFCv2 needs more information about the operation being executed */
> +       if (nfc->caps->is_nfcv2)
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       if (oob_required) {
> +               marvell_nfc_enable_spare(chip);
> +               oob_bytes = lt->spare_bytes;
> +               if (raw)
> +                       oob_bytes += lt->ecc_bytes;
> +       }
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
> +                                 "WRDREQ while loading FIFO (data)");
> +       if (ret)
> +               return ret;
> +
> +       /* Write the page then the OOB area */
> +       if (nfc->use_dma) {
> +               memcpy(nfc->dma_buf, buf, lt->data_bytes);
> +               if (oob_required)
> +                       memcpy(nfc->dma_buf + lt->data_bytes, chip->oob_poi,
> +                              oob_bytes);
> +               marvell_nfc_xfer_data_dma(nfc, DMA_TO_DEVICE, lt->data_bytes +
> +                                         lt->ecc_bytes + lt->spare_bytes);
> +       } else {
> +               marvell_nfc_xfer_data_out_pio(nfc, buf, lt->data_bytes);
> +               if (oob_required)
> +                       marvell_nfc_xfer_data_out_pio(nfc, chip->oob_poi,
> +                                                     oob_bytes);
> +       }
> +
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       ret = marvell_nfc_wait_op(chip,
> +                                 chip->data_interface.timings.sdr.tPROG_max);
> +       if (ret)
> +               return ret;
> +
> +       if (oob_required)
> +               marvell_nfc_disable_spare(chip);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
> +                                                struct nand_chip *chip,
> +                                                const u8 *buf,
> +                                                int oob_required, int page)
> +{
> +       return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, oob_required,
> +                                                   true, page);
> +}
> +
> +static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
> +                                            struct nand_chip *chip,
> +                                            const u8 *buf,
> +                                            int oob_required, int page)
> +{
> +       int ret;
> +
> +       /*
> +        * Reading/Writing a given page must always be performed with the same
> +        * configuration regarding the state of the SPARE_EN bit or ECC bytes
> +        * will not be present at the same location (writing only data, without
> +        * SPARE_EN will put the ECC bytes at the beginning of the OOB area,
> +        * while writing with the SPARE_EN bit (hence, also writing free OOB
> +        * bytes) will put first the spare bytes then, at the end of the OOB
> +        * area, the ECC bytes. Choices has been made to always read/write OOB
> +        * area (padding with 0xFF is handled by the core for writes).
> +        */
> +
> +       marvell_nfc_enable_hw_ecc(chip);
> +       ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, true, false,
> +                                                  page);
> +       marvell_nfc_disable_hw_ecc(chip);
> +
> +       return ret;
> +}
> +
> +/*
> + * Spare area in Hamming layouts is not protected by the ECC engine (even if
> + * 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,
> +                                               int page)
> +{
> +       /* Invalidate page cache */
> +       chip->pagebuf = -1;
> +
> +       memset(chip->data_buf, 0xFF, mtd->writesize);
> +
> +       return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf, true,
> +                                                   true, page);
> +}
> +
> +/* BCH read helpers */
> +static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
> +                                               struct nand_chip *chip, u8 *buf,
> +                                               int oob_required, int page)
> +{
> +       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;
> +       int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
> +               (lt->last_chunk_cnt * lt->last_spare_bytes);
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       int data_len = lt->data_bytes;
> +       int spare_len = lt->spare_bytes;
> +       int ecc_len = lt->ecc_bytes;
> +       int chunk;
> +
> +       if (oob_required)
> +               memset(chip->oob_poi, 0xFF, mtd->oobsize);
> +
> +       nand_read_page_op(chip, page, 0, NULL, 0);
> +
> +       for (chunk = 0; chunk < nchunks; chunk++) {
> +               int offset_in_page = chunk * chunk_size;
> +
> +               /* Update last chunk length */
> +               if (chunk >= lt->full_chunk_cnt) {
> +                       data_len = lt->last_data_bytes;
> +                       spare_len = lt->last_spare_bytes;
> +                       ecc_len = lt->last_ecc_bytes;
> +               }
> +
> +               nand_change_read_column_op(chip, offset_in_page, buf,
> +                                          lt->data_bytes, false);
> +               buf += lt->data_bytes;
> +
> +               if (!oob_required)
> +                       continue;
> +
> +               offset_in_page += data_len;
> +               nand_change_read_column_op(chip, offset_in_page,
> +                                          oob + (lt->spare_bytes * chunk),
> +                                          spare_len, false);
> +
> +               offset_in_page += spare_len;
> +               nand_change_read_column_op(chip, offset_in_page,
> +                                          oob + ecc_offset +
> +                                          (ALIGN(lt->ecc_bytes, 32) * chunk),
> +                                          ecc_len, false);
> +       }
> +
> +       return 0;
> +}
> +
> +static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
> +                                             u8 *data, unsigned int data_len,
> +                                             u8 *spare, unsigned int spare_len,
> +                                             int page)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       int i, ret;
> +       struct marvell_nfc_op nfc_op = {
> +               .ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
> +                          NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
> +                          NDCB0_LEN_OVRD,
> +               .ndcb[1] = NDCB1_ADDRS(page),
> +               .ndcb[2] = NDCB2_ADDR5(page),
> +       };
> +
> +       /*
> +        * Reading spare area is mandatory when using HW ECC or read operation
> +        * will trigger uncorrectable ECC errors, but do not read ECC here.
> +        */
> +       nfc_op.ndcb[3] = data_len + spare_len;
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return;
> +
> +       if (chunk == 0)
> +               nfc_op.ndcb[0] |= NDCB0_DBC |
> +                                 NDCB0_CMD1(NAND_CMD_READ0) |
> +                                 NDCB0_CMD2(NAND_CMD_READSTART);
> +
> +       /*
> +        * Trigger the naked read operation only on the last chunk.
> +        * Otherwise, use monolithic read.
> +        */
> +       if (chunk < nchunks - 1)
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
> +       else
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +
> +       /*
> +        * According to the datasheet, when reading from NDDB
> +        * with BCH enabled, after each 32 bytes reads, we
> +        * have to make sure that the NDSR.RDDREQ bit is set.
> +        *
> +        * Drain the FIFO, 8 32-bit reads at a time, and skip
> +        * the polling on the last read.
> +        *
> +        * Length is a multiple of 32 bytes, hence it is a multiple of 8 too.
> +        *
> +        */
> +
> +       for (i = 0; i < data_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
> +               marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
> +                                   "RDDREQ while draining FIFO (data)");
> +               marvell_nfc_xfer_data_in_pio(nfc, data,
> +                                            FIFO_DEPTH * BCH_SEQ_READS);
> +               data += FIFO_DEPTH * BCH_SEQ_READS;
> +       }
> +
> +       for (i = 0; i < spare_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
> +               marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
> +                                   "RDDREQ while draining FIFO (OOB)");
> +               marvell_nfc_xfer_data_in_pio(nfc, spare,
> +                                            FIFO_DEPTH * BCH_SEQ_READS);
> +               spare += FIFO_DEPTH * BCH_SEQ_READS;
> +       }
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
> +                                           struct nand_chip *chip,
> +                                           u8 *buf, int oob_required,
> +                                           int page)
> +{
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       int data_len = lt->data_bytes;
> +       int spare_len = lt->spare_bytes;
> +       u8 *data = buf;
> +       u8 *spare = chip->oob_poi;
> +       int max_bitflips = 0;
> +       int chunk, ecc_offset_in_page, ecc_offset_in_oob_buf, ecc_len;
> +
> +       /*
> +        * With BCH, OOB is not fully used (and thus not read entirely), not
> +        * expected bytes could show up at the end of the OOB buffer if not
> +        * explicitly erased.
> +        */
> +       if (oob_required)
> +               memset(chip->oob_poi, 0xFF, mtd->oobsize);
> +
> +       marvell_nfc_enable_hw_ecc(chip);
> +
> +       for (chunk = 0; chunk < nchunks; chunk++) {
> +               /* Update length for the last chunk */
> +               if (chunk >= lt->full_chunk_cnt) {
> +                       data_len = lt->last_data_bytes;
> +                       spare_len = lt->last_spare_bytes;
> +               }
> +
> +               /* Read the chunk and detect number of bitflips */
> +               marvell_nfc_hw_ecc_bch_read_chunk(chip, chunk, data, data_len,
> +                                                 spare, spare_len, page);
> +               marvell_nfc_hw_ecc_correct(chip, data, data_len,
> +                                          spare, spare_len, &max_bitflips);
> +
> +               data += data_len;
> +               spare += spare_len;
> +       }
> +
> +       marvell_nfc_disable_hw_ecc(chip);
> +
> +       if (!oob_required)
> +               return max_bitflips;
> +
> +       /*
> +        * Re-read ECC bytes without ECC enabled, else it is garbage and it
> +        * fails the ->correct() call.
> +        */
> +       ecc_len = lt->ecc_bytes;
> +       ecc_offset_in_oob_buf =
> +               (lt->full_chunk_cnt * lt->spare_bytes) +
> +               (lt->last_chunk_cnt * lt->last_spare_bytes);
> +       ecc_offset_in_page = lt->data_bytes + lt->spare_bytes;
> +
> +       for (chunk = 0; chunk < nchunks;) {
> +               /* Do the actual raw read of the ECC bytes */
> +               nand_change_read_column_op(chip, ecc_offset_in_page,
> +                                          chip->oob_poi + ecc_offset_in_oob_buf,
> +                                          ecc_len, false);
> +
> +               chunk++;
> +
> +               /* When using a "last chunk", the ECC size might vary */
> +               if (chunk >= lt->full_chunk_cnt)
> +                       ecc_len = lt->last_ecc_bytes;
> +
> +               /* Increment the offsets where ECC will be read and written */
> +               ecc_offset_in_oob_buf += ALIGN(lt->ecc_bytes, 32);
> +               ecc_offset_in_page += lt->ecc_bytes;
> +               if (chunk < lt->full_chunk_cnt)
> +                       ecc_offset_in_page += lt->data_bytes + lt->spare_bytes;
> +               else
> +                       ecc_offset_in_page += lt->last_data_bytes +
> +                               lt->last_spare_bytes;
> +       }
> +
> +       return max_bitflips;
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
> +                                              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);
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
> +                                          struct nand_chip *chip, int page)
> +{
> +       /* Invalidate page cache */
> +       chip->pagebuf = -1;
> +
> +       return chip->ecc.read_page(mtd, 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,
> +                                                const u8 *buf,
> +                                                int oob_required, int page)
> +{
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       int full_chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
> +       int data_len = lt->data_bytes;
> +       int spare_len = lt->spare_bytes;
> +       int ecc_len = lt->ecc_bytes;
> +       int oob_len = spare_len + ecc_len;
> +       int spare_offset = 0;
> +       int ecc_offset =
> +               (lt->full_chunk_cnt * lt->spare_bytes) +
> +               (lt->last_chunk_cnt * lt->last_spare_bytes);
> +       int chunk;
> +
> +       nand_prog_page_begin_op(chip, page, 0, NULL, 0);
> +
> +       for (chunk = 0; chunk < nchunks; chunk++) {
> +               if (chunk >= lt->full_chunk_cnt) {
> +                       data_len = lt->last_data_bytes;
> +                       spare_len = lt->last_spare_bytes;
> +                       ecc_len = lt->last_ecc_bytes;
> +                       oob_len = spare_len + ecc_len;
> +               }
> +
> +               /* Point to the column of the next chunk */
> +               nand_change_write_column_op(chip, chunk * full_chunk_size,
> +                                           NULL, 0, false);
> +
> +               /* Write the data */
> +               nand_write_data_op(chip, buf + (chunk * lt->data_bytes),
> +                                  data_len, false);
> +
> +               if (!oob_required)
> +                       continue;
> +
> +               /* Write the spare bytes */
> +               if (spare_len)
> +                       nand_write_data_op(chip, chip->oob_poi + spare_offset,
> +                                          spare_len, false);
> +
> +               /* Write the ECC bytes */
> +               if (ecc_len)
> +                       nand_write_data_op(chip, chip->oob_poi + ecc_offset,
> +                                          ecc_len, false);
> +
> +               spare_offset += spare_len;
> +               ecc_offset += ALIGN(ecc_len, 32);
> +       }
> +
> +       return nand_prog_page_end_op(chip);
> +}
> +
> +static int
> +marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
> +                                  const u8 *data, unsigned int data_len,
> +                                  const u8 *spare, unsigned int spare_len,
> +                                  int page)
> +{
> +       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       int ret;
> +       struct marvell_nfc_op nfc_op = {
> +               .ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) | NDCB0_LEN_OVRD,
> +               .ndcb[3] = data_len + spare_len,
> +       };
> +
> +       /*
> +        * First operation dispatches the CMD_SEQIN command, issue the address
> +        * cycles and asks for the first chunk of data.
> +        * All operations in the middle (if any) will issue a naked write and
> +        * also ask for data.
> +        * Last operation dispatches the PAGEPROG command and also asks for the
> +        * last chunk of data.
> +        */
> +       if (chunk == 0) {
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_WRITE_DISPATCH) |
> +                                 NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
> +                                 NDCB0_CMD1(NAND_CMD_SEQIN);
> +               nfc_op.ndcb[1] |= NDCB1_ADDRS(page);
> +               nfc_op.ndcb[2] |= NDCB2_ADDR5(page);
> +       } else if (chunk < nchunks - 1) {
> +               nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_NAKED_RW);
> +       } else {
> +               nfc_op.ndcb[0] |= NDCB0_CMD2(NAND_CMD_PAGEPROG) | NDCB0_DBC |
> +                                 NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
> +       }
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
> +                                 "WRDREQ while loading FIFO (data)");
> +       if (ret)
> +               return ret;
> +
> +       /* Transfer the contents */
> +       iowrite32_rep(nfc->regs + NDDB, data, FIFO_REP(data_len));
> +       iowrite32_rep(nfc->regs + NDDB, spare, FIFO_REP(spare_len));
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
> +                                            struct nand_chip *chip,
> +                                            const u8 *buf,
> +                                            int oob_required, int page)
> +{
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt + lt->last_chunk_cnt;
> +       const u8 *data = buf;
> +       const u8 *spare = chip->oob_poi;
> +       int data_len = lt->data_bytes;
> +       int spare_len = lt->spare_bytes;
> +       int chunk, ret;
> +
> +       /* Spare data will be written anyway, so clear it to avoid garbage */
> +       if (!oob_required)
> +               memset(chip->oob_poi, 0xFF, mtd->oobsize);
> +
> +       marvell_nfc_enable_hw_ecc(chip);
> +
> +       for (chunk = 0; chunk < nchunks; chunk++) {
> +               if (chunk >= lt->full_chunk_cnt) {
> +                       data_len = lt->last_data_bytes;
> +                       spare_len = lt->last_spare_bytes;
> +               }
> +
> +               marvell_nfc_hw_ecc_bch_write_chunk(chip, chunk, data, data_len,
> +                                                  spare, spare_len, page);
> +               data += data_len;
> +               spare += spare_len;
> +
> +               /*
> +                * Waiting only for CMDD or PAGED is not enough, ECC are
> +                * partially written. No flag is set once the operation is
> +                * really finished but the ND_RUN bit is cleared, so wait for it
> +                * before stepping into the next command.
> +                */
> +               marvell_nfc_wait_ndrun(chip);
> +       }
> +
> +       ret = marvell_nfc_wait_op(chip,
> +                                 chip->data_interface.timings.sdr.tPROG_max);
> +
> +       marvell_nfc_disable_hw_ecc(chip);
> +
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
> +                                               struct nand_chip *chip,
> +                                               int page)
> +{
> +       /* 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);
> +}
> +
> +static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
> +                                           struct nand_chip *chip, int page)
> +{
> +       /* 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);
> +}
> +
> +/* NAND framework ->exec_op() hooks and related helpers */
> +static void marvell_nfc_parse_instructions(struct nand_chip *chip,
> +                                          const struct nand_subop *subop,
> +                                          struct marvell_nfc_op *nfc_op)
> +{
> +       const struct nand_op_instr *instr = NULL;
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       bool first_cmd = true;
> +       unsigned int op_id;
> +       int i;
> +
> +       /* Reset the input structure as most of its fields will be OR'ed */
> +       memset(nfc_op, 0, sizeof(struct marvell_nfc_op));
> +
> +       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);
> +
> +               instr = &subop->instrs[op_id];
> +
> +               switch (instr->type) {
> +               case NAND_OP_CMD_INSTR:
> +                       if (first_cmd)
> +                               nfc_op->ndcb[0] |=
> +                                       NDCB0_CMD1(instr->ctx.cmd.opcode);
> +                       else
> +                               nfc_op->ndcb[0] |=
> +                                       NDCB0_CMD2(instr->ctx.cmd.opcode) |
> +                                       NDCB0_DBC;
> +
> +                       nfc_op->cle_ale_delay_ns = instr->delay_ns;
> +                       first_cmd = false;
> +                       break;
> +
> +               case NAND_OP_ADDR_INSTR:
> +                       offset = nand_subop_get_addr_start_off(subop, op_id);
> +                       naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
> +                       addrs = &instr->ctx.addr.addrs[offset];
> +
> +                       nfc_op->ndcb[0] |= NDCB0_ADDR_CYC(naddrs);
> +
> +                       for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
> +                               nfc_op->ndcb[1] |= addrs[i] << (8 * i);
> +
> +                       if (naddrs >= 5)
> +                               nfc_op->ndcb[2] |= NDCB2_ADDR5(addrs[5]);
> +                       if (naddrs >= 6)
> +                               nfc_op->ndcb[3] |= NDCB3_ADDR6(addrs[6]);
> +                       if (naddrs == 7)
> +                               nfc_op->ndcb[3] |= NDCB3_ADDR7(addrs[7]);
> +
> +                       nfc_op->cle_ale_delay_ns = instr->delay_ns;
> +                       break;
> +
> +               case NAND_OP_DATA_IN_INSTR:
> +                       nfc_op->data_instr = instr;
> +                       nfc_op->data_instr_idx = op_id;
> +                       nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ);
> +                       if (nfc->caps->is_nfcv2) {
> +                               nfc_op->ndcb[0] |=
> +                                       NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
> +                                       NDCB0_LEN_OVRD;
> +                               nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
> +                       }
> +                       nfc_op->data_delay_ns = instr->delay_ns;
> +                       break;
> +
> +               case NAND_OP_DATA_OUT_INSTR:
> +                       nfc_op->data_instr = instr;
> +                       nfc_op->data_instr_idx = op_id;
> +                       nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE);
> +                       if (nfc->caps->is_nfcv2) {
> +                               nfc_op->ndcb[0] |=
> +                                       NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
> +                                       NDCB0_LEN_OVRD;
> +                               nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
> +                       }
> +                       nfc_op->data_delay_ns = instr->delay_ns;
> +                       break;
> +
> +               case NAND_OP_WAITRDY_INSTR:
> +                       nfc_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
> +                       nfc_op->rdy_delay_ns = instr->delay_ns;
> +                       break;
> +               }
> +       }
> +}
> +
> +static int marvell_nfc_xfer_data_pio(struct nand_chip *chip,
> +                                    const struct nand_subop *subop,
> +                                    struct marvell_nfc_op *nfc_op)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct nand_op_instr *instr = nfc_op->data_instr;
> +       unsigned int op_id = nfc_op->data_instr_idx;
> +       unsigned int len = nand_subop_get_data_len(subop, op_id);
> +       unsigned int offset = nand_subop_get_data_start_off(subop, op_id);
> +       bool reading = (instr->type == NAND_OP_DATA_IN_INSTR);
> +       int ret;
> +
> +       if (instr->ctx.data.force_8bit)
> +               marvell_nfc_force_byte_access(chip, true);
> +
> +       if (reading) {
> +               u8 *in = instr->ctx.data.buf.in + offset;
> +
> +               ret = marvell_nfc_xfer_data_in_pio(nfc, in, len);
> +       } else {
> +               const u8 *out = instr->ctx.data.buf.out + offset;
> +
> +               ret = marvell_nfc_xfer_data_out_pio(nfc, out, len);
> +       }
> +
> +       if (instr->ctx.data.force_8bit)
> +               marvell_nfc_force_byte_access(chip, false);
> +
> +       return ret;
> +}
> +
> +static int marvell_nfc_monolithic_access_exec(struct nand_chip *chip,
> +                                             const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       bool reading;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +       reading = (nfc_op.data_instr->type == NAND_OP_DATA_IN_INSTR);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
> +                                 "RDDREQ/WRDREQ while draining raw data");
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.cle_ale_delay_ns);
> +
> +       if (reading) {
> +               if (nfc_op.rdy_timeout_ms) {
> +                       ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +                       if (ret)
> +                               return ret;
> +               }
> +
> +               cond_delay(nfc_op.rdy_delay_ns);
> +       }
> +
> +       marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.data_delay_ns);
> +
> +       if (!reading) {
> +               if (nfc_op.rdy_timeout_ms) {
> +                       ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +                       if (ret)
> +                               return ret;
> +               }
> +
> +               cond_delay(nfc_op.rdy_delay_ns);
> +       }
> +
> +       /*
> +        * NDCR ND_RUN bit should be cleared automatically at the end of each
> +        * operation but experience shows that the behavior is buggy when it
> +        * comes to writes (with LEN_OVRD). Clear it by hand in this case.
> +        */
> +       if (!reading) {
> +               struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +
> +               writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
> +                              nfc->regs + NDCR);
> +       }
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_naked_access_exec(struct nand_chip *chip,
> +                                        const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +
> +       /*
> +        * Naked access are different in that they need to be flagged as naked
> +        * by the controller. Reset the controller registers fields that inform
> +        * on the type and refill them according to the ongoing operation.
> +        */
> +       nfc_op.ndcb[0] &= ~(NDCB0_CMD_TYPE(TYPE_MASK) |
> +                           NDCB0_CMD_XTYPE(XTYPE_MASK));
> +       switch (subop->instrs[0].type) {
> +       case NAND_OP_CMD_INSTR:
> +               nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_CMD);
> +               break;
> +       case NAND_OP_ADDR_INSTR:
> +               nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_ADDR);
> +               break;
> +       case NAND_OP_DATA_IN_INSTR:
> +               nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ) |
> +                                 NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
> +               break;
> +       case NAND_OP_DATA_OUT_INSTR:
> +               nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE) |
> +                                 NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
> +               break;
> +       default:
> +               /* This should never happen */
> +               break;
> +       }
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +
> +       if (!nfc_op.data_instr) {
> +               ret = marvell_nfc_wait_cmdd(chip);
> +               cond_delay(nfc_op.cle_ale_delay_ns);
> +               return ret;
> +       }
> +
> +       ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
> +                                 "RDDREQ/WRDREQ while draining raw data");
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * NDCR ND_RUN bit should be cleared automatically at the end of each
> +        * operation but experience shows that the behavior is buggy when it
> +        * comes to writes (with LEN_OVRD). Clear it by hand in this case.
> +        */
> +       if (subop->instrs[0].type == NAND_OP_DATA_OUT_INSTR) {
> +               struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +
> +               writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
> +                              nfc->regs + NDCR);
> +       }
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_naked_waitrdy_exec(struct nand_chip *chip,
> +                                         const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +
> +       ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +       cond_delay(nfc_op.rdy_delay_ns);
> +
> +       return ret;
> +}
> +
> +static int marvell_nfc_read_id_type_exec(struct nand_chip *chip,
> +                                        const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +       nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
> +       nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ_ID);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
> +                                 "RDDREQ while reading ID");
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.cle_ale_delay_ns);
> +
> +       if (nfc_op.rdy_timeout_ms) {
> +               ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       cond_delay(nfc_op.rdy_delay_ns);
> +
> +       marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.data_delay_ns);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_read_status_exec(struct nand_chip *chip,
> +                                       const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +       nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
> +       nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_STATUS);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
> +                                 "RDDREQ while reading status");
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.cle_ale_delay_ns);
> +
> +       if (nfc_op.rdy_timeout_ms) {
> +               ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       cond_delay(nfc_op.rdy_delay_ns);
> +
> +       marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.data_delay_ns);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_reset_cmd_type_exec(struct nand_chip *chip,
> +                                          const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +       nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_RESET);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.cle_ale_delay_ns);
> +
> +       ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.rdy_delay_ns);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_erase_cmd_type_exec(struct nand_chip *chip,
> +                                          const struct nand_subop *subop)
> +{
> +       struct marvell_nfc_op nfc_op;
> +       int ret;
> +
> +       marvell_nfc_parse_instructions(chip, subop, &nfc_op);
> +       nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_ERASE);
> +
> +       ret = marvell_nfc_prepare_cmd(chip);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_send_cmd(chip, &nfc_op);
> +       ret = marvell_nfc_wait_cmdd(chip);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.cle_ale_delay_ns);
> +
> +       ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
> +       if (ret)
> +               return ret;
> +
> +       cond_delay(nfc_op.rdy_delay_ns);
> +
> +       return 0;
> +}
> +
> +static const struct nand_op_parser marvell_nfcv2_op_parser = NAND_OP_PARSER(
> +       /* Monolithic reads/writes */
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_monolithic_access_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC_NFCV2),
> +               NAND_OP_PARSER_PAT_CMD_ELEM(true),
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
> +               NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_monolithic_access_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2),
> +               NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE),
> +               NAND_OP_PARSER_PAT_CMD_ELEM(true),
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
> +       /* Naked commands */
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_access_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_access_exec,
> +               NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_access_exec,
> +               NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_access_exec,
> +               NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_waitrdy_exec,
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> +       );
> +
> +static const struct nand_op_parser marvell_nfcv1_op_parser = NAND_OP_PARSER(
> +       /* Naked commands not supported, use a function for each pattern */
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_read_id_type_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
> +               NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_erase_cmd_type_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_read_status_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_reset_cmd_type_exec,
> +               NAND_OP_PARSER_PAT_CMD_ELEM(false),
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> +       NAND_OP_PARSER_PATTERN(
> +               marvell_nfc_naked_waitrdy_exec,
> +               NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> +       );
> +
> +static int marvell_nfc_exec_op(struct nand_chip *chip,
> +                              const struct nand_operation *op,
> +                              bool check_only)
> +{
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +
> +       if (nfc->caps->is_nfcv2)
> +               return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser,
> +                                             op, check_only);
> +       else
> +               return nand_op_parser_exec_op(chip, &marvell_nfcv1_op_parser,
> +                                             op, check_only);
> +}
> +
> +/*
> + * HW ECC layouts, identical to old pxa3xx_nand driver,
> + * to be fully backward compatible.
> + */
> +static int marvell_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
> +                                     struct mtd_oob_region *oobregion)
> +{
> +       struct nand_chip *chip = mtd_to_nand(mtd);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt;
> +
> +       if (section >= nchunks)
> +               return -ERANGE;
> +
> +       oobregion->offset = ((lt->spare_bytes + lt->ecc_bytes) * section) +
> +               lt->spare_bytes;
> +       oobregion->length = lt->ecc_bytes;
> +
> +       return 0;
> +}
> +
> +static int marvell_nand_ooblayout_free(struct mtd_info *mtd, int section,
> +                                      struct mtd_oob_region *oobregion)
> +{
> +       struct nand_chip *chip = mtd_to_nand(mtd);
> +       const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
> +       int nchunks = lt->full_chunk_cnt;
> +
> +       if (section >= nchunks)
> +               return -ERANGE;
> +
> +       if (!lt->spare_bytes)
> +               return 0;
> +
> +       oobregion->offset = section * (lt->spare_bytes + lt->ecc_bytes);
> +       oobregion->length = lt->spare_bytes;
> +       if (!section) {
> +               /*
> +                * Bootrom looks in bytes 0 & 5 for bad blocks for the
> +                * 4KB page / 4bit BCH combination.
> +                */
> +               if (mtd->writesize == 4096 && lt->data_bytes == 2048) {
> +                       oobregion->offset += 6;
> +                       oobregion->length -= 6;
> +               } else {
> +                       oobregion->offset += 2;
> +                       oobregion->length -= 2;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops marvell_nand_ooblayout_ops = {
> +       .ecc = marvell_nand_ooblayout_ecc,
> +       .free = marvell_nand_ooblayout_free,
> +};
> +
> +static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
> +                                        struct nand_ecc_ctrl *ecc)
> +{
> +       struct nand_chip *chip = mtd_to_nand(mtd);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       const struct marvell_hw_ecc_layout *l;
> +       int i;
> +
> +       if (!nfc->caps->is_nfcv2 &&
> +           (mtd->writesize + mtd->oobsize > MAX_CHUNK_SIZE)) {
> +               dev_err(nfc->dev,
> +                       "NFCv1: writesize (%d) cannot be bigger than a chunk (%d)\n",
> +                       mtd->writesize, MAX_CHUNK_SIZE - mtd->oobsize);
> +               return -ENOTSUPP;
> +       }
> +
> +       to_marvell_nand(chip)->layout = NULL;
> +       for (i = 0; i < ARRAY_SIZE(marvell_nfc_layouts); i++) {
> +               l = &marvell_nfc_layouts[i];
> +               if (mtd->writesize == l->writesize &&
> +                   ecc->size == l->chunk && ecc->strength == l->strength) {
> +                       to_marvell_nand(chip)->layout = l;
> +                       break;
> +               }
> +       }
> +
> +       if (!to_marvell_nand(chip)->layout ||
> +           (!nfc->caps->is_nfcv2 && ecc->strength > 1)) {
> +               dev_err(nfc->dev,
> +                       "ECC strength %d at page size %d is not supported\n",
> +                       ecc->strength, mtd->writesize);
> +               return -ENOTSUPP;
> +       }
> +
> +       mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
> +       ecc->steps = l->full_chunk_cnt + l->last_chunk_cnt;
> +       ecc->size = l->data_bytes;
> +
> +       if (ecc->strength == 1) {
> +               chip->ecc.algo = NAND_ECC_HAMMING;
> +               ecc->read_page_raw = marvell_nfc_hw_ecc_hmg_read_page_raw;
> +               ecc->read_page = marvell_nfc_hw_ecc_hmg_read_page;
> +               ecc->read_oob_raw = marvell_nfc_hw_ecc_hmg_read_oob_raw;
> +               ecc->read_oob = ecc->read_oob_raw;
> +               ecc->write_page_raw = marvell_nfc_hw_ecc_hmg_write_page_raw;
> +               ecc->write_page = marvell_nfc_hw_ecc_hmg_write_page;
> +               ecc->write_oob_raw = marvell_nfc_hw_ecc_hmg_write_oob_raw;
> +               ecc->write_oob = ecc->write_oob_raw;
> +       } else {
> +               chip->ecc.algo = NAND_ECC_BCH;
> +               ecc->strength = 16;
> +               ecc->read_page_raw = marvell_nfc_hw_ecc_bch_read_page_raw;
> +               ecc->read_page = marvell_nfc_hw_ecc_bch_read_page;
> +               ecc->read_oob_raw = marvell_nfc_hw_ecc_bch_read_oob_raw;
> +               ecc->read_oob = marvell_nfc_hw_ecc_bch_read_oob;
> +               ecc->write_page_raw = marvell_nfc_hw_ecc_bch_write_page_raw;
> +               ecc->write_page = marvell_nfc_hw_ecc_bch_write_page;
> +               ecc->write_oob_raw = marvell_nfc_hw_ecc_bch_write_oob_raw;
> +               ecc->write_oob = marvell_nfc_hw_ecc_bch_write_oob;
> +       }
> +
> +       return 0;
> +}
> +
> +static int marvell_nand_ecc_init(struct mtd_info *mtd,
> +                                struct nand_ecc_ctrl *ecc)
> +{
> +       struct nand_chip *chip = mtd_to_nand(mtd);
> +       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
> +       int ret;
> +
> +       if ((ecc->mode != NAND_ECC_NONE) && (!ecc->size || !ecc->strength)) {
> +               if (chip->ecc_step_ds && chip->ecc_strength_ds) {
> +                       ecc->size = chip->ecc_step_ds;
> +                       ecc->strength = chip->ecc_strength_ds;
> +               } else {
> +                       dev_info(nfc->dev,
> +                                "No minimum ECC strength, using 1b/512B\n");
> +                       ecc->size = 512;
> +                       ecc->strength = 1;
> +               }
> +       }
> +
> +       switch (ecc->mode) {
> +       case NAND_ECC_HW:
> +               ret = marvell_nand_hw_ecc_ctrl_init(mtd, ecc);
> +               if (ret)
> +                       return ret;
> +               break;
> +       case NAND_ECC_NONE:
> +               chip->ecc.algo = 0;
> +       case NAND_ECC_SOFT:
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
> +static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
> +
> +static struct nand_bbt_descr bbt_main_descr = {
> +       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
> +                  NAND_BBT_2BIT | NAND_BBT_VERSION,
> +       .offs = 8,
> +       .len = 6,
> +       .veroffs = 14,
> +       .maxblocks = 8, /* Last 8 blocks in each chip */
> +       .pattern = bbt_pattern
> +};
> +
> +static struct nand_bbt_descr bbt_mirror_descr = {
> +       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
> +                  NAND_BBT_2BIT | NAND_BBT_VERSION,
> +       .offs = 8,
> +       .len = 6,
> +       .veroffs = 14,
> +       .maxblocks = 8, /* Last 8 blocks in each chip */
> +       .pattern = bbt_mirror_pattern
> +};
> +
> +static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, 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->ecc_clk) * 2;
> +       const struct nand_sdr_timings *sdr;
> +       struct marvell_nfc_timings nfc_tmg;
> +       int read_delay;
> +
> +       sdr = nand_get_sdr_timings(conf);
> +       if (IS_ERR(sdr))
> +               return PTR_ERR(sdr);
> +
> +       /*
> +        * SDR timings are given in pico-seconds while NFC timings must be
> +        * expressed in NAND controller clock cycles, which is half of the
> +        * frequency of the accessible ECC clock retrieved by clk_get_rate().
> +        * This is not written anywhere in the datasheet but was observed
> +        * with an oscilloscope.
> +        *
> +        * NFC datasheet gives equations from which thoses calculations
> +        * are derived, they tend to be slightly more restrictives than the
> +        * given core timings and may improve the overall speed.
> +        */
> +       nfc_tmg.tRP = TO_CYCLES(DIV_ROUND_UP(sdr->tRC_min, 2), period_ns) - 1;
> +       nfc_tmg.tRH = nfc_tmg.tRP;
> +       nfc_tmg.tWP = TO_CYCLES(DIV_ROUND_UP(sdr->tWC_min, 2), period_ns) - 1;
> +       nfc_tmg.tWH = nfc_tmg.tWP;
> +       nfc_tmg.tCS = TO_CYCLES(sdr->tCS_min, period_ns);
> +       nfc_tmg.tCH = TO_CYCLES(sdr->tCH_min, period_ns) - 1;
> +       nfc_tmg.tADL = TO_CYCLES(sdr->tADL_min, period_ns);
> +       /*
> +        * Read delay is the time of propagation from SoC pins to NFC internal
> +        * logic. With non-EDO timings, this is MIN_RD_DEL_CNT clock cycles. In
> +        * EDO mode, an additional delay of tRH must be taken into account so
> +        * the data is sampled on the falling edge instead of the rising edge.
> +        */
> +       read_delay = sdr->tRC_min >= 30000 ?
> +               MIN_RD_DEL_CNT : MIN_RD_DEL_CNT + nfc_tmg.tRH;
> +
> +       nfc_tmg.tAR = TO_CYCLES(sdr->tAR_min, period_ns);
> +       /*
> +        * tWHR and tRHW are supposed to be read to write delays (and vice
> +        * versa) but in some cases, ie. when doing a change column, they must
> +        * be greater than that to be sure tCCS delay is respected.
> +        */
> +       nfc_tmg.tWHR = TO_CYCLES(max_t(int, sdr->tWHR_min, sdr->tCCS_min),
> +                                period_ns) - 2,
> +       nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min),
> +                                period_ns);
> +
> +       /* Use WAIT_MODE (wait for RB line) instead of only relying on delays */
> +       nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
> +
> +       if (chipnr < 0)
> +               return 0;
> +
> +       marvell_nand->ndtr0 =
> +               NDTR0_TRP(nfc_tmg.tRP) |
> +               NDTR0_TRH(nfc_tmg.tRH) |
> +               NDTR0_ETRP(nfc_tmg.tRP) |
> +               NDTR0_TWP(nfc_tmg.tWP) |
> +               NDTR0_TWH(nfc_tmg.tWH) |
> +               NDTR0_TCS(nfc_tmg.tCS) |
> +               NDTR0_TCH(nfc_tmg.tCH) |
> +               NDTR0_RD_CNT_DEL(read_delay) |
> +               NDTR0_SELCNTR |
> +               NDTR0_TADL(nfc_tmg.tADL);
> +
> +       marvell_nand->ndtr1 =
> +               NDTR1_TAR(nfc_tmg.tAR) |
> +               NDTR1_TWHR(nfc_tmg.tWHR) |
> +               NDTR1_TRHW(nfc_tmg.tRHW) |
> +               NDTR1_WAIT_MODE |
> +               NDTR1_TR(nfc_tmg.tR);
> +
> +       writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
> +       writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
> +
> +       return 0;
> +}
> +
> +static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
> +                                 struct device_node *np)
> +{
> +       struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(dev);
> +       struct marvell_nand_chip *marvell_nand;
> +       struct mtd_info *mtd;
> +       struct nand_chip *chip;
> +       int nsels, ret, i;
> +       u32 cs, rb;
> +
> +       /*
> +        * The legacy "num-cs" property indicates the number of CS on the only
> +        * chip connected to the controller (legacy bindings does not support
> +        * more than one chip). CS are only incremented one by one while the RB
> +        * pin is always the #0.
> +        *
> +        * When not using legacy bindings, a couple of "reg" and "marvell,rb"
> +        * properties must be filled. For each chip, expressed as a subnode,
> +        * "reg" points to the CS lines and "marvell,rb" to the RB line.
> +        */
> +       if (pdata) {
> +               nsels = 1;
> +       } else if (nfc->caps->legacy_of_bindings) {
> +               if (!of_get_property(np, "num-cs", &nsels)) {
> +                       dev_err(dev, "missing num-cs property\n");
> +                       return -EINVAL;
> +               }
> +       } else {
> +               if (!of_get_property(np, "reg", &nsels)) {
> +                       dev_err(dev, "missing reg property\n");
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       if (!pdata)
> +               nsels /= sizeof(u32);
> +       if (!nsels) {
> +               dev_err(dev, "invalid reg property size\n");
> +               return -EINVAL;
> +       }
> +
> +       /* Alloc the nand chip structure */
> +       marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) +
> +                                   (nsels *
> +                                    sizeof(struct marvell_nand_chip_sel)),
> +                                   GFP_KERNEL);
> +       if (!marvell_nand) {
> +               dev_err(dev, "could not allocate chip structure\n");
> +               return -ENOMEM;
> +       }
> +
> +       marvell_nand->nsels = nsels;
> +       marvell_nand->selected_die = -1;
> +
> +       for (i = 0; i < nsels; i++) {
> +               if (pdata || nfc->caps->legacy_of_bindings) {
> +                       /*
> +                        * Legacy bindings use the CS lines in natural
> +                        * order (0, 1, ...)
> +                        */
> +                       cs = i;
> +               } else {
> +                       /* Retrieve CS id */
> +                       ret = of_property_read_u32_index(np, "reg", i, &cs);
> +                       if (ret) {
> +                               dev_err(dev, "could not retrieve reg property: %d\n",
> +                                       ret);
> +                               return ret;
> +                       }
> +               }
> +
> +               if (cs >= nfc->caps->max_cs_nb) {
> +                       dev_err(dev, "invalid reg value: %u (max CS = %d)\n",
> +                               cs, nfc->caps->max_cs_nb);
> +                       return -EINVAL;
> +               }
> +
> +               if (test_and_set_bit(cs, &nfc->assigned_cs)) {
> +                       dev_err(dev, "CS %d already assigned\n", cs);
> +                       return -EINVAL;
> +               }
> +
> +               /*
> +                * The cs variable represents the chip select id, which must be
> +                * converted in bit fields for NDCB0 and NDCB2 to select the
> +                * right chip. Unfortunately, due to a lack of information on
> +                * the subject and incoherent documentation, the user should not
> +                * use CS1 and CS3 at all as asserting them is not supported in
> +                * a reliable way (due to multiplexing inside ADDR5 field).
> +                */
> +               marvell_nand->sels[i].cs = cs;
> +               switch (cs) {
> +               case 0:
> +               case 2:
> +                       marvell_nand->sels[i].ndcb0_csel = 0;
> +                       break;
> +               case 1:
> +               case 3:
> +                       marvell_nand->sels[i].ndcb0_csel = NDCB0_CSEL;
> +                       break;
> +               default:
> +                       return -EINVAL;
> +               }
> +
> +               /* Retrieve RB id */
> +               if (pdata || nfc->caps->legacy_of_bindings) {
> +                       /* Legacy bindings always use RB #0 */
> +                       rb = 0;
> +               } else {
> +                       ret = of_property_read_u32_index(np, "marvell,rb", i,
> +                                                        &rb);
> +                       if (ret) {
> +                               dev_err(dev,
> +                                       "could not retrieve RB property: %d\n",
> +                                       ret);
> +                               return ret;
> +                       }
> +               }
> +
> +               if (rb >= nfc->caps->max_rb_nb) {
> +                       dev_err(dev, "invalid reg value: %u (max RB = %d)\n",
> +                               rb, nfc->caps->max_rb_nb);
> +                       return -EINVAL;
> +               }
> +
> +               marvell_nand->sels[i].rb = rb;
> +       }
> +
> +       chip = &marvell_nand->chip;
> +       chip->controller = &nfc->controller;
> +       nand_set_flash_node(chip, np);
> +
> +       chip->exec_op = marvell_nfc_exec_op;
> +       chip->select_chip = marvell_nfc_select_chip;
> +       if (nfc->caps->is_nfcv2 &&
> +           !of_property_read_bool(np, "marvell,nand-keep-config"))
> +               chip->setup_data_interface = marvell_nfc_setup_data_interface;
> +
> +       mtd = nand_to_mtd(chip);
> +       mtd->dev.parent = dev;
> +
> +       /*
> +        * Default to HW ECC engine mode. If the nand-ecc-mode property is given
> +        * in the DT node, this entry will be overwritten in nand_scan_ident().
> +        */
> +       chip->ecc.mode = NAND_ECC_HW;
> +
> +       ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
> +       if (ret) {
> +               dev_err(dev, "could not identify the nand chip\n");
> +               return ret;
> +       }
> +
> +       if (pdata && pdata->flash_bbt)
> +               chip->bbt_options |= NAND_BBT_USE_FLASH;
> +
> +       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_NO_OOB_BBM;
> +               chip->bbt_td = &bbt_main_descr;
> +               chip->bbt_md = &bbt_mirror_descr;
> +       }
> +
> +       /*
> +        * With RA_START bit set in NDCR, columns takes two address cycles. This
> +        * means addressing a chip with more than 256 pages needs a fifth
> +        * address cycle. Addressing a chip using CS 2 or 3 should also needs
> +        * this additional cycle but due to insistance in the documentation and
> +        * lack of hardware to test this situation, this case has been dropped
> +        * and is not supported by this driver.
> +        */
> +       marvell_nand->addr_cyc = 4;
> +       if (chip->options & NAND_ROW_ADDR_3)
> +               marvell_nand->addr_cyc = 5;
> +
> +       if (pdata) {
> +               chip->ecc.size = pdata->ecc_step_size;
> +               chip->ecc.strength = pdata->ecc_strength;
> +       }
> +
> +       ret = marvell_nand_ecc_init(mtd, &chip->ecc);
> +       if (ret) {
> +               dev_err(dev, "ECC init failed: %d\n", ret);
> +               return ret;
> +       }
> +
> +       if (chip->ecc.mode == NAND_ECC_HW) {
> +               /*
> +                * Subpage write not available with hardware ECC, prohibit also
> +                * subpage read as in userspace subpage acces would still be
> +                * allowed and subpage write, if used, would lead to numerous
> +                * uncorrectable ECC errors.
> +                */
> +               chip->options |= NAND_NO_SUBPAGE_WRITE;
> +       }
> +
> +       if (pdata || nfc->caps->legacy_of_bindings) {
> +               /*
> +                * We keep the MTD name unchanged to avoid breaking platforms
> +                * where the MTD cmdline parser is used and the bootloader
> +                * has not been updated to use the new naming scheme.
> +                */
> +               mtd->name = "pxa3xx_nand-0";
> +       } else if (!mtd->name) {
> +               /*
> +                * If the new bindings are used and the bootloader has not been
> +                * updated to pass a new mtdparts parameter on the cmdline, you
> +                * should define the following property in your NAND node, ie:
> +                *
> +                *      label = "main-storage";
> +                *
> +                * This way, mtd->name will be set by the core when
> +                * nand_set_flash_node() is called.
> +                */
> +               mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
> +                                          "%s:nand.%d", dev_name(nfc->dev),
> +                                          marvell_nand->sels[0].cs);
> +               if (!mtd->name) {
> +                       dev_err(nfc->dev, "Failed to allocate mtd->name\n");
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       ret = nand_scan_tail(mtd);
> +       if (ret) {
> +               dev_err(dev, "nand_scan_tail failed: %d\n", ret);
> +               return ret;
> +       }
> +
> +       if (pdata)
> +               /* Legacy bindings support only one chip */
> +               ret = mtd_device_register(mtd, pdata->parts[0],
> +                                         pdata->nr_parts[0]);
> +       else
> +               ret = mtd_device_register(mtd, NULL, 0);
> +       if (ret) {
> +               dev_err(dev, "failed to register mtd device: %d\n", ret);
> +               nand_release(mtd);
> +               return ret;
> +       }
> +
> +       list_add_tail(&marvell_nand->node, &nfc->chips);
> +
> +       return 0;
> +}
> +
> +static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
> +{
> +       struct device_node *np = dev->of_node;
> +       struct device_node *nand_np;
> +       int max_cs = nfc->caps->max_cs_nb;
> +       int nchips;
> +       int ret;
> +
> +       if (!np)
> +               nchips = 1;
> +       else
> +               nchips = of_get_child_count(np);
> +
> +       if (nchips > max_cs) {
> +               dev_err(dev, "too many NAND chips: %d (max = %d CS)\n", nchips,
> +                       max_cs);
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * Legacy bindings do not use child nodes to exhibit NAND chip
> +        * properties and layout. Instead, NAND properties are mixed with the
> +        * controller's and a single subnode presents the memory layout.
> +        */
> +       if (nfc->caps->legacy_of_bindings) {
> +               ret = marvell_nand_chip_init(dev, nfc, np);
> +               return ret;
> +       }
> +
> +       for_each_child_of_node(np, nand_np) {
> +               ret = marvell_nand_chip_init(dev, nfc, nand_np);
> +               if (ret) {
> +                       of_node_put(nand_np);
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
> +{
> +       struct marvell_nand_chip *entry, *temp;
> +
> +       list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
> +               nand_release(nand_to_mtd(&entry->chip));
> +               list_del(&entry->node);
> +       }
> +}
> +
> +static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
> +{
> +       struct platform_device *pdev = container_of(nfc->dev,
> +                                                   struct platform_device,
> +                                                   dev);
> +       struct dma_slave_config config = {};
> +       struct resource *r;
> +       dma_cap_mask_t mask;
> +       struct pxad_param param;
> +       int ret;
> +
> +       if (!IS_ENABLED(CONFIG_PXA_DMA)) {
> +               dev_warn(nfc->dev,
> +                        "DMA not enabled in configuration\n");
> +               return -ENOTSUPP;
> +       }
> +
> +       ret = dma_set_mask_and_coherent(nfc->dev, DMA_BIT_MASK(32));
> +       if (ret)
> +               return ret;
> +
> +       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +       if (!r) {
> +               dev_err(nfc->dev, "No resource defined for data DMA\n");
> +               return -ENXIO;
> +       }
> +
> +       param.drcmr = r->start;
> +       param.prio = PXAD_PRIO_LOWEST;
> +       dma_cap_zero(mask);
> +       dma_cap_set(DMA_SLAVE, mask);
> +       nfc->dma_chan =
> +               dma_request_slave_channel_compat(mask, pxad_filter_fn,
> +                                                &param, nfc->dev,
> +                                                "data");
> +       if (!nfc->dma_chan) {
> +               dev_err(nfc->dev,
> +                       "Unable to request data DMA channel\n");
> +               return -ENODEV;
> +       }
> +
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!r)
> +               return -ENXIO;
> +
> +       config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> +       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> +       config.src_addr = r->start + NDDB;
> +       config.dst_addr = r->start + NDDB;
> +       config.src_maxburst = 32;
> +       config.dst_maxburst = 32;
> +       ret = dmaengine_slave_config(nfc->dma_chan, &config);
> +       if (ret < 0) {
> +               dev_err(nfc->dev, "Failed to configure DMA channel\n");
> +               return ret;
> +       }
> +
> +       /*
> +        * DMA must act on length multiple of 32 and this length may be
> +        * bigger than the destination buffer. Use this buffer instead
> +        * for DMA transfers and then copy the desired amount of data to
> +        * the provided buffer.
> +        */
> +       nfc->dma_buf = kmalloc(MAX_CHUNK_SIZE, GFP_DMA);
> +       if (!nfc->dma_buf)
> +               return -ENOMEM;
> +
> +       nfc->use_dma = true;
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_init(struct marvell_nfc *nfc)
> +{
> +       struct device_node *np = nfc->dev->of_node;
> +
> +       /*
> +        * Some SoCs like A7k/A8k need to enable manually the NAND
> +        * controller, gated clocks and reset bits to avoid being bootloader
> +        * dependent. This is done through the use of the System Functions
> +        * registers.
> +        */
> +       if (nfc->caps->need_system_controller) {
> +               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_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_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
> +               reg |= GENCONF_ND_CLK_CTRL_EN;
> +               regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
> +       }
> +
> +       /* Configure the DMA if appropriate */
> +       if (!nfc->caps->is_nfcv2)
> +               marvell_nfc_init_dma(nfc);
> +
> +       /*
> +        * ECC operations and interruptions are only enabled when specifically
> +        * needed. ECC shall not be activated in the early stages (fails probe).
> +        * Arbiter flag, even if marked as "reserved", must be set (empirical).
> +        */
> +       writel_relaxed(NDCR_RA_START | NDCR_ALL_INT | NDCR_ND_ARB_EN |
> +                      (nfc->caps->is_nfcv2 ?
> +                       0 : NDCR_RD_ID_CNT(NFCV1_READID_LEN)),
> +                      nfc->regs + NDCR);
> +       writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
> +       writel_relaxed(0, nfc->regs + NDECCCTRL);
> +
> +       return 0;
> +}
> +
> +static int marvell_nfc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *r;
> +       struct marvell_nfc *nfc;
> +       int ret;
> +       int irq;
> +
> +       nfc = devm_kzalloc(&pdev->dev, sizeof(struct marvell_nfc),
> +                          GFP_KERNEL);
> +       if (!nfc)
> +               return -ENOMEM;
> +
> +       nfc->dev = dev;
> +       nand_hw_control_init(&nfc->controller);
> +       INIT_LIST_HEAD(&nfc->chips);
> +
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       nfc->regs = devm_ioremap_resource(dev, r);
> +       if (IS_ERR(nfc->regs))
> +               return PTR_ERR(nfc->regs);
> +
> +       irq = platform_get_irq(pdev, 0);
> +       if (irq < 0) {
> +               dev_err(dev, "failed to retrieve irq\n");
> +               return irq;
> +       }
> +
> +       nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL);
> +       if (IS_ERR(nfc->ecc_clk))
> +               return PTR_ERR(nfc->ecc_clk);
> +
> +       ret = clk_prepare_enable(nfc->ecc_clk);
> +       if (ret)
> +               return ret;
> +
> +       marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
> +       marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
> +       ret = devm_request_irq(dev, irq, marvell_nfc_isr,
> +                              0, "marvell-nfc", nfc);
> +       if (ret)
> +               goto unprepare_clk;
> +
> +       /* Get NAND controller capabilities */
> +       if (pdev->id_entry)
> +               nfc->caps = (void *)pdev->id_entry->driver_data;
> +       else
> +               nfc->caps = of_device_get_match_data(&pdev->dev);
> +
> +       if (!nfc->caps) {
> +               dev_err(dev, "Could not retrieve NFC caps\n");
> +               ret = -EINVAL;
> +               goto unprepare_clk;
> +       }
> +
> +       /* Init the controller and then probe the chips */
> +       ret = marvell_nfc_init(nfc);
> +       if (ret)
> +               goto unprepare_clk;
> +
> +       platform_set_drvdata(pdev, nfc);
> +
> +       ret = marvell_nand_chips_init(dev, nfc);
> +       if (ret)
> +               goto unprepare_clk;
> +
> +       return 0;
> +
> +unprepare_clk:
> +       clk_disable_unprepare(nfc->ecc_clk);
> +
> +       return ret;
> +}
> +
> +static int marvell_nfc_remove(struct platform_device *pdev)
> +{
> +       struct marvell_nfc *nfc = platform_get_drvdata(pdev);
> +
> +       marvell_nand_chips_cleanup(nfc);
> +
> +       if (nfc->use_dma) {
> +               dmaengine_terminate_all(nfc->dma_chan);
> +               dma_release_channel(nfc->dma_chan);
> +       }
> +
> +       clk_disable_unprepare(nfc->ecc_clk);
> +
> +       return 0;
> +}
> +
> +static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
> +       .max_cs_nb = 4,
> +       .max_rb_nb = 2,
> +       .need_system_controller = true,
> +       .is_nfcv2 = true,
> +};
> +
> +static const struct marvell_nfc_caps marvell_armada370_nfc_caps = {
> +       .max_cs_nb = 4,
> +       .max_rb_nb = 2,
> +       .is_nfcv2 = true,
> +};
> +
> +static const struct marvell_nfc_caps marvell_pxa3xx_nfc_caps = {
> +       .max_cs_nb = 2,
> +       .max_rb_nb = 1,
> +       .use_dma = true,
> +};
> +
> +static const struct marvell_nfc_caps marvell_armada_8k_nfc_legacy_caps = {
> +       .max_cs_nb = 4,
> +       .max_rb_nb = 2,
> +       .need_system_controller = true,
> +       .legacy_of_bindings = true,
> +       .is_nfcv2 = true,
> +};
> +
> +static const struct marvell_nfc_caps marvell_armada370_nfc_legacy_caps = {
> +       .max_cs_nb = 4,
> +       .max_rb_nb = 2,
> +       .legacy_of_bindings = true,
> +};
> +
> +static const struct marvell_nfc_caps marvell_pxa3xx_nfc_legacy_caps = {
> +       .max_cs_nb = 2,
> +       .max_rb_nb = 1,
> +       .legacy_of_bindings = true,
> +};
> +
> +static const struct platform_device_id marvell_nfc_platform_ids[] = {
> +       {
> +               .name = "pxa3xx-nand",
> +               .driver_data = (kernel_ulong_t)&marvell_pxa3xx_nfc_legacy_caps,
> +       },
> +       { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(platform, marvell_nfc_platform_ids);
> +
> +static const struct of_device_id marvell_nfc_of_ids[] = {
> +       {
> +               .compatible = "marvell,armada-8k-nand-controller",
> +               .data = &marvell_armada_8k_nfc_caps,
> +       },
> +       {
> +               .compatible = "marvell,armada370-nand-controller",
> +               .data = &marvell_armada370_nfc_caps,
> +       },
> +       {
> +               .compatible = "marvell,pxa3xx-nand-controller",
> +               .data = &marvell_pxa3xx_nfc_caps,
> +       },
> +       /* Support for old/deprecated bindings: */
> +       {
> +               .compatible = "marvell,armada-8k-nand",
> +               .data = &marvell_armada_8k_nfc_legacy_caps,
> +       },
> +       {
> +               .compatible = "marvell,armada370-nand",
> +               .data = &marvell_armada370_nfc_legacy_caps,
> +       },
> +       {
> +               .compatible = "marvell,pxa3xx-nand",
> +               .data = &marvell_pxa3xx_nfc_legacy_caps,
> +       },
> +       { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, marvell_nfc_of_ids);
> +
> +static struct platform_driver marvell_nfc_driver = {
> +       .driver = {
> +               .name           = "marvell-nfc",
> +               .of_match_table = marvell_nfc_of_ids,
> +       },
> +       .id_table = marvell_nfc_platform_ids,
> +       .probe = marvell_nfc_probe,
> +       .remove = marvell_nfc_remove,
> +};
> +module_platform_driver(marvell_nfc_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Marvell NAND controller driver");
> --
> 2.11.0
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver
       [not found]         ` <CAAEAJfC89bRugBsK8jrK=6fdq76yzjThA74UCAhAaVuonLLNvg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-12-11 16:55           ` Miquel RAYNAL
  2017-12-11 17:05             ` Boris Brezillon
  0 siblings, 1 reply; 32+ messages in thread
From: Miquel RAYNAL @ 2017-12-11 16:55 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas

On Mon, 11 Dec 2017 13:27:30 -0300
Ezequiel Garcia <ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote:

> On 7 December 2017 at 17:18, Miquel Raynal
> <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> > Add marvell_nand driver which aims at replacing the existing
> > pxa3xx_nand driver.
> >
> > The new driver intends to be easier to understand and follows the
> > brand new NAND framework rules by implementing hooks for every
> > pattern the controller might support and referencing them inside a
> > parser object that will be given to the core at each ->exec_op()
> > call.
> >
> > Raw accessors are implemented, useful to test/debug
> > memory/filesystem corruptions. Userspace binaries contained in the
> > mtd-utils package may now be used and their output trusted.
> >
> > Timings may not be kept from the bootloader anymore, the timings
> > used for instance in U-Boot were not optimal and it supposed to
> > have NAND support (and initialized) in the bootloader.
> >
> > Thanks to the improved timings, implementation of ONFI mode 5
> > support (with EDO managed by adding a delay on data sampling),
> > merging the commands together and optimizing writes in the command
> > registers, the new driver may achieve faster throughputs in both
> > directions. Measurements show an improvement of about +23% read
> > throughput and +24% write throughput. These measurements have been
> > done with an Armada-385-DB-AP (4kiB NAND pages forced in 4-bit
> > strength BCH ECC correction) using the userspace tool 'flash_speed'
> > from the MTD test suite.
> >
> > Besides these important topics, the new driver addresses several
> > unsolved known issues in the old driver which:
> > - did not work with ECC soft neither with ECC none ;
> > - relied on naked read/write (which is unchanged) while the NFCv1
> >   embedded in the pxa3xx platforms do not implement it, so several
> >   NAND commands did not actually ever work without any notice (like
> >   reading the ONFI PARAM_PAGE or SET/GET_FEATURES) ;
> > - wrote the OOB data correctly, but was not able to read it
> > correctly past the first OOB data chunk ;
> > - did not displayed ECC bytes ;
> > - used device tree bindings that did not allow more than one NAND
> > chip, and did not allow to choose the correct chip select if not
> >   incrementing from 0. Plus, the Ready/Busy line used had to be 0.
> >
> > Old device tree bindings are still supported but deprecated. A more
> > hierarchical view has to be used to keep the controller and the NAND
> > chip structures clearly separated both inside the device tree and
> > also in the driver code.
> >  
> 
> So, is this driver fully compatible with the current pxa3xx-nand
> driver?

It should be!

> 
> Have you tested with U-Boot's driver (based on the pxa3xx-nand)?
> 
> I recally some subtle issues with the fact that U-Boot and Linux had
> to agree about the BBT format.

I kept the pxa3xx_nand driver BBT format.

This is something I mistakenly omitted from the commit message:

There are 5 supported layouts in the driver (the same as withing the
pxa3xx_nand driver):
    1/ Page: 512B, strength 1b/512B (hamming)
    2/ Page: 2kiB, strength 4b/2kiB (hamming)
    3/ page: 2kiB, strength 16b/2kiB (BCH)
    4/ page: 4kiB, strength 16b/2kiB (BCH)
    5/ page: 4kiB, strength 32b/2kiB (BCH)

Layout 2 has been tested with CM_X300 compulab module (PXA SoC) with
and without DMA.
Layout 4 has been tested with an Armada 385 db, an Armada 7040 DB and
an Armada 8040 DB.
Layout 5 has been tested with an Armada 398 db.

Layout 1 has been tested with the Armada 385 db with some hacks.
Layout 3 has been tested with the Armada 385 db with some other hacks,
that is why I am concerned about the other thread on the MTD mailing
list "wait timeout when scanning for BB" where a 2kiB page with
16b/2048B strength is in use.

Regards,
Miquèl
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver
  2017-12-11 16:55           ` Miquel RAYNAL
@ 2017-12-11 17:05             ` Boris Brezillon
  2017-12-11 21:02               ` Miquel RAYNAL
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2017-12-11 17:05 UTC (permalink / raw)
  To: Miquel RAYNAL
  Cc: Ezequiel Garcia, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas, Will Deacon

On Mon, 11 Dec 2017 17:55:06 +0100
Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> On Mon, 11 Dec 2017 13:27:30 -0300
> Ezequiel Garcia <ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote:
> 
> > On 7 December 2017 at 17:18, Miquel Raynal
> > <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:  
> > > Add marvell_nand driver which aims at replacing the existing
> > > pxa3xx_nand driver.
> > >
> > > The new driver intends to be easier to understand and follows the
> > > brand new NAND framework rules by implementing hooks for every
> > > pattern the controller might support and referencing them inside a
> > > parser object that will be given to the core at each ->exec_op()
> > > call.
> > >
> > > Raw accessors are implemented, useful to test/debug
> > > memory/filesystem corruptions. Userspace binaries contained in the
> > > mtd-utils package may now be used and their output trusted.
> > >
> > > Timings may not be kept from the bootloader anymore, the timings
> > > used for instance in U-Boot were not optimal and it supposed to
> > > have NAND support (and initialized) in the bootloader.
> > >
> > > Thanks to the improved timings, implementation of ONFI mode 5
> > > support (with EDO managed by adding a delay on data sampling),
> > > merging the commands together and optimizing writes in the command
> > > registers, the new driver may achieve faster throughputs in both
> > > directions. Measurements show an improvement of about +23% read
> > > throughput and +24% write throughput. These measurements have been
> > > done with an Armada-385-DB-AP (4kiB NAND pages forced in 4-bit
> > > strength BCH ECC correction) using the userspace tool 'flash_speed'
> > > from the MTD test suite.
> > >
> > > Besides these important topics, the new driver addresses several
> > > unsolved known issues in the old driver which:
> > > - did not work with ECC soft neither with ECC none ;
> > > - relied on naked read/write (which is unchanged) while the NFCv1
> > >   embedded in the pxa3xx platforms do not implement it, so several
> > >   NAND commands did not actually ever work without any notice (like
> > >   reading the ONFI PARAM_PAGE or SET/GET_FEATURES) ;
> > > - wrote the OOB data correctly, but was not able to read it
> > > correctly past the first OOB data chunk ;
> > > - did not displayed ECC bytes ;
> > > - used device tree bindings that did not allow more than one NAND
> > > chip, and did not allow to choose the correct chip select if not
> > >   incrementing from 0. Plus, the Ready/Busy line used had to be 0.
> > >
> > > Old device tree bindings are still supported but deprecated. A more
> > > hierarchical view has to be used to keep the controller and the NAND
> > > chip structures clearly separated both inside the device tree and
> > > also in the driver code.
> > >    
> > 
> > So, is this driver fully compatible with the current pxa3xx-nand
> > driver?  
> 
> It should be!
> 
> > 
> > Have you tested with U-Boot's driver (based on the pxa3xx-nand)?
> > 
> > I recally some subtle issues with the fact that U-Boot and Linux had
> > to agree about the BBT format.  
> 
> I kept the pxa3xx_nand driver BBT format.
> 
> This is something I mistakenly omitted from the commit message:
> 
> There are 5 supported layouts in the driver (the same as withing the
> pxa3xx_nand driver):
>     1/ Page: 512B, strength 1b/512B (hamming)
>     2/ Page: 2kiB, strength 4b/2kiB (hamming)
>     3/ page: 2kiB, strength 16b/2kiB (BCH)
>     4/ page: 4kiB, strength 16b/2kiB (BCH)
>     5/ page: 4kiB, strength 32b/2kiB (BCH)

Are you sure of #5? I thought the engine was only capable of modifying
the ECC block size, not the strength. If this is the case, then mode #5
is actually 16b/1024kiB.

> 
> Layout 2 has been tested with CM_X300 compulab module (PXA SoC) with
> and without DMA.
> Layout 4 has been tested with an Armada 385 db, an Armada 7040 DB and
> an Armada 8040 DB.
> Layout 5 has been tested with an Armada 398 db.
> 
> Layout 1 has been tested with the Armada 385 db with some hacks.
> Layout 3 has been tested with the Armada 385 db with some other hacks,
> that is why I am concerned about the other thread on the MTD mailing
> list "wait timeout when scanning for BB" where a 2kiB page with
> 16b/2048B strength is in use.
> 
> Regards,
> Miquèl

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver
  2017-12-11 17:05             ` Boris Brezillon
@ 2017-12-11 21:02               ` Miquel RAYNAL
  0 siblings, 0 replies; 32+ messages in thread
From: Miquel RAYNAL @ 2017-12-11 21:02 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Ezequiel Garcia, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Robert Jarzmik, Eric Miao, Catalin Marinas, Will Deacon

On Mon, 11 Dec 2017 18:05:11 +0100
Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> On Mon, 11 Dec 2017 17:55:06 +0100
> Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> 
> > On Mon, 11 Dec 2017 13:27:30 -0300
> > Ezequiel Garcia <ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote:
> >   
> > > On 7 December 2017 at 17:18, Miquel Raynal
> > > <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:    
> > > > Add marvell_nand driver which aims at replacing the existing
> > > > pxa3xx_nand driver.
> > > >
> > > > The new driver intends to be easier to understand and follows
> > > > the brand new NAND framework rules by implementing hooks for
> > > > every pattern the controller might support and referencing them
> > > > inside a parser object that will be given to the core at each
> > > > ->exec_op() call.
> > > >
> > > > Raw accessors are implemented, useful to test/debug
> > > > memory/filesystem corruptions. Userspace binaries contained in
> > > > the mtd-utils package may now be used and their output trusted.
> > > >
> > > > Timings may not be kept from the bootloader anymore, the timings
> > > > used for instance in U-Boot were not optimal and it supposed to
> > > > have NAND support (and initialized) in the bootloader.
> > > >
> > > > Thanks to the improved timings, implementation of ONFI mode 5
> > > > support (with EDO managed by adding a delay on data sampling),
> > > > merging the commands together and optimizing writes in the
> > > > command registers, the new driver may achieve faster
> > > > throughputs in both directions. Measurements show an
> > > > improvement of about +23% read throughput and +24% write
> > > > throughput. These measurements have been done with an
> > > > Armada-385-DB-AP (4kiB NAND pages forced in 4-bit strength BCH
> > > > ECC correction) using the userspace tool 'flash_speed' from the
> > > > MTD test suite.
> > > >
> > > > Besides these important topics, the new driver addresses several
> > > > unsolved known issues in the old driver which:
> > > > - did not work with ECC soft neither with ECC none ;
> > > > - relied on naked read/write (which is unchanged) while the
> > > > NFCv1 embedded in the pxa3xx platforms do not implement it, so
> > > > several NAND commands did not actually ever work without any
> > > > notice (like reading the ONFI PARAM_PAGE or SET/GET_FEATURES) ;
> > > > - wrote the OOB data correctly, but was not able to read it
> > > > correctly past the first OOB data chunk ;
> > > > - did not displayed ECC bytes ;
> > > > - used device tree bindings that did not allow more than one
> > > > NAND chip, and did not allow to choose the correct chip select
> > > > if not incrementing from 0. Plus, the Ready/Busy line used had
> > > > to be 0.
> > > >
> > > > Old device tree bindings are still supported but deprecated. A
> > > > more hierarchical view has to be used to keep the controller
> > > > and the NAND chip structures clearly separated both inside the
> > > > device tree and also in the driver code.
> > > >      
> > > 
> > > So, is this driver fully compatible with the current pxa3xx-nand
> > > driver?    
> > 
> > It should be!
> >   
> > > 
> > > Have you tested with U-Boot's driver (based on the pxa3xx-nand)?
> > > 
> > > I recally some subtle issues with the fact that U-Boot and Linux
> > > had to agree about the BBT format.    
> > 
> > I kept the pxa3xx_nand driver BBT format.
> > 
> > This is something I mistakenly omitted from the commit message:
> > 
> > There are 5 supported layouts in the driver (the same as withing the
> > pxa3xx_nand driver):
> >     1/ Page: 512B, strength 1b/512B (hamming)
> >     2/ Page: 2kiB, strength 4b/2kiB (hamming)
> >     3/ page: 2kiB, strength 16b/2kiB (BCH)
> >     4/ page: 4kiB, strength 16b/2kiB (BCH)
> >     5/ page: 4kiB, strength 32b/2kiB (BCH)  
> 
> Are you sure of #5? I thought the engine was only capable of modifying
> the ECC block size, not the strength. If this is the case, then mode
> #5 is actually 16b/1024kiB.

You are right, #5 you actually be:

    5/ page: 4kiB, strength 16b/1kiB (BCH)  

Thanks for pointing it,
Miquèl

> 
> > 
> > Layout 2 has been tested with CM_X300 compulab module (PXA SoC) with
> > and without DMA.
> > Layout 4 has been tested with an Armada 385 db, an Armada 7040 DB
> > and an Armada 8040 DB.
> > Layout 5 has been tested with an Armada 398 db.
> > 
> > Layout 1 has been tested with the Armada 385 db with some hacks.
> > Layout 3 has been tested with the Armada 385 db with some other
> > hacks, that is why I am concerned about the other thread on the MTD
> > mailing list "wait timeout when scanning for BB" where a 2kiB page
> > with 16b/2048B strength is in use.
> > 
> > Regards,
> > Miquèl  
> 



-- 
Miquel Raynal, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
       [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
                     ` (12 preceding siblings ...)
  2017-12-09 23:27   ` [PATCH 00/12] Marvell NAND controller rework with ->exec_op() Ezequiel Garcia
@ 2017-12-14  6:09   ` Boris Brezillon
  2017-12-18  7:11     ` Robert Jarzmik
  13 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2017-12-14  6:09 UTC (permalink / raw)
  To: Miquel Raynal, Robert Jarzmik
  Cc: David Woodhouse, Brian Norris, Marek Vasut, Richard Weinberger,
	Cyrille Pitchen, Rob Herring, Mark Rutland, Jason Cooper,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Russell King, Daniel Mack, Haojian Zhuang, Eric Miao,
	Catalin Marinas, Will Deacon, Ezequiel Garcia,
	linux-mtd-IAPFreCvJWMP3drIcvDWNA

Hi,

On Thu,  7 Dec 2017 21:18:02 +0100
Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hi,
> 
> After the addition of the NAND framework ->exec_op() interface (see [1]
> for the series preparing it and [2] for the last version of the
> core-side implementation of ->exec_op() itself), this series replaces
> the current Marvell NAND controller driver pxa3xx_nand.c with a rework
> called marvell_nand.c.
> 
> Aside the fact that it drops the big state machine, improves the overall
> speed and implements raw accesses, it is the first driver-side
> implementation of the ->exec_op() interface and may be used as reference
> for latter reworks of the same type.
> 
> One may find more detail about why a completely new driver is needed in
> the commit log of:
> 
>     "mtd: nand: add reworked Marvell NAND controller driver"
> 
> The series also changes the device tree NAND node definition for all
> platforms referring to the Marvell driver to use the new bindings. They
> are more hierarchical and fit the real organization of the hardware, by
> having NAND partitions that are part of NAND chip nodes, themselves part
> of the NAND controller node.
> 
> These changes have been tested on:
>    - PXA3xx platform with a CM-X300 board (2kiB page NAND, 1b/512B
>      strength, Hamming ECC engine) [32 bits]
>    - Armada 385 DB AP (4kiB page NAND, 4b/512B, BCH ECC engine) [32 bits]
>    - Armada 398 DB (4kiB page NAND, 8b/512B, BCH ECC engine using a layout
>      with a last chunk different than the others) [32 bits]
>    - Armada 7040 DB and Armada 8040 DB (4kiB page NAND, 4b/512B, BCH ECC
>      engine) [64 bits]
> 
> Robert, it would be great if you could also do more testing on PXA and
> validate this driver. If needed, a branch ready to be tested is
> available at [3]. It is based on nand/next and has all the changes
> brought by the previously mentionned series as well as this one.

Robert, do you think you'll have some time to test Miquel's branch on
your PXA boards? Miquel already tested on one of these boards (CM-X300),
but we'd like to have other testers. Also feel free to review the
driver if have the time.

Thanks,

Boris

> 
> Thank you,
> Miquèl
> 
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg619633.html
> [2] http://lists.infradead.org/pipermail/linux-mtd/2017-December/077965.html
> [3] https://github.com/miquelraynal/linux/tree/marvell/nand-next/nfc-rework
> 
> Miquel Raynal (12):
>   dt-bindings: mtd: add Marvell NAND controller documentation
>   mtd: nand: add reworked Marvell NAND controller driver
>   mtd: nand: replace pxa3xx_nand driver by its rework called
>     marvell_nand
>   dt-bindings: mtd: remove pxa3xx NAND controller documentation
>   mtd: nand: remove useless fields from pxa3xx NAND platform data
>   ARM: dts: armada-370-xp: use reworked NAND controller driver
>   ARM: dts: armada-375: use reworked NAND controller driver
>   ARM: dts: armada-38x: use reworked NAND controller driver
>   ARM: dts: armada-39x: use reworked NAND controller driver
>   ARM: dts: pxa: use reworked NAND controller driver
>   ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
>   ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K
> 
>  .../devicetree/bindings/mtd/marvell-nand.txt       |   84 +
>  .../devicetree/bindings/mtd/pxa3xx-nand.txt        |   50 -
>  arch/arm/boot/dts/armada-370-db.dts                |   57 +-
>  arch/arm/boot/dts/armada-370-dlink-dns327l.dts     |  120 +-
>  arch/arm/boot/dts/armada-370-mirabox.dts           |   51 +-
>  arch/arm/boot/dts/armada-370-netgear-rn102.dts     |   90 +-
>  arch/arm/boot/dts/armada-370-netgear-rn104.dts     |   90 +-
>  arch/arm/boot/dts/armada-370-rd.dts                |   52 +-
>  arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi |   64 +-
>  arch/arm/boot/dts/armada-370-xp.dtsi               |    6 +-
>  arch/arm/boot/dts/armada-375-db.dts                |   50 +-
>  arch/arm/boot/dts/armada-375.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-385-db-ap.dts             |   69 +-
>  arch/arm/boot/dts/armada-385-linksys-caiman.dts    |  129 +-
>  arch/arm/boot/dts/armada-385-linksys-cobra.dts     |  129 +-
>  arch/arm/boot/dts/armada-385-linksys-rango.dts     |  141 +-
>  arch/arm/boot/dts/armada-385-linksys-shelby.dts    |  129 +-
>  arch/arm/boot/dts/armada-385-linksys.dtsi          |   16 +-
>  arch/arm/boot/dts/armada-388-db.dts                |   55 +-
>  arch/arm/boot/dts/armada-38x.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-390-db.dts                |   66 +-
>  arch/arm/boot/dts/armada-395-gp.dts                |   74 +-
>  arch/arm/boot/dts/armada-398-db.dts                |   60 +-
>  arch/arm/boot/dts/armada-39x.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-xp-db-dxbc2.dts           |    2 +-
>  arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts      |    2 +-
>  arch/arm/boot/dts/armada-xp-db.dts                 |    2 +-
>  arch/arm/boot/dts/armada-xp-gp.dts                 |    2 +-
>  arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts    |    2 +-
>  arch/arm/boot/dts/armada-xp-linksys-mamba.dts      |  156 +-
>  arch/arm/boot/dts/armada-xp-netgear-rn2120.dts     |   90 +-
>  arch/arm/boot/dts/pxa3xx.dtsi                      |    6 +-
>  arch/arm/configs/cm_x300_defconfig                 |    2 +-
>  arch/arm/configs/mvebu_v7_defconfig                |    2 +-
>  arch/arm/configs/pxa3xx_defconfig                  |    3 +-
>  arch/arm/configs/pxa_defconfig                     |    2 +-
>  arch/arm/configs/raumfeld_defconfig                |    2 +-
>  arch/arm/mach-mmp/ttc_dkb.c                        |    4 +-
>  arch/arm/mach-pxa/cm-x300.c                        |    8 +-
>  arch/arm/mach-pxa/colibri-pxa3xx.c                 |    8 +-
>  arch/arm/mach-pxa/colibri.h                        |    2 +-
>  arch/arm/mach-pxa/littleton.c                      |   10 +-
>  arch/arm/mach-pxa/mxm8x10.c                        |   10 +-
>  arch/arm/mach-pxa/raumfeld.c                       |    6 +-
>  arch/arm/mach-pxa/zylonite.c                       |   10 +-
>  arch/arm64/boot/dts/marvell/armada-7040-db.dts     |   52 +-
>  arch/arm64/boot/dts/marvell/armada-8040-db.dts     |   46 +-
>  .../boot/dts/marvell/armada-cp110-master.dtsi      |    8 +-
>  .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi |   10 +-
>  drivers/mtd/nand/Kconfig                           |   12 +
>  drivers/mtd/nand/Makefile                          |    2 +-
>  drivers/mtd/nand/marvell_nand.c                    | 2950 ++++++++++++++++++++
>  drivers/mtd/nand/pxa3xx_nand.c                     | 2104 --------------
>  include/linux/platform_data/mtd-nand-pxa3xx.h      |   43 +-
>  54 files changed, 4093 insertions(+), 3065 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mtd/marvell-nand.txt
>  delete mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
>  create mode 100644 drivers/mtd/nand/marvell_nand.c
>  delete mode 100644 drivers/mtd/nand/pxa3xx_nand.c
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
       [not found]     ` <20171207201814.30411-12-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-15 10:29       ` Gregory CLEMENT
       [not found]         ` <87374cmghe.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Gregory CLEMENT @ 2017-12-15 10:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Russell King,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik, Eric Miao,
	Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi Miquel,
 
 On jeu., déc. 07 2017, Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Use the new bindings of the reworked Marvell NAND controller driver.
> Also adapt the nand controller node organization to distinguish which
> property is relevant for the controller, and which one is NAND chip
> specific. Expose the partitions as a subnode of the NAND chip.
>
> Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
> the driver activates the arbiter by default for all boards (either
> needed or harmless).
>
> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Applied on mvebu/dt64

Thanks,

Gregory

> ---
>  arch/arm64/boot/dts/marvell/armada-7040-db.dts     | 52 +++++++++++++---------
>  .../boot/dts/marvell/armada-cp110-master.dtsi      |  8 ++--
>  2 files changed, 36 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
> index 52b5341cb270..758452c10612 100644
> --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
> +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
> @@ -156,36 +156,48 @@
>  	};
>  };
>  
> -&cpm_nand {
> +&cpm_nand_controller {
>  	/*
>  	 * SPI on CPM and NAND have common pins on this board. We can
> -	 * use only one at a time. To enable the NAND (whihch will
> +	 * use only one at a time. To enable the NAND (which will
>  	 * disable the SPI), the "status = "okay";" line have to be
>  	 * added here.
>  	 */
> -	num-cs = <1>;
>  	pinctrl-0 = <&nand_pins>, <&nand_rb>;
>  	pinctrl-names = "default";
> -	nand-ecc-strength = <4>;
> -	nand-ecc-step-size = <512>;
> -	marvell,nand-enable-arbiter;
> -	nand-on-flash-bbt;
> -
> -	partition@0 {
> -		label = "U-Boot";
> -		reg = <0 0x200000>;
> -	};
> -	partition@200000 {
> -		label = "Linux";
> -		reg = <0x200000 0xe00000>;
> -	};
> -	partition@1000000 {
> -		label = "Filesystem";
> -		reg = <0x1000000 0x3f000000>;
> +
> +	nand@0 {
> +		reg = <0>;
> +		label = "pxa3xx_nand-0";
> +		marvell,rb = <0>;
> +		nand-on-flash-bbt;
> +		nand-ecc-strength = <4>;
> +		nand-ecc-step-size = <512>;
> +
> +		partitions {
> +			compatible = "fixed-partitions";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			partition@0 {
> +				label = "U-Boot";
> +				reg = <0 0x200000>;
> +			};
> +
> +			partition@200000 {
> +				label = "Linux";
> +				reg = <0x200000 0xe00000>;
> +			};
> +
> +			partition@1000000 {
> +				label = "Filesystem";
> +				reg = <0x1000000 0x3f000000>;
> +			};
> +
> +		};
>  	};
>  };
>  
> -
>  &cpm_spi1 {
>  	status = "okay";
>  
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> index e3b64d03fbd8..8a3cff9a7343 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> @@ -309,17 +309,17 @@
>  				status = "disabled";
>  			};
>  
> -			cpm_nand: nand@720000 {
> +			cpm_nand_controller: nand@720000 {
>  				/*
>  				 * Due to the limiation of the pin available
>  				 * this controller is only usable on the CPM
>  				 * for A7K and on the CPS for A8K.
>  				 */
> -				compatible = "marvell,armada-8k-nand",
> -					     "marvell,armada370-nand";
> +				compatible = "marvell,armada-8k-nand-controller",
> +					     "marvell,armada370-nand-controller";
>  				reg = <0x720000 0x54>;
>  				#address-cells = <1>;
> -				#size-cells = <1>;
> +				#size-cells = <0>;
>  				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
>  				clocks = <&cpm_clk 1 2>;
>  				marvell,system-controller = <&cpm_syscon0>;
> -- 
> 2.11.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K
       [not found]     ` <20171207201814.30411-13-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-15 10:29       ` Gregory CLEMENT
       [not found]         ` <87y3m4l1wi.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Gregory CLEMENT @ 2017-12-15 10:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Russell King,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik, Eric Miao,
	Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi Miquel,
 
 On jeu., déc. 07 2017, Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Use the new bindings of the reworked Marvell NAND controller driver.
> Also adapt the nand controller node organization to distinguish which
> property is relevant for the controller, and which one is NAND chip
> specific. Expose the partitions as a subnode of the NAND chip.
>
> Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
> the driver activates the arbiter by default for all boards (either
> needed or harmless).
>
> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Applied on mvebu/dt64

Thanks,

Gregory

> ---
>  arch/arm64/boot/dts/marvell/armada-8040-db.dts     | 46 +++++++++++++---------
>  .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi | 10 ++---
>  2 files changed, 32 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
> index b1f6cccc5081..c25ac3fa9aec 100644
> --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts
> +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
> @@ -272,27 +272,35 @@
>   * Proper NAND usage will require DPR-76 to be in position 1-2, which disables
>   * MDIO signal of CP1.
>   */
> -&cps_nand {
> -	num-cs = <1>;
> +&cps_nand_controller {
>  	pinctrl-0 = <&nand_pins>, <&nand_rb>;
>  	pinctrl-names = "default";
> -	nand-ecc-strength = <4>;
> -	nand-ecc-step-size = <512>;
> -	marvell,nand-enable-arbiter;
> -	marvell,system-controller = <&cps_syscon0>;
> -	nand-on-flash-bbt;
> -
> -	partition@0 {
> -		label = "U-Boot";
> -		reg = <0 0x200000>;
> -	};
> -	partition@200000 {
> -		label = "Linux";
> -		reg = <0x200000 0xe00000>;
> -	};
> -	partition@1000000 {
> -		label = "Filesystem";
> -		reg = <0x1000000 0x3f000000>;
> +
> +	nand@0 {
> +		reg = <0>;
> +		marvell,rb = <0>;
> +		nand-on-flash-bbt;
> +		nand-ecc-strength = <4>;
> +		nand-ecc-step-size = <512>;
> +
> +		partitions {
> +			compatible = "fixed-partitions";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			partition@0 {
> +				label = "U-Boot";
> +				reg = <0 0x200000>;
> +			};
> +			partition@200000 {
> +				label = "Linux";
> +				reg = <0x200000 0xe00000>;
> +			};
> +			partition@1000000 {
> +				label = "Filesystem";
> +				reg = <0x1000000 0x3f000000>;
> +			};
> +		};
>  	};
>  };
>  
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> index cb1fb49ccf81..8610163bb1a4 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> @@ -310,20 +310,20 @@
>  				status = "disabled";
>  			};
>  
> -			cps_nand: nand@720000 {
> +			cps_nand_controller: nand@720000 {
>  				/*
>  				 * Due to the limiation of the pin available
>  				 * this controller is only usable on the CPM
>  				 * for A7K and on the CPS for A8K.
>  				 */
> -				compatible = "marvell,armada370-nand",
> -					     "marvell,armada-8k-nand";
> +				compatible = "marvell,armada-8k-nand-controller",
> +					     "marvell,armada370-nand-controller";
>  				reg = <0x720000 0x54>;
>  				#address-cells = <1>;
> -				#size-cells = <1>;
> +				#size-cells = <0>;
>  				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
>  				clocks = <&cps_clk 1 2>;
> -				marvell,system-controller = <&cpm_syscon0>;
> +				marvell,system-controller = <&cps_syscon0>;
>  				status = "disabled";
>  			};
>  
> -- 
> 2.11.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
       [not found]         ` <87374cmghe.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-15 10:44           ` Gregory CLEMENT
  0 siblings, 0 replies; 32+ messages in thread
From: Gregory CLEMENT @ 2017-12-15 10:44 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Russell King,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik, Eric Miao,
	Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi,
 
 On ven., déc. 15 2017, Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hi Miquel,
>  
>  On jeu., déc. 07 2017, Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>
>> Use the new bindings of the reworked Marvell NAND controller driver.
>> Also adapt the nand controller node organization to distinguish which
>> property is relevant for the controller, and which one is NAND chip
>> specific. Expose the partitions as a subnode of the NAND chip.
>>
>> Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
>> the driver activates the arbiter by default for all boards (either
>> needed or harmless).
>>
>> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>
> Applied on mvebu/dt64

Well I have been said that actually thess changes are not ready and that
we should wait for the driver would me merged first so I moved it on
mvebu/dt64-nand

>
> Thanks,
>
> Gregory
>
>> ---
>>  arch/arm64/boot/dts/marvell/armada-7040-db.dts     | 52 +++++++++++++---------
>>  .../boot/dts/marvell/armada-cp110-master.dtsi      |  8 ++--
>>  2 files changed, 36 insertions(+), 24 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
>> index 52b5341cb270..758452c10612 100644
>> --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
>> +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
>> @@ -156,36 +156,48 @@
>>  	};
>>  };
>>  
>> -&cpm_nand {
>> +&cpm_nand_controller {
>>  	/*
>>  	 * SPI on CPM and NAND have common pins on this board. We can
>> -	 * use only one at a time. To enable the NAND (whihch will
>> +	 * use only one at a time. To enable the NAND (which will
>>  	 * disable the SPI), the "status = "okay";" line have to be
>>  	 * added here.
>>  	 */
>> -	num-cs = <1>;
>>  	pinctrl-0 = <&nand_pins>, <&nand_rb>;
>>  	pinctrl-names = "default";
>> -	nand-ecc-strength = <4>;
>> -	nand-ecc-step-size = <512>;
>> -	marvell,nand-enable-arbiter;
>> -	nand-on-flash-bbt;
>> -
>> -	partition@0 {
>> -		label = "U-Boot";
>> -		reg = <0 0x200000>;
>> -	};
>> -	partition@200000 {
>> -		label = "Linux";
>> -		reg = <0x200000 0xe00000>;
>> -	};
>> -	partition@1000000 {
>> -		label = "Filesystem";
>> -		reg = <0x1000000 0x3f000000>;
>> +
>> +	nand@0 {
>> +		reg = <0>;
>> +		label = "pxa3xx_nand-0";
>> +		marvell,rb = <0>;
>> +		nand-on-flash-bbt;
>> +		nand-ecc-strength = <4>;
>> +		nand-ecc-step-size = <512>;
>> +
>> +		partitions {
>> +			compatible = "fixed-partitions";
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +
>> +			partition@0 {
>> +				label = "U-Boot";
>> +				reg = <0 0x200000>;
>> +			};
>> +
>> +			partition@200000 {
>> +				label = "Linux";
>> +				reg = <0x200000 0xe00000>;
>> +			};
>> +
>> +			partition@1000000 {
>> +				label = "Filesystem";
>> +				reg = <0x1000000 0x3f000000>;
>> +			};
>> +
>> +		};
>>  	};
>>  };
>>  
>> -
>>  &cpm_spi1 {
>>  	status = "okay";
>>  
>> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
>> index e3b64d03fbd8..8a3cff9a7343 100644
>> --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
>> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
>> @@ -309,17 +309,17 @@
>>  				status = "disabled";
>>  			};
>>  
>> -			cpm_nand: nand@720000 {
>> +			cpm_nand_controller: nand@720000 {
>>  				/*
>>  				 * Due to the limiation of the pin available
>>  				 * this controller is only usable on the CPM
>>  				 * for A7K and on the CPS for A8K.
>>  				 */
>> -				compatible = "marvell,armada-8k-nand",
>> -					     "marvell,armada370-nand";
>> +				compatible = "marvell,armada-8k-nand-controller",
>> +					     "marvell,armada370-nand-controller";
>>  				reg = <0x720000 0x54>;
>>  				#address-cells = <1>;
>> -				#size-cells = <1>;
>> +				#size-cells = <0>;
>>  				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
>>  				clocks = <&cpm_clk 1 2>;
>>  				marvell,system-controller = <&cpm_syscon0>;
>> -- 
>> 2.11.0
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> -- 
> Gregory Clement, Free Electrons
> Kernel, drivers, real-time and embedded Linux
> development, consulting, training and support.
> http://free-electrons.com

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K
       [not found]         ` <87y3m4l1wi.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-12-15 10:44           ` Gregory CLEMENT
  0 siblings, 0 replies; 32+ messages in thread
From: Gregory CLEMENT @ 2017-12-15 10:44 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Russell King,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik, Eric Miao,
	Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi,
 
 On ven., déc. 15 2017, Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hi Miquel,
>  
>  On jeu., déc. 07 2017, Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>
>> Use the new bindings of the reworked Marvell NAND controller driver.
>> Also adapt the nand controller node organization to distinguish which
>> property is relevant for the controller, and which one is NAND chip
>> specific. Expose the partitions as a subnode of the NAND chip.
>>
>> Remove the 'marvell,nand-enable-arbiter' property, not needed anymore as
>> the driver activates the arbiter by default for all boards (either
>> needed or harmless).
>>
>> Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>
> Applied on mvebu/dt64


As for the other paych, I have been said that actually thess changes are
not ready and that we should wait for the driver would me merged first
so I moved it on mvebu/dt64-nand

Gregory

>
> Thanks,
>
> Gregory
>
>> ---
>>  arch/arm64/boot/dts/marvell/armada-8040-db.dts     | 46 +++++++++++++---------
>>  .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi | 10 ++---
>>  2 files changed, 32 insertions(+), 24 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
>> index b1f6cccc5081..c25ac3fa9aec 100644
>> --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts
>> +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
>> @@ -272,27 +272,35 @@
>>   * Proper NAND usage will require DPR-76 to be in position 1-2, which disables
>>   * MDIO signal of CP1.
>>   */
>> -&cps_nand {
>> -	num-cs = <1>;
>> +&cps_nand_controller {
>>  	pinctrl-0 = <&nand_pins>, <&nand_rb>;
>>  	pinctrl-names = "default";
>> -	nand-ecc-strength = <4>;
>> -	nand-ecc-step-size = <512>;
>> -	marvell,nand-enable-arbiter;
>> -	marvell,system-controller = <&cps_syscon0>;
>> -	nand-on-flash-bbt;
>> -
>> -	partition@0 {
>> -		label = "U-Boot";
>> -		reg = <0 0x200000>;
>> -	};
>> -	partition@200000 {
>> -		label = "Linux";
>> -		reg = <0x200000 0xe00000>;
>> -	};
>> -	partition@1000000 {
>> -		label = "Filesystem";
>> -		reg = <0x1000000 0x3f000000>;
>> +
>> +	nand@0 {
>> +		reg = <0>;
>> +		marvell,rb = <0>;
>> +		nand-on-flash-bbt;
>> +		nand-ecc-strength = <4>;
>> +		nand-ecc-step-size = <512>;
>> +
>> +		partitions {
>> +			compatible = "fixed-partitions";
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +
>> +			partition@0 {
>> +				label = "U-Boot";
>> +				reg = <0 0x200000>;
>> +			};
>> +			partition@200000 {
>> +				label = "Linux";
>> +				reg = <0x200000 0xe00000>;
>> +			};
>> +			partition@1000000 {
>> +				label = "Filesystem";
>> +				reg = <0x1000000 0x3f000000>;
>> +			};
>> +		};
>>  	};
>>  };
>>  
>> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
>> index cb1fb49ccf81..8610163bb1a4 100644
>> --- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
>> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
>> @@ -310,20 +310,20 @@
>>  				status = "disabled";
>>  			};
>>  
>> -			cps_nand: nand@720000 {
>> +			cps_nand_controller: nand@720000 {
>>  				/*
>>  				 * Due to the limiation of the pin available
>>  				 * this controller is only usable on the CPM
>>  				 * for A7K and on the CPS for A8K.
>>  				 */
>> -				compatible = "marvell,armada370-nand",
>> -					     "marvell,armada-8k-nand";
>> +				compatible = "marvell,armada-8k-nand-controller",
>> +					     "marvell,armada370-nand-controller";
>>  				reg = <0x720000 0x54>;
>>  				#address-cells = <1>;
>> -				#size-cells = <1>;
>> +				#size-cells = <0>;
>>  				interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
>>  				clocks = <&cps_clk 1 2>;
>> -				marvell,system-controller = <&cpm_syscon0>;
>> +				marvell,system-controller = <&cps_syscon0>;
>>  				status = "disabled";
>>  			};
>>  
>> -- 
>> 2.11.0
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> -- 
> Gregory Clement, Free Electrons
> Kernel, drivers, real-time and embedded Linux
> development, consulting, training and support.
> http://free-electrons.com

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
  2017-12-14  6:09   ` Boris Brezillon
@ 2017-12-18  7:11     ` Robert Jarzmik
       [not found]       ` <877etkecig.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Robert Jarzmik @ 2017-12-18  7:11 UTC (permalink / raw)
  To: Boris Brezillon, Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Catalin Marinas, Hanna Hawa,
	Will Deacon, Nadav Haklai, linux-mtd, Richard Weinberger,
	Russell King, Marek Vasut, Ezequiel Garcia,
	Sebastian Hesselbarth, devicetree, Jason Cooper, Haojian Zhuang,
	Rob Herring, Gregory Clement, Ofer Heifetz, linux-arm-kernel,
	Thomas Petazzoni, Eric Miao, Antoine Tenart, Cyri

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

>> Robert, it would be great if you could also do more testing on PXA and
>> validate this driver. If needed, a branch ready to be tested is
>> available at [3]. It is based on nand/next and has all the changes
>> brought by the previously mentionned series as well as this one.
>
> Robert, do you think you'll have some time to test Miquel's branch on
> your PXA boards? Miquel already tested on one of these boards (CM-X300),
> but we'd like to have other testers. Also feel free to review the
> driver if have the time.
>
> Thanks,
>
> Boris

Hi Boris and Miquel,

I have applied the whole serie to linux-next yesterday.

A boot attempt on my zylonite with my old defconfig (with the new Marvell NAND
config activated) yields to :
 - this message
[    3.136818] marvell-nfc pxa3xx-nand: could not identify the nand chip
[    3.143874] marvell-nfc: probe of pxa3xx-nand failed with error -22
 - then my board hangs

Is there something to be done to improve the trace level so that you can guess
what's happening ?

Cheers.

--
Robert

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
       [not found]       ` <877etkecig.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
@ 2017-12-18  8:25         ` Miquel RAYNAL
  2017-12-20 21:26           ` Robert Jarzmik
  0 siblings, 1 reply; 32+ messages in thread
From: Miquel RAYNAL @ 2017-12-18  8:25 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon

Hello Robert,

On Mon, 18 Dec 2017 08:11:35 +0100
Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:

> Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> 
> >> Robert, it would be great if you could also do more testing on PXA
> >> and validate this driver. If needed, a branch ready to be tested is
> >> available at [3]. It is based on nand/next and has all the changes
> >> brought by the previously mentionned series as well as this one.  
> >
> > Robert, do you think you'll have some time to test Miquel's branch
> > on your PXA boards? Miquel already tested on one of these boards
> > (CM-X300), but we'd like to have other testers. Also feel free to
> > review the driver if have the time.
> >
> > Thanks,
> >
> > Boris  
> 
> Hi Boris and Miquel,
> 
> I have applied the whole serie to linux-next yesterday.
> 
> A boot attempt on my zylonite with my old defconfig (with the new
> Marvell NAND config activated) yields to :
>  - this message
> [    3.136818] marvell-nfc pxa3xx-nand: could not identify the nand
> chip [    3.143874] marvell-nfc: probe of pxa3xx-nand failed with
> error -22
>  - then my board hangs
> 
> Is there something to be done to improve the trace level so that you
> can guess what's happening ?

Thank you very much for testing this.

Could you please try this branch [1] instead of linux-next + the
patches?

Also, can you please add #define DEBUG in marvell_nand.c + nand_base.c,
it should help us figuring out what is wrong.

Thank you,
Miquèl

[1] https://github.com/miquelraynal/linux/tree/marvell/nand-next/nfc
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
  2017-12-18  8:25         ` Miquel RAYNAL
@ 2017-12-20 21:26           ` Robert Jarzmik
       [not found]             ` <87y3lxccr7.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Robert Jarzmik @ 2017-12-20 21:26 UTC (permalink / raw)
  To: Miquel RAYNAL
  Cc: Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon

Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:

> Hello Robert,
>
> On Mon, 18 Dec 2017 08:11:35 +0100
> Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:
>
>> Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
>> 
>> >> Robert, it would be great if you could also do more testing on PXA
>> >> and validate this driver. If needed, a branch ready to be tested is
>> >> available at [3]. It is based on nand/next and has all the changes
>> >> brought by the previously mentionned series as well as this one.  
>> >
>> > Robert, do you think you'll have some time to test Miquel's branch
>> > on your PXA boards? Miquel already tested on one of these boards
>> > (CM-X300), but we'd like to have other testers. Also feel free to
>> > review the driver if have the time.
>> >
>> > Thanks,
>> >
>> > Boris  
>> 
>> Hi Boris and Miquel,
>> 
>> I have applied the whole serie to linux-next yesterday.
>> 
>> A boot attempt on my zylonite with my old defconfig (with the new
>> Marvell NAND config activated) yields to :
>>  - this message
>> [    3.136818] marvell-nfc pxa3xx-nand: could not identify the nand
>> chip [    3.143874] marvell-nfc: probe of pxa3xx-nand failed with
>> error -22
>>  - then my board hangs
>> 
>> Is there something to be done to improve the trace level so that you
>> can guess what's happening ?
>
> Thank you very much for testing this.
>
> Could you please try this branch [1] instead of linux-next + the
> patches?
>
> Also, can you please add #define DEBUG in marvell_nand.c + nand_base.c,
> it should help us figuring out what is wrong.

Done, same result, the dmesg is in [1].

Cheers.

-- 
Robert

[1] Kernel output
Loading ARM Linux zImage '/mnt/tftp/zImage_jenkins'
commandline: ram=64M console=ttyS0,115200 ip=dhcp root=/dev/nfs nfsroot=/home/none/nfsroot/zylonite,v3,tcp earlycon mtdparts=pxa3xx_nand-0:128k@0(TIMH)ro,128k@128k(OBMI)ro,768k@256k(barebox),256k@1024k(barebox-env),12M@1280k(kernel),38016k@13568k(root)
arch_number: 1233
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.15.0-rc1-00041-g4dc0195 (jenkins@belgarath) (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29)) #721 PREEMPT Wed Dec 20 22:15:08 CET 2017
[    0.000000] CPU: XScale-V3 based processor [69056891] revision 1 (ARMv5TE), cr=0000397f
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] Machine: PXA3xx Platform Development Kit (aka Zylonite)
[    0.000000] Ignoring tag cmdline (using the default kernel command line)
[    0.000000] Memory policy: Data cache writeback
[    0.000000] RO Mode clock: 0.00MHz
[    0.000000] Run Mode clock: 0.00MHz
[    0.000000] Turbo Mode clock: 0.00MHz
[    0.000000] System bus clock: 0.00MHz
[    0.000000] On node 0 totalpages: 16384
[    0.000000]   Normal zone: 128 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 16384 pages, LIFO batch:3
[    0.000000] random: fast init done
[    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.000000] pcpu-alloc: [0] 0 
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 16256
[    0.000000] Kernel command line: root=/dev/ram0 ip=192.168.1.232:192.168.1.5::255.255.255.0::eth0:on console=ttyS0,115200 mem=64M mtdparts=pxa3xx_nand-0:128k@0(TIMH)ro,128k@128k(OBMI)ro,768k@256k(barebox),256k@1024k(barebox-env),12M@1280k(kernel),38016k@13568k(root) ubi.mtd=5 earlycon=pxa,io,0xf6200000,115200n8 debug no_console_suspend
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 56856K/65536K available (4225K kernel code, 202K rwdata, 972K rodata, 2396K init, 102K bss, 8680K reserved, 0K cma-reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xc4800000 - 0xff800000   ( 944 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0xc0008000 - 0xc04289e8   (4227 kB)
[    0.000000]       .init : 0xc053f000 - 0xc0796000   (2396 kB)
[    0.000000]       .data : 0xc0796000 - 0xc07c8bec   ( 203 kB)
[    0.000000]        .bss : 0xc07c8bec - 0xc07e25fc   ( 103 kB)
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000] 	Tasks RCU enabled.
[    0.000000] NR_IRQS: 16, nr_irqs: 336, preallocated irqs: 336
[    0.000000] RJK: parent_rate=13000000, xl=8, xn=1
[    0.000069] sched_clock: 32 bits at 3250kHz, resolution 307ns, wraps every 660764198758ns
[    0.000267] clocksource: oscr0: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 588080137591 ns
[    0.002142] Console: colour dummy device 80x30
[    0.002302] Calibrating delay loop... 103.83 BogoMIPS (lpj=519168)
[    0.081019] pid_max: default: 32768 minimum: 301
[    0.081860] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.081960] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.085178] CPU: Testing write buffer coherency: ok
[    0.089002] Setting up static identity map for 0x80008200 - 0x80008260
[    0.089962] Hierarchical SRCU implementation.
[    0.102994] devtmpfs: initialized
[    0.113882] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.114023] futex hash table entries: 256 (order: -1, 3072 bytes)
[    0.116361] NET: Registered protocol family 16
[    0.119175] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.389891] Advanced Linux Sound Architecture Driver Initialized.
[    0.394261] clocksource: Switched to clocksource oscr0
[    0.552465] NET: Registered protocol family 2
[    0.559531] TCP established hash table entries: 1024 (order: 0, 4096 bytes)
[    0.559757] TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
[    0.559938] TCP: Hash tables configured (established 1024 bind 1024)
[    0.560478] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    0.560660] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    0.561794] NET: Registered protocol family 1
[    0.563834] RPC: Registered named UNIX socket transport module.
[    0.563934] RPC: Registered udp transport module.
[    0.563988] RPC: Registered tcp transport module.
[    0.564046] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    2.503938] Initialise system trusted keyrings
[    2.506180] workingset: timestamp_bits=30 max_order=14 bucket_order=0
[    2.510083] NFS: Registering the id_resolver key type
[    2.510312] Key type id_resolver registered
[    2.510374] Key type id_legacy registered
[    2.516887] Key type asymmetric registered
[    2.516991] Asymmetric key parser 'x509' registered
[    2.517149] io scheduler noop registered
[    2.517213] io scheduler deadline registered
[    2.517601] io scheduler cfq registered (default)
[    2.517671] io scheduler mq-deadline registered
[    2.517732] io scheduler kyber registered
[    2.577937] pxa-dma pxa-dma.0: initialized 32 channels on 100 requestors
[    2.581363] pxa2xx-uart.0: ttyS0 at MMIO 0x40100000 (irq = 38, base_baud = 928571) is a UART1
[    3.056921] console [ttyS0] enabled
[    3.063284] pxa2xx-uart.1: ttyS1 at MMIO 0x40200000 (irq = 37, base_baud = 928571) is a UART2
[    3.076187] pxa2xx-uart.2: ttyS2 at MMIO 0x40700000 (irq = 36, base_baud = 928571) is a UART3
[    3.091759] nand: executing subop:
[    3.097924] nand:     ->CMD      [0xff]
[    3.101830] nand:     ->WAITRDY  [max 250 ms]
[    3.106998] marvell-nfc pxa3xx-nand: 
[    3.106998] NDCR:  0x90079fff
[    3.106998] NDCB0: 0x00a000ff
[    3.106998] NDCB1: 0x00000000
[    3.106998] NDCB2: 0x00000000
[    3.106998] NDCB3: 0x00000000
[    3.126261] nand: executing subop:
[    3.129732] nand:     ->CMD      [0x90]
[    3.133605] nand:     ->ADDR     [1 cyc: 00]
[    3.138275] nand:     ->DATA_IN  [2 B, force 8-bit]
[    3.143276] marvell-nfc pxa3xx-nand: 
[    3.143276] NDCR:  0x90079fff
[    3.143276] NDCB0: 0x00610090
[    3.143276] NDCB1: 0x00000000
[    3.143276] NDCB2: 0x00000000
[    3.143276] NDCB3: 0x00000000
[    3.162111] nand: executing subop:
[    3.165754] nand:     ->CMD      [0x90]
[    3.169644] nand:     ->ADDR     [1 cyc: 00]
[    3.173945] nand:     ->DATA_IN  [8 B, force 8-bit]
[    3.179056] marvell-nfc pxa3xx-nand: 
[    3.179056] NDCR:  0x90079fff
[    3.179056] NDCB0: 0x00610090
[    3.179056] NDCB1: 0x00000000
[    3.179056] NDCB2: 0x00000000
[    3.179056] NDCB3: 0x00000000
[    3.197729] nand: executing subop:
[    3.201185] nand:     ->CMD      [0x90]
[    3.205207] nand:     ->ADDR     [1 cyc: 20]
[    3.209519] nand:     ->DATA_IN  [4 B, force 8-bit]
[    3.214626] marvell-nfc pxa3xx-nand: 
[    3.214626] NDCR:  0x90079fff
[    3.214626] NDCB0: 0x00610090
[    3.214626] NDCB1: 0x00000020
[    3.214626] NDCB2: 0x00000000
[    3.214626] NDCB3: 0x00000000
[    3.233249] nand: executing subop:
[    3.236837] nand:     ->CMD      [0x90]
[    3.240719] nand:     ->ADDR     [1 cyc: 40]
[    3.245158] nand:     ->DATA_IN  [5 B, force 8-bit]
[    3.250133] marvell-nfc pxa3xx-nand: 
[    3.250133] NDCR:  0x90079fff
[    3.250133] NDCB0: 0x00610090
[    3.250133] NDCB1: 0x00000040
[    3.250133] NDCB2: 0x00000000
[    3.250133] NDCB3: 0x00000000
[    3.268756] nand: device found, Manufacturer ID: 0x20, Chip ID: 0xba
[    3.275239] nand: ST Micro pxa3xx-nand
[    3.279028] nand: bus width 8 instead of 16 bits
[    3.283651] nand: No NAND device found
[    3.287582] marvell-nfc pxa3xx-nand: could not identify the nand chip
[    3.294466] marvell-nfc: probe of pxa3xx-nand failed with error -22
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
       [not found]             ` <87y3lxccr7.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
@ 2017-12-20 21:41               ` Boris Brezillon
  2017-12-22 20:11                 ` Robert Jarzmik
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2017-12-20 21:41 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Miquel RAYNAL, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

On Wed, 20 Dec 2017 22:26:04 +0100
Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:

> Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> 
> > Hello Robert,
> >
> > On Mon, 18 Dec 2017 08:11:35 +0100
> > Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:
> >  
> >> Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> >>   
> >> >> Robert, it would be great if you could also do more testing on PXA
> >> >> and validate this driver. If needed, a branch ready to be tested is
> >> >> available at [3]. It is based on nand/next and has all the changes
> >> >> brought by the previously mentionned series as well as this one.    
> >> >
> >> > Robert, do you think you'll have some time to test Miquel's branch
> >> > on your PXA boards? Miquel already tested on one of these boards
> >> > (CM-X300), but we'd like to have other testers. Also feel free to
> >> > review the driver if have the time.
> >> >
> >> > Thanks,
> >> >
> >> > Boris    
> >> 
> >> Hi Boris and Miquel,
> >> 
> >> I have applied the whole serie to linux-next yesterday.
> >> 
> >> A boot attempt on my zylonite with my old defconfig (with the new
> >> Marvell NAND config activated) yields to :
> >>  - this message
> >> [    3.136818] marvell-nfc pxa3xx-nand: could not identify the nand
> >> chip [    3.143874] marvell-nfc: probe of pxa3xx-nand failed with
> >> error -22
> >>  - then my board hangs
> >> 
> >> Is there something to be done to improve the trace level so that you
> >> can guess what's happening ?  
> >
> > Thank you very much for testing this.
> >
> > Could you please try this branch [1] instead of linux-next + the
> > patches?
> >
> > Also, can you please add #define DEBUG in marvell_nand.c + nand_base.c,
> > it should help us figuring out what is wrong.  
> 
> Done, same result, the dmesg is in [1].

Looks like there is a mismatch on the nand bus width detected by the
core and the one declared by the driver. Can you try with the following
diff applied?

Thanks,

Boris

--->8---
diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c
index c618ccb22a61..ddd6a07888e2 100644
--- a/drivers/mtd/nand/marvell_nand.c
+++ b/drivers/mtd/nand/marvell_nand.c
@@ -2481,6 +2481,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
         */
        chip->ecc.mode = NAND_ECC_HW;
 
+       chip->options |= NAND_BUSWIDTH_AUTO;
        ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
        if (ret) {
                dev_err(dev, "could not identify the nand chip\n");
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
  2017-12-20 21:41               ` Boris Brezillon
@ 2017-12-22 20:11                 ` Robert Jarzmik
       [not found]                   ` <87lghucykr.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
  0 siblings, 1 reply; 32+ messages in thread
From: Robert Jarzmik @ 2017-12-22 20:11 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel RAYNAL, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:

> Looks like there is a mismatch on the nand bus width detected by the
> core and the one declared by the driver. Can you try with the following
> diff applied?

Sure.

Now I get a lot of these message which I didn't have before :
[   26.897372] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
[   26.928559] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
[   26.959623] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
[   26.990714] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read 126976 bytes
[   27.002084] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97 #737
[   27.009674] Hardware name: PXA3xx Platform Development Kit (aka Zylonite)
[   27.016750] [<c0010440>] (unwind_backtrace) from [<c000df94>] (show_stack+0x10/0x14)
[   27.024729] [<c000df94>] (show_stack) from [<c02c5bd4>] (ubi_io_read+0x124/0x368)
[   27.032453] [<c02c5bd4>] (ubi_io_read) from [<c02cd550>] (ubi_attach+0xbd8/0x1868)
[   27.040148] [<c02cd550>] (ubi_attach) from [<c02be7c4>] (ubi_attach_mtd_dev+0x548/0xe58)
[   27.048473] [<c02be7c4>] (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
[   27.056623] [<c05526e4>] (ubi_init) from [<c00099f8>] (do_one_initcall+0x3c/0x17c)
[   27.064466] [<c00099f8>] (do_one_initcall) from [<c053fd80>] (kernel_init_freeable+0x104/0x1c0)
[   27.073398] [<c053fd80>] (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
[   27.081715] [<c0423ab8>] (kernel_init) from [<c000a780>] (ret_from_fork+0x14/0x34)
[   27.090115] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
[   27.102363] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
[   27.114586] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
[   27.126813] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read 64 bytes
[   27.137416] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97 #737
[   27.145143] Hardware name: PXA3xx Platform Development Kit (aka Zylonite)
[   27.152207] [<c0010440>] (unwind_backtrace) from [<c000df94>] (show_stack+0x10/0x14)
[   27.160037] [<c000df94>] (show_stack) from [<c02c5bd4>] (ubi_io_read+0x124/0x368)
[   27.167742] [<c02c5bd4>] (ubi_io_read) from [<c02c63dc>] (ubi_io_read_vid_hdr+0x60/0x3ac)
[   27.176156] [<c02c63dc>] (ubi_io_read_vid_hdr) from [<c02cce58>] (ubi_attach+0x4e0/0x1868)
[   27.184675] [<c02cce58>] (ubi_attach) from [<c02be7c4>] (ubi_attach_mtd_dev+0x548/0xe58)
[   27.193010] [<c02be7c4>] (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
[   27.201159] [<c05526e4>] (ubi_init) from [<c00099f8>] (do_one_initcall+0x3c/0x17c)
[   27.208839] [<c00099f8>] (do_one_initcall) from [<c053fd80>] (kernel_init_freeable+0x104/0x1c0)
[   27.217755] [<c053fd80>] (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
[   27.226074] [<c0423ab8>] (kernel_init) from [<c000a780>] (ret_from_fork+0x14/0x34)

Cheers.

-- 
Robert
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
       [not found]                   ` <87lghucykr.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
@ 2017-12-22 21:24                     ` Boris Brezillon
  2017-12-22 22:37                       ` Miquel RAYNAL
  0 siblings, 1 reply; 32+ messages in thread
From: Boris Brezillon @ 2017-12-22 21:24 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Miquel RAYNAL, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi Robert,

On Fri, 22 Dec 2017 21:11:32 +0100
Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:

> Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> 
> > Looks like there is a mismatch on the nand bus width detected by the
> > core and the one declared by the driver. Can you try with the following
> > diff applied?  
> 
> Sure.
> 
> Now I get a lot of these message which I didn't have before :
> [   26.897372] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
> [   26.928559] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
> [   26.959623] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read only 126976 bytes, retry
> [   26.990714] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read 126976 bytes
> [   27.002084] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97 #737
> [   27.009674] Hardware name: PXA3xx Platform Development Kit (aka Zylonite)
> [   27.016750] [<c0010440>] (unwind_backtrace) from [<c000df94>] (show_stack+0x10/0x14)
> [   27.024729] [<c000df94>] (show_stack) from [<c02c5bd4>] (ubi_io_read+0x124/0x368)
> [   27.032453] [<c02c5bd4>] (ubi_io_read) from [<c02cd550>] (ubi_attach+0xbd8/0x1868)
> [   27.040148] [<c02cd550>] (ubi_attach) from [<c02be7c4>] (ubi_attach_mtd_dev+0x548/0xe58)
> [   27.048473] [<c02be7c4>] (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
> [   27.056623] [<c05526e4>] (ubi_init) from [<c00099f8>] (do_one_initcall+0x3c/0x17c)
> [   27.064466] [<c00099f8>] (do_one_initcall) from [<c053fd80>] (kernel_init_freeable+0x104/0x1c0)
> [   27.073398] [<c053fd80>] (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> [   27.081715] [<c0423ab8>] (kernel_init) from [<c000a780>] (ret_from_fork+0x14/0x34)
> [   27.090115] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
> [   27.102363] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
> [   27.114586] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read only 64 bytes, retry
> [   27.126813] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 243:2048, read 64 bytes
> [   27.137416] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97 #737
> [   27.145143] Hardware name: PXA3xx Platform Development Kit (aka Zylonite)
> [   27.152207] [<c0010440>] (unwind_backtrace) from [<c000df94>] (show_stack+0x10/0x14)
> [   27.160037] [<c000df94>] (show_stack) from [<c02c5bd4>] (ubi_io_read+0x124/0x368)
> [   27.167742] [<c02c5bd4>] (ubi_io_read) from [<c02c63dc>] (ubi_io_read_vid_hdr+0x60/0x3ac)
> [   27.176156] [<c02c63dc>] (ubi_io_read_vid_hdr) from [<c02cce58>] (ubi_attach+0x4e0/0x1868)
> [   27.184675] [<c02cce58>] (ubi_attach) from [<c02be7c4>] (ubi_attach_mtd_dev+0x548/0xe58)
> [   27.193010] [<c02be7c4>] (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
> [   27.201159] [<c05526e4>] (ubi_init) from [<c00099f8>] (do_one_initcall+0x3c/0x17c)
> [   27.208839] [<c00099f8>] (do_one_initcall) from [<c053fd80>] (kernel_init_freeable+0x104/0x1c0)
> [   27.217755] [<c053fd80>] (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> [   27.226074] [<c0423ab8>] (kernel_init) from [<c000a780>] (ret_from_fork+0x14/0x34)

Looks like a mismatch in the ECC config. Can you check the ecc
strength/step_size in both situation (old driver vs new driver)? Could
you also dump the NDCR register in both cases?

Thanks,

Boris
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
  2017-12-22 21:24                     ` Boris Brezillon
@ 2017-12-22 22:37                       ` Miquel RAYNAL
  2017-12-22 22:50                         ` Miquel RAYNAL
  0 siblings, 1 reply; 32+ messages in thread
From: Miquel RAYNAL @ 2017-12-22 22:37 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Robert Jarzmik, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

Hi Robert,

On Fri, 22 Dec 2017 22:24:41 +0100
Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hi Robert,
> 
> On Fri, 22 Dec 2017 21:11:32 +0100
> Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:
> 
> > Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> >   
> > > Looks like there is a mismatch on the nand bus width detected by
> > > the core and the one declared by the driver. Can you try with the
> > > following diff applied?    
> > 
> > Sure.
> > 
> > Now I get a lot of these message which I didn't have before :
> > [   26.897372] ubi0 warning: ubi_io_read: error -74 (ECC error)
> > while reading 126976 bytes from PEB 242:4096, read only 126976
> > bytes, retry [   26.928559] ubi0 warning: ubi_io_read: error -74
> > (ECC error) while reading 126976 bytes from PEB 242:4096, read only
> > 126976 bytes, retry [   26.959623] ubi0 warning: ubi_io_read: error
> > -74 (ECC error) while reading 126976 bytes from PEB 242:4096, read
> > only 126976 bytes, retry [   26.990714] ubi0 error: ubi_io_read:
> > error -74 (ECC error) while reading 126976 bytes from PEB 242:4096,
> > read 126976 bytes [   27.002084] CPU: 0 PID: 1 Comm: swapper Not
> > tainted 4.15.0-rc1-00041-ge371e97 #737 [   27.009674] Hardware
> > name: PXA3xx Platform Development Kit (aka Zylonite) [   27.016750]
> > [<c0010440>] (unwind_backtrace) from [<c000df94>]
> > (show_stack+0x10/0x14) [   27.024729] [<c000df94>] (show_stack)
> > from [<c02c5bd4>] (ubi_io_read+0x124/0x368) [   27.032453]
> > [<c02c5bd4>] (ubi_io_read) from [<c02cd550>]
> > (ubi_attach+0xbd8/0x1868) [   27.040148] [<c02cd550>] (ubi_attach)
> > from [<c02be7c4>] (ubi_attach_mtd_dev+0x548/0xe58) [   27.048473]
> > [<c02be7c4>] (ubi_attach_mtd_dev) from [<c05526e4>]
> > (ubi_init+0x134/0x1d4) [   27.056623] [<c05526e4>] (ubi_init) from
> > [<c00099f8>] (do_one_initcall+0x3c/0x17c) [   27.064466]
> > [<c00099f8>] (do_one_initcall) from [<c053fd80>]
> > (kernel_init_freeable+0x104/0x1c0) [   27.073398] [<c053fd80>]
> > (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> > [   27.081715] [<c0423ab8>] (kernel_init) from [<c000a780>]
> > (ret_from_fork+0x14/0x34) [   27.090115] ubi0 warning: ubi_io_read:
> > error -74 (ECC error) while reading 64 bytes from PEB 243:2048,
> > read only 64 bytes, retry [   27.102363] ubi0 warning: ubi_io_read:
> > error -74 (ECC error) while reading 64 bytes from PEB 243:2048,
> > read only 64 bytes, retry [   27.114586] ubi0 warning: ubi_io_read:
> > error -74 (ECC error) while reading 64 bytes from PEB 243:2048,
> > read only 64 bytes, retry [   27.126813] ubi0 error: ubi_io_read:
> > error -74 (ECC error) while reading 64 bytes from PEB 243:2048,
> > read 64 bytes [   27.137416] CPU: 0 PID: 1 Comm: swapper Not
> > tainted 4.15.0-rc1-00041-ge371e97 #737 [   27.145143] Hardware
> > name: PXA3xx Platform Development Kit (aka Zylonite) [   27.152207]
> > [<c0010440>] (unwind_backtrace) from [<c000df94>]
> > (show_stack+0x10/0x14) [   27.160037] [<c000df94>] (show_stack)
> > from [<c02c5bd4>] (ubi_io_read+0x124/0x368) [   27.167742]
> > [<c02c5bd4>] (ubi_io_read) from [<c02c63dc>]
> > (ubi_io_read_vid_hdr+0x60/0x3ac) [   27.176156] [<c02c63dc>]
> > (ubi_io_read_vid_hdr) from [<c02cce58>] (ubi_attach+0x4e0/0x1868)
> > [   27.184675] [<c02cce58>] (ubi_attach) from [<c02be7c4>]
> > (ubi_attach_mtd_dev+0x548/0xe58) [   27.193010] [<c02be7c4>]
> > (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
> > [   27.201159] [<c05526e4>] (ubi_init) from [<c00099f8>]
> > (do_one_initcall+0x3c/0x17c) [   27.208839] [<c00099f8>]
> > (do_one_initcall) from [<c053fd80>]
> > (kernel_init_freeable+0x104/0x1c0) [   27.217755] [<c053fd80>]
> > (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> > [   27.226074] [<c0423ab8>] (kernel_init) from [<c000a780>]
> > (ret_from_fork+0x14/0x34)  
> 
> Looks like a mismatch in the ECC config. Can you check the ecc
> strength/step_size in both situation (old driver vs new driver)?

For that, you might want to add traces in marvell_nand_ecc_init() and
marvell_nand_hw_ecc_ctrl_init().

> Could you also dump the NDCR register in both cases?

NDCR register (as well as NDCBx registers) will appear if you let

    #define DEBUG

at the beginning of the driver.

Also, can you please give us the entire dmesg (I mean the boot, not the
flow of UBIFS errors of course).

If this, in conjunction with your check of the ECC configuration, does
not give satisfying results, I will write a test script using
nandwrite/nanddump/flash_erase.

Thank you,
Miquèl


> 
> Thanks,
> 
> Boris



-- 
Miquel Raynal, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
  2017-12-22 22:37                       ` Miquel RAYNAL
@ 2017-12-22 22:50                         ` Miquel RAYNAL
  0 siblings, 0 replies; 32+ messages in thread
From: Miquel RAYNAL @ 2017-12-22 22:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Robert Jarzmik, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
	Jason Cooper, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Russell King, Daniel Mack, Haojian Zhuang,
	Eric Miao, Catalin Marinas, Will Deacon, Ezequiel Garcia

On Fri, 22 Dec 2017 23:37:30 +0100
Miquel RAYNAL <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hi Robert,
> 
> On Fri, 22 Dec 2017 22:24:41 +0100
> Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> 
> > Hi Robert,
> > 
> > On Fri, 22 Dec 2017 21:11:32 +0100
> > Robert Jarzmik <robert.jarzmik-GANU6spQydw@public.gmane.org> wrote:
> > 
> > > Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes:
> > >   
> > > > Looks like there is a mismatch on the nand bus width detected by
> > > > the core and the one declared by the driver. Can you try with
> > > > the following diff applied?    
> > > 
> > > Sure.
> > > 
> > > Now I get a lot of these message which I didn't have before :
> > > [   26.897372] ubi0 warning: ubi_io_read: error -74 (ECC error)
> > > while reading 126976 bytes from PEB 242:4096, read only 126976
> > > bytes, retry [   26.928559] ubi0 warning: ubi_io_read: error -74
> > > (ECC error) while reading 126976 bytes from PEB 242:4096, read
> > > only 126976 bytes, retry [   26.959623] ubi0 warning:
> > > ubi_io_read: error -74 (ECC error) while reading 126976 bytes
> > > from PEB 242:4096, read only 126976 bytes, retry [   26.990714]
> > > ubi0 error: ubi_io_read: error -74 (ECC error) while reading
> > > 126976 bytes from PEB 242:4096, read 126976 bytes [   27.002084]
> > > CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97
> > > #737 [   27.009674] Hardware name: PXA3xx Platform Development
> > > Kit (aka Zylonite) [   27.016750] [<c0010440>] (unwind_backtrace)
> > > from [<c000df94>] (show_stack+0x10/0x14) [   27.024729]
> > > [<c000df94>] (show_stack) from [<c02c5bd4>]
> > > (ubi_io_read+0x124/0x368) [   27.032453] [<c02c5bd4>]
> > > (ubi_io_read) from [<c02cd550>] (ubi_attach+0xbd8/0x1868)
> > > [   27.040148] [<c02cd550>] (ubi_attach) from [<c02be7c4>]
> > > (ubi_attach_mtd_dev+0x548/0xe58) [   27.048473] [<c02be7c4>]
> > > (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
> > > [   27.056623] [<c05526e4>] (ubi_init) from [<c00099f8>]
> > > (do_one_initcall+0x3c/0x17c) [   27.064466] [<c00099f8>]
> > > (do_one_initcall) from [<c053fd80>]
> > > (kernel_init_freeable+0x104/0x1c0) [   27.073398] [<c053fd80>]
> > > (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> > > [   27.081715] [<c0423ab8>] (kernel_init) from [<c000a780>]
> > > (ret_from_fork+0x14/0x34) [   27.090115] ubi0 warning:
> > > ubi_io_read: error -74 (ECC error) while reading 64 bytes from
> > > PEB 243:2048, read only 64 bytes, retry [   27.102363] ubi0
> > > warning: ubi_io_read: error -74 (ECC error) while reading 64
> > > bytes from PEB 243:2048, read only 64 bytes, retry [   27.114586]
> > > ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64
> > > bytes from PEB 243:2048, read only 64 bytes, retry [   27.126813]
> > > ubi0 error: ubi_io_read: error -74 (ECC error) while reading 64
> > > bytes from PEB 243:2048, read 64 bytes [   27.137416] CPU: 0 PID:
> > > 1 Comm: swapper Not tainted 4.15.0-rc1-00041-ge371e97 #737
> > > [   27.145143] Hardware name: PXA3xx Platform Development Kit
> > > (aka Zylonite) [   27.152207] [<c0010440>] (unwind_backtrace)
> > > from [<c000df94>] (show_stack+0x10/0x14) [   27.160037]
> > > [<c000df94>] (show_stack) from [<c02c5bd4>]
> > > (ubi_io_read+0x124/0x368) [   27.167742] [<c02c5bd4>]
> > > (ubi_io_read) from [<c02c63dc>] (ubi_io_read_vid_hdr+0x60/0x3ac)
> > > [   27.176156] [<c02c63dc>] (ubi_io_read_vid_hdr) from
> > > [<c02cce58>] (ubi_attach+0x4e0/0x1868) [   27.184675]
> > > [<c02cce58>] (ubi_attach) from [<c02be7c4>]
> > > (ubi_attach_mtd_dev+0x548/0xe58) [   27.193010] [<c02be7c4>]
> > > (ubi_attach_mtd_dev) from [<c05526e4>] (ubi_init+0x134/0x1d4)
> > > [   27.201159] [<c05526e4>] (ubi_init) from [<c00099f8>]
> > > (do_one_initcall+0x3c/0x17c) [   27.208839] [<c00099f8>]
> > > (do_one_initcall) from [<c053fd80>]
> > > (kernel_init_freeable+0x104/0x1c0) [   27.217755] [<c053fd80>]
> > > (kernel_init_freeable) from [<c0423ab8>] (kernel_init+0x8/0xf8)
> > > [   27.226074] [<c0423ab8>] (kernel_init) from [<c000a780>]
> > > (ret_from_fork+0x14/0x34)  
> > 
> > Looks like a mismatch in the ECC config. Can you check the ecc
> > strength/step_size in both situation (old driver vs new driver)?
> 
> For that, you might want to add traces in marvell_nand_ecc_init() and
> marvell_nand_hw_ecc_ctrl_init().
> 
> > Could you also dump the NDCR register in both cases?
> 
> NDCR register (as well as NDCBx registers) will appear if you let
> 
>     #define DEBUG
> 
> at the beginning of the driver.
> 
> Also, can you please give us the entire dmesg (I mean the boot, not
> the flow of UBIFS errors of course).
> 
> If this, in conjunction with your check of the ECC configuration, does
> not give satisfying results, I will write a test script using
> nandwrite/nanddump/flash_erase.

Something else:
Do you use platform data or device tree? Can you show where the board
information are?

I guess you tried to compile from the top of the branch, could you try
right after the addition of marvell_nand.c, bypassing the pdata/DT
changes.

Thanks,
Miquèl

> 
> Thank you,
> Miquèl
> 
> 
> > 
> > Thanks,
> > 
> > Boris
> 
> 
> 



-- 
Miquel Raynal, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2017-12-22 22:50 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-07 20:18 [PATCH 00/12] Marvell NAND controller rework with ->exec_op() Miquel Raynal
     [not found] ` <20171207201814.30411-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-07 20:18   ` [PATCH 01/12] dt-bindings: mtd: add Marvell NAND controller documentation Miquel Raynal
     [not found]     ` <20171207201814.30411-2-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-08 20:56       ` Boris Brezillon
2017-12-07 20:18   ` [PATCH 02/12] mtd: nand: add reworked Marvell NAND controller driver Miquel Raynal
     [not found]     ` <20171207201814.30411-3-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-11 16:27       ` Ezequiel Garcia
     [not found]         ` <CAAEAJfC89bRugBsK8jrK=6fdq76yzjThA74UCAhAaVuonLLNvg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-12-11 16:55           ` Miquel RAYNAL
2017-12-11 17:05             ` Boris Brezillon
2017-12-11 21:02               ` Miquel RAYNAL
2017-12-07 20:18   ` [PATCH 03/12] mtd: nand: replace pxa3xx_nand driver by its rework called marvell_nand Miquel Raynal
2017-12-07 20:18   ` [PATCH 04/12] dt-bindings: mtd: remove pxa3xx NAND controller documentation Miquel Raynal
2017-12-07 20:18   ` [PATCH 05/12] mtd: nand: remove useless fields from pxa3xx NAND platform data Miquel Raynal
2017-12-07 20:18   ` [PATCH 06/12] ARM: dts: armada-370-xp: use reworked NAND controller driver Miquel Raynal
2017-12-07 20:18   ` [PATCH 07/12] ARM: dts: armada-375: " Miquel Raynal
2017-12-07 20:18   ` [PATCH 08/12] ARM: dts: armada-38x: " Miquel Raynal
2017-12-07 20:18   ` [PATCH 09/12] ARM: dts: armada-39x: " Miquel Raynal
2017-12-07 20:18   ` [PATCH 10/12] ARM: dts: pxa: " Miquel Raynal
2017-12-07 20:18   ` [PATCH 11/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K Miquel Raynal
     [not found]     ` <20171207201814.30411-12-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-15 10:29       ` Gregory CLEMENT
     [not found]         ` <87374cmghe.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-15 10:44           ` Gregory CLEMENT
2017-12-07 20:18   ` [PATCH 12/12] ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K Miquel Raynal
     [not found]     ` <20171207201814.30411-13-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-15 10:29       ` Gregory CLEMENT
     [not found]         ` <87y3m4l1wi.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-12-15 10:44           ` Gregory CLEMENT
2017-12-09 23:27   ` [PATCH 00/12] Marvell NAND controller rework with ->exec_op() Ezequiel Garcia
2017-12-14  6:09   ` Boris Brezillon
2017-12-18  7:11     ` Robert Jarzmik
     [not found]       ` <877etkecig.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
2017-12-18  8:25         ` Miquel RAYNAL
2017-12-20 21:26           ` Robert Jarzmik
     [not found]             ` <87y3lxccr7.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
2017-12-20 21:41               ` Boris Brezillon
2017-12-22 20:11                 ` Robert Jarzmik
     [not found]                   ` <87lghucykr.fsf-4ty26DBLk+jEm7gnYqmdkQ@public.gmane.org>
2017-12-22 21:24                     ` Boris Brezillon
2017-12-22 22:37                       ` Miquel RAYNAL
2017-12-22 22:50                         ` Miquel RAYNAL

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).