linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808
@ 2020-01-24 16:29 Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings Johan Jonker
                   ` (10 more replies)
  0 siblings, 11 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

DISCLAIMER: Use at your own risk.
Status: For testing only!

Version: V2

Title: Enable RK3066 NANDC for MK808.

The majority of Rockchip devices use a closed source FTL driver
to reduce wear leveling. This patch serie proposes
an experimental raw NAND controller driver for basic tasks
in order to get the bindings and the nodes accepted for in the dts files.

What does it do:

On module load this driver will reserve its resources.
After initialization the MTD framework will then try to detect
the type and number of NAND chips. When all conditions are met,
it registers it self as MTD device.
This driver is then ready to receive user commands
such as to read and write NAND pages.

Test examples:

# dd if=/dev/mtd0 of=dd.bin bs=8192 count=4

# nanddump -a -l 32768 -f nanddump.bin /dev/mtd0

Not tested:

NANDC version 9.
NAND raw write.
RK3066 still has no support for Uboot.
Any write command would interfere with data structures made by the boot loader.

Etc.

Problems:

No bad block support. Most devices use a FTL bad block map with tags
that must be located on specific page locations which is outside
the scope of the raw MTD framework.

hynix_nand_init() add extra option NAND_BBM_LASTPAGE for H27UCG8T2ATR-BC.

No partition support. A FTL driver will store at random locations and
a linear user specific layout does not fit within
the generic character of this basic driver.

Driver assumes that IO pins are correctly set by the boot loader.

Fixed timing setting.

RK3228A/RK3228B compatibility version 701 unknown
RV1108 nand version unknown

Etc.

Todo:

MLC ?
ARM vs arm64 testing
move BCH strengths and array size to struct rk_nandc_data

Changes V2:
Include suggestions by Miquel Raynal
Include suggestions by Rob Herring

Kconfig:
  add supported Socs

rk3*.dtsi
  change compatible
  remove #address-cells and #size-cells;
  swap clock
  swap clock-names

rockchip,nand-controller.yaml
  add "rockchip,idb-res-blk-num" property
  add hash
  change compatible
  change doc name
  swap clock-names

rockchip-nand-controller.c
  add fls(8 * 1024) original intention
  add more struct rk_nandc_data types
  add rk_nandc_hw_ecc_setup_helper()
  add "rockchip,idb-res-blk-num" property
  add struct rk_nandc_cap
  add struct rk_nandc_reg_offset
  change copyright text
  change dev_err to dev_dbg in rk_nandc_probe()
  change driver name
  change of_rk_nandc_match compatible and data
  change rk_nandc_hw_syndrome_ecc_read_page() error message
  check return status rk_nandc_hw_syndrome_ecc_read_page()
  check return status rk_nandc_hw_syndrome_ecc_write_page()
  fix ./scripts/checkpatch.pl --strict issues
  fix arm64 compile (untested)
  fix rk_nandc_chip_init nand_scan
  move empty line above MODULE_LICENSE()
  move NAND_ECC_HW below NAND_ECC_HW_SYNDROME
  move vars from controller to chip structure
  relocate init_completion()
  remove nand_to_mtd in rk_nandc_attach_chip()
  remove page pointer write tag for bootrom
  rename all defines to RK_NANDC_*
  rename rk_nand_ctrl
  replace bank_base calculations by defines
  replace g_nandc_info[id]
  replace kmalloc by devm_kzalloc
  replace uint8_t by u8
  replace uint32_t bu u32
  replace writel by writel_relaxed
  replace RK_NANDC_NUM_BANKS by ctrl->cap->max_cs


Chris Zhong (1):
  ARM: dts: rockchip: add nandc node for rk3066a/rk3188

Dingqiang Lin (2):
  arm64: dts: rockchip: add nandc node for px30
  arm64: dts: rockchip: add nandc node for rk3308

Jianqun Xu (1):
  ARM: dts: rockchip: add nandc nodes for rk3288

Johan Jonker (2):
  dt-bindings: mtd: add rockchip nand controller bindings
  ARM: dts: rockchip: rk3066a-mk808: enable nandc node

Jon Lin (1):
  ARM: dts: rockchip: add nandc node for rv1108

Wenping Zhang (1):
  ARM: dts: rockchip: add nandc node for rk322x

Yifeng Zhao (1):
  mtd: rawnand: rockchip: Add NAND controller driver

Zhaoyifeng (1):
  arm64: dts: rockchip: add nandc node for rk3368

 .../bindings/mtd/rockchip,nand-controller.yaml     |   92 ++
 arch/arm/boot/dts/rk3066a-mk808.dts                |   11 +
 arch/arm/boot/dts/rk322x.dtsi                      |    9 +
 arch/arm/boot/dts/rk3288.dtsi                      |   20 +
 arch/arm/boot/dts/rk3xxx.dtsi                      |    9 +
 arch/arm/boot/dts/rv1108.dtsi                      |    9 +
 arch/arm64/boot/dts/rockchip/px30.dtsi             |   12 +
 arch/arm64/boot/dts/rockchip/rk3308.dtsi           |    9 +
 arch/arm64/boot/dts/rockchip/rk3368.dtsi           |    9 +
 drivers/mtd/nand/raw/Kconfig                       |    9 +
 drivers/mtd/nand/raw/Makefile                      |    1 +
 drivers/mtd/nand/raw/rockchip-nand-controller.c    | 1307 ++++++++++++++++++++
 12 files changed, 1497 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
 create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c

--
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-02-03 15:45   ` Rob Herring
  2020-01-24 16:29 ` [RFC PATCH v2 02/10] mtd: rawnand: rockchip: Add NAND controller driver Johan Jonker
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

Add the Rockchip NAND controller bindings.

Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 .../bindings/mtd/rockchip,nand-controller.yaml     | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml

diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
new file mode 100644
index 000000000..5c725f972
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip NAND Controller Device Tree Bindings
+
+allOf:
+  - $ref: "nand-controller.yaml#"
+
+maintainers:
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,px30-nand-controller
+      - rockchip,rk3066-nand-controller
+      - rockchip,rk3228-nand-controller
+      - rockchip,rk3288-nand-controller
+      - rockchip,rk3308-nand-controller
+      - rockchip,rk3368-nand-controller
+      - rockchip,rv1108-nand-controller
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    minItems: 1
+    items:
+      - const: hclk_nandc
+      - const: clk_nandc
+
+patternProperties:
+  "^nand@[a-f0-9]+$":
+    type: object
+    properties:
+      reg:
+        minimum: 0
+        maximum: 3
+
+      nand-is-boot-medium: true
+
+      rockchip,idb-res-blk-num:
+        minimum: 2
+        default: 16
+        allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          For legacy devices where the bootrom can only handle 24 bit BCH/ECC.
+          If specified it indicates the number of erase blocks in use by
+          the bootloader that need a lower BCH/ECC setting.
+          Only used in combination with 'nand-is-boot-medium'.
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    #include <dt-bindings/clock/rk3188-cru-common.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    nandc: nand-controller@10500000 {
+      compatible = "rockchip,rk3066-nand-controller";
+      reg = <0x10500000 0x4000>;
+      interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&cru HCLK_NANDC0>;
+      clock-names = "hclk_nandc";
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      nand@0 {
+        reg = <0>;
+        nand-is-boot-medium;
+      };
+    };
+
+...
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 02/10] mtd: rawnand: rockchip: Add NAND controller driver
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 03/10] ARM: dts: rockchip: add nandc node for rk3066a/rk3188 Johan Jonker
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Yifeng Zhao <zyf@rock-chips.com>

Add basic Rockchip NAND controller driver.

Compatible with hardware version 6 and 9.
V6:16, 24, 40, 60 per 1024B BCH/ECC.
V9:16, 40, 60, 70 per 1024B BCH/ECC.
8 bit asynchronous flash interface support.
Supports up to 2 identical nandc nodes.
Max 4 nand chips per controller.
Able to select a different hardware ecc setup
for the loader blocks.
No bad block support.

Signed-off-by: Yifeng Zhao <zyf@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 drivers/mtd/nand/raw/Kconfig                    |    9 +
 drivers/mtd/nand/raw/Makefile                   |    1 +
 drivers/mtd/nand/raw/rockchip-nand-controller.c | 1307 +++++++++++++++++++++++
 3 files changed, 1317 insertions(+)
 create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c

diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 74fb91ade..acee3d6ee 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -457,6 +457,15 @@ config MTD_NAND_CADENCE
 	  Enable the driver for NAND flash on platforms using a Cadence NAND
 	  controller.
 
+config MTD_NAND_ROCKCHIP
+	tristate "Rockchip raw NAND controller driver"
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  Enables support for the Rockchip raw NAND controller driver.
+	  This controller is found on:
+	  px30, rk3066, rk3188, rk3228, rk3288, rk3308, rk3368, rv1108 SoCs.
+
 comment "Misc"
 
 config MTD_SM_COMMON
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index 2d136b158..a54aa85f4 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_TEGRA)		+= tegra_nand.o
 obj-$(CONFIG_MTD_NAND_STM32_FMC2)	+= stm32_fmc2_nand.o
 obj-$(CONFIG_MTD_NAND_MESON)		+= meson_nand.o
 obj-$(CONFIG_MTD_NAND_CADENCE)		+= cadence-nand-controller.o
+obj-$(CONFIG_MTD_NAND_ROCKCHIP)		+= rockchip-nand-controller.o
 
 nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
 nand-objs += nand_onfi.o
diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c
new file mode 100644
index 000000000..76ed1c08d
--- /dev/null
+++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c
@@ -0,0 +1,1307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Based on:
+ * https://github.com/rockchip-linux/kernel
+ *
+ * Copyright (c) 2016-2019 Yifeng Zhao yifeng.zhao@rock-chips.com
+ *
+ * Support NAND controller versions 6 and 9 found on SoCs:
+ * px30, rk3066, rk3188, rk3228, rk3288, rk3308, rk3368, rv1108
+ *
+ * Copyright (c) 2020 Johan Jonker jbx6244@gmail.com
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/rawnand.h>
+
+#define RK_NANDC_ID_V600		0x56363030
+#define RK_NANDC_ID_V622		0x56363232
+#define RK_NANDC_ID_V701		0x701
+#define RK_NANDC_ID_V800		0x56383030
+#define RK_NANDC_ID_V801		0x801
+#define RK_NANDC_ID_V900		0x56393030
+
+#define RK_NANDC_IDB_Res_Blk_Num	16
+#define RK_NANDC_IDB_Ecc_Bits		24
+
+#define RK_NANDC_V6_ECC_16		0x00000000
+#define RK_NANDC_V6_ECC_24		0x00000010
+#define RK_NANDC_V6_ECC_40		0x00040000
+#define RK_NANDC_V6_ECC_60		0x00040010
+
+#define RK_NANDC_V9_ECC_16		0x02000001
+#define RK_NANDC_V9_ECC_40		0x04000001
+#define RK_NANDC_V9_ECC_60		0x06000001
+#define RK_NANDC_V9_ECC_70		0x00000001
+
+#define RK_NANDC_NUM_BANKS		8
+#define RK_NANDC_DEF_TIMEOUT		10000
+
+#define RK_NANDC_REG_DATA		0x00
+#define RK_NANDC_REG_ADDR		0x04
+#define RK_NANDC_REG_CMD		0x08
+
+/* register offset nandc version 6 */
+#define RK_NANDC_REG_V6_FMCTL		0x00
+#define RK_NANDC_REG_V6_FMWAIT		0x04
+#define RK_NANDC_REG_V6_FLCTL		0x08
+#define RK_NANDC_REG_V6_BCHCTL		0x0c
+#define RK_NANDC_REG_V6_DMA_CFG		0x10
+#define RK_NANDC_REG_V6_DMA_BUF0	0x14
+#define RK_NANDC_REG_V6_DMA_BUF1	0x18
+#define RK_NANDC_REG_V6_DMA_ST		0x1C
+#define RK_NANDC_REG_V6_BCHST		0x20
+#define RK_NANDC_REG_V6_RANDMZ		0x150
+#define RK_NANDC_REG_V6_VER		0x160
+#define RK_NANDC_REG_V6_INTEN		0x16C
+#define RK_NANDC_REG_V6_INTCLR		0x170
+#define RK_NANDC_REG_V6_INTST		0x174
+#define RK_NANDC_REG_V6_SPARE0		0x200
+#define RK_NANDC_REG_V6_SPARE1		0x230
+
+/* register offset nandc version 9 */
+#define RK_NANDC_REG_V9_FMCTL		0x00
+#define RK_NANDC_REG_V9_FMWAIT		0x04
+#define RK_NANDC_REG_V9_FLCTL		0x10
+#define RK_NANDC_REG_V9_BCHCTL		0x20
+#define RK_NANDC_REG_V9_DMA_CFG		0x30
+#define RK_NANDC_REG_V9_DMA_BUF0	0x34
+#define RK_NANDC_REG_V9_DMA_BUF1	0x38
+#define RK_NANDC_REG_V9_DMA_ST		0x40
+#define RK_NANDC_REG_V9_VER		0x80
+#define RK_NANDC_REG_V9_INTEN		0x120
+#define RK_NANDC_REG_V9_INTCLR		0x124
+#define RK_NANDC_REG_V9_INTST		0x128
+#define RK_NANDC_REG_V9_BCHST		0x150
+#define RK_NANDC_REG_V9_SPARE0		0x200
+#define RK_NANDC_REG_V9_SPARE1		0x204
+#define RK_NANDC_REG_V9_RANDMZ		0x208
+
+/* register offset nandc common */
+#define RK_NANDC_REG_BANK0		0x800
+#define RK_NANDC_REG_SRAM0		0x1000
+
+/* calculate bank_base */
+#define RK_NANDC_BANK_SIZE		0x100
+
+#define RK_REG(ctrl, off) \
+	((ctrl)->regs + \
+	RK_NANDC_REG_BANK0 + \
+	(ctrl)->selected_bank * RK_NANDC_BANK_SIZE + \
+	(off))
+
+#define RK_REG_DATA(ctrl) RK_REG(ctrl, RK_NANDC_REG_DATA)
+#define RK_REG_ADDR(ctrl) RK_REG(ctrl, RK_NANDC_REG_ADDR)
+#define RK_REG_CMD(ctrl)  RK_REG(ctrl, RK_NANDC_REG_CMD)
+
+/* FMCTL */
+#define RK_NANDC_V6_FM_WP		BIT(8)
+#define RK_NANDC_V6_FM_CE_SEL_M		0xFF
+#define RK_NANDC_V6_FM_CE_SEL(x)	(1 << (x))
+#define RK_NANDC_V6_FM_FREADY		BIT(9)
+
+#define RK_NANDC_V9_FM_WP		BIT(8)
+#define RK_NANDC_V9_FM_CE_SEL_M		0xFF
+#define RK_NANDC_V9_FM_CE_SEL(x)	(1 << (x))
+#define RK_NANDC_V9_RDY			BIT(9)
+
+/* FLCTL */
+#define RK_NANDC_V6_FL_RST		BIT(0)
+#define RK_NANDC_V6_FL_DIR(x)		((x) ? BIT(1) : 0)
+#define RK_NANDC_V6_FL_XFER_START	BIT(2)
+#define RK_NANDC_V6_FL_XFER_EN		BIT(3)
+#define RK_NANDC_V6_FL_ST_BUF_S		0x4
+#define RK_NANDC_V6_FL_XFER_COUNT	BIT(5)
+#define RK_NANDC_V6_FL_ACORRECT		BIT(10)
+#define RK_NANDC_V6_FL_XFER_READY	BIT(20)
+#define RK_NANDC_V6_FL_PAGE_NUM(x)	((x) << 22)
+#define RK_NANDC_V6_FL_ASYNC_TOG_MIX	BIT(29)
+
+#define RK_NANDC_V9_FL_RST		BIT(0)
+#define RK_NANDC_V9_FL_DIR(x)		((x) ? BIT(1) : 0)
+#define RK_NANDC_V9_FL_XFER_START	BIT(2)
+#define RK_NANDC_V9_FL_XFER_EN		BIT(3)
+#define RK_NANDC_V9_FL_ST_BUF_S		0x4
+#define RK_NANDC_V9_FL_XFER_COUNT	BIT(5)
+#define RK_NANDC_V9_FL_ACORRECT		BIT(10)
+#define RK_NANDC_V9_FL_XFER_READY	BIT(20)
+#define RK_NANDC_V9_FL_PAGE_NUM(x)	((x) << 22)
+#define RK_NANDC_V9_FL_ASYNC_TOG_MIX	BIT(29)
+
+/* BCHCTL */
+#define RK_NANDC_V6_BCH_REGION_S	0x5
+#define RK_NANDC_V6_BCH_REGION_M	0x7
+
+#define RK_NANDC_V9_BCH_MODE_S		25
+#define RK_NANDC_V9_BCH_MODE_M		0x7
+
+/* BCHST */
+#define RK_NANDC_V6_BCH0_ST_ERR		BIT(2)
+#define RK_NANDC_V6_BCH1_ST_ERR		BIT(15)
+#define RK_NANDC_V6_ECC_ERR_CNT0(x)	(((((x) & (0x1F << 3)) >> 3) \
+					| (((x) & (1 << 27)) >> 22)) & 0x3F)
+#define RK_NANDC_V6_ECC_ERR_CNT1(x)	(((((x) & (0x1F << 16)) >> 16) \
+					| (((x) & (1 << 29)) >> 24)) & 0x3F)
+
+#define RK_NANDC_V9_BCH0_ST_ERR		BIT(2)
+#define RK_NANDC_V9_BCH1_ST_ERR		BIT(18)
+#define RK_NANDC_V9_ECC_ERR_CNT0(x)	(((x) & (0x7F << 3)) >> 3)
+#define RK_NANDC_V9_ECC_ERR_CNT1(x)	(((x) & (0x7F << 19)) >> 19)
+
+/* DMA_CFG */
+#define RK_NANDC_V6_DMA_CFG_WR_ST	BIT(0)
+#define RK_NANDC_V6_DMA_CFG_WR(x)	(!(x) ? BIT(1) : 0)
+#define RK_NANDC_V6_DMA_CFG_BUS_MODE	BIT(2)
+
+#define RK_NANDC_V6_DMA_CFG_HSIZE_8	0
+#define RK_NANDC_V6_DMA_CFG_HSIZE_16	BIT(3)
+#define RK_NANDC_V6_DMA_CFG_HSIZE_32	(2 << 3)
+
+#define RK_NANDC_V6_DMA_CFG_BURST_1	0
+#define RK_NANDC_V6_DMA_CFG_BURST_4	(3 << 6)
+#define RK_NANDC_V6_DMA_CFG_BURST_8	(5 << 6)
+#define RK_NANDC_V6_DMA_CFG_BURST_16	(7 << 6)
+
+#define RK_NANDC_V6_DMA_CFG_INCR_NUM(x)	((x) << 9)
+
+#define RK_NANDC_V9_DMA_CFG_WR_ST	BIT(0)
+#define RK_NANDC_V9_DMA_CFG_WR(x)	(!(x) ? BIT(1) : 0)
+#define RK_NANDC_V9_DMA_CFG_BUS_MODE	BIT(2)
+
+#define RK_NANDC_V9_DMA_CFG_HSIZE_8	0
+#define RK_NANDC_V9_DMA_CFG_HSIZE_16	BIT(3)
+#define RK_NANDC_V9_DMA_CFG_HSIZE_32	(2 << 3)
+
+#define RK_NANDC_V9_DMA_CFG_BURST_1	0
+#define RK_NANDC_V9_DMA_CFG_BURST_4	(3 << 6)
+#define RK_NANDC_V9_DMA_CFG_BURST_8	(5 << 6)
+#define RK_NANDC_V9_DMA_CFG_BURST_16	(7 << 6)
+
+#define RK_NANDC_V9_DMA_CFG_INCR_NUM(x)	((x) << 9)
+
+/* INTEN */
+#define RK_NANDC_V6_INT_DMA		BIT(0)
+
+#define RK_NANDC_V9_INT_DMA		BIT(0)
+
+/*
+ * The bit positions for
+ * RK_NANDC_REG_V6_FMCTL and RK_NANDC_REG_V9_FMCTL,
+ * RK_NANDC_REG_V6_FLCTL and RK_NANDC_REG_V9_FLCTL,
+ * RK_NANDC_REG_V6_DMA_CFG and RK_NANDC_REG_V9_DMA_CFG
+ * are identical.
+ */
+
+enum rk_nandc_version {
+	VERSION_6 = 6,
+	VERSION_9 = 9,
+};
+
+struct rk_nandc_reg_offset {
+	u32 fmctl;
+	u32 fmwait;
+	u32 flctl;
+	u32 bchctl;
+	u32 dma_cfg;
+	u32 dma_buf0;
+	u32 dma_buf1;
+	u32 dma_st;
+	u32 bchst;
+	u32 randmz;
+	u32 ver;
+	u32 inten;
+	u32 intclr;
+	u32 intst;
+	u32 spare0;
+	u32 spare1;
+};
+
+static const struct rk_nandc_reg_offset rk_nandc_V6_reg_offset = {
+	.fmctl =    RK_NANDC_REG_V6_FMCTL,
+	.fmwait =   RK_NANDC_REG_V6_FMWAIT,
+	.flctl =    RK_NANDC_REG_V6_FLCTL,
+	.bchctl =   RK_NANDC_REG_V6_BCHCTL,
+	.dma_cfg =  RK_NANDC_REG_V6_DMA_CFG,
+	.dma_buf0 = RK_NANDC_REG_V6_DMA_BUF0,
+	.dma_buf1 = RK_NANDC_REG_V6_DMA_BUF1,
+	.dma_st =   RK_NANDC_REG_V6_DMA_ST,
+	.bchst =    RK_NANDC_REG_V6_BCHST,
+	.randmz =   RK_NANDC_REG_V6_RANDMZ,
+	.ver =      RK_NANDC_REG_V6_VER,
+	.inten =    RK_NANDC_REG_V6_INTEN,
+	.intclr =   RK_NANDC_REG_V6_INTCLR,
+	.intst =    RK_NANDC_REG_V6_INTST,
+	.spare0 =   RK_NANDC_REG_V6_SPARE0,
+	.spare1 =   RK_NANDC_REG_V6_SPARE1,
+};
+
+static const struct rk_nandc_reg_offset rk_nandc_V9_reg_offset = {
+	.fmctl =    RK_NANDC_REG_V9_FMCTL,
+	.fmwait =   RK_NANDC_REG_V9_FMWAIT,
+	.flctl =    RK_NANDC_REG_V9_FLCTL,
+	.bchctl =   RK_NANDC_REG_V9_BCHCTL,
+	.dma_cfg =  RK_NANDC_REG_V9_DMA_CFG,
+	.dma_buf0 = RK_NANDC_REG_V9_DMA_BUF0,
+	.dma_buf1 = RK_NANDC_REG_V9_DMA_BUF1,
+	.dma_st =   RK_NANDC_REG_V9_DMA_ST,
+	.bchst =    RK_NANDC_REG_V9_BCHST,
+	.randmz =   RK_NANDC_REG_V9_RANDMZ,
+	.ver =      RK_NANDC_REG_V9_VER,
+	.inten =    RK_NANDC_REG_V9_INTEN,
+	.intclr =   RK_NANDC_REG_V9_INTCLR,
+	.intst =    RK_NANDC_REG_V9_INTST,
+	.spare0 =   RK_NANDC_REG_V9_SPARE0,
+	.spare1 =   RK_NANDC_REG_V9_SPARE1,
+};
+
+struct rk_nandc_cap {
+	u8 max_cs;
+};
+
+static const struct rk_nandc_cap rk_nandc_V600_cap = {
+	.max_cs = 8,
+};
+
+static const struct rk_nandc_cap rk_nandc_V622_cap = {
+	.max_cs = 4,
+};
+
+static const struct rk_nandc_cap rk_nandc_V701_cap = {
+	.max_cs = 4,
+};
+
+static const struct rk_nandc_cap rk_nandc_V801_cap = {
+	.max_cs = 4,
+};
+
+static const struct rk_nandc_cap rk_nandc_V900_cap = {
+	.max_cs = 4,
+};
+
+struct rk_nandc_data {
+	enum rk_nandc_version version;
+	struct rk_nandc_reg_offset *ofs;
+	struct rk_nandc_cap *cap;
+};
+
+struct rk_nand_ctrl {
+	struct device *dev;
+	void __iomem *regs;
+	int irq;
+	struct clk *hclk;
+	struct clk *clk;
+	struct list_head chips;
+	struct completion complete;
+	struct nand_controller controller;
+	int cs[RK_NANDC_NUM_BANKS];
+	u32 *oob_buf;
+	u32 *page_buf;
+	int selected_bank;
+	unsigned long assigned_cs;
+	enum rk_nandc_version version;
+	struct rk_nandc_reg_offset *ofs;
+	struct rk_nandc_cap *cap;
+};
+
+struct rk_nand_chip {
+	struct nand_chip nand;
+	struct list_head node;
+	bool bootromblocks;
+	int ecc_mode;
+	int max_ecc_strength;
+	int idbresblknum;
+};
+
+static struct rk_nand_chip *to_rk_nand(struct nand_chip *nand)
+{
+	return container_of(nand, struct rk_nand_chip, nand);
+}
+
+static void rk_nandc_init(struct rk_nand_ctrl *ctrl)
+{
+	writel_relaxed(0, ctrl->regs + ctrl->ofs->randmz);
+	writel_relaxed(0, ctrl->regs + ctrl->ofs->dma_cfg);
+	writel_relaxed(RK_NANDC_V6_FM_WP, ctrl->regs + ctrl->ofs->fmctl);
+	writel_relaxed(RK_NANDC_V6_FL_RST, ctrl->regs + ctrl->ofs->flctl);
+	writel_relaxed(0x1081, ctrl->regs + ctrl->ofs->fmwait);
+}
+
+static irqreturn_t rk_nandc_interrupt(int irq, void *dev_id)
+{
+	struct rk_nand_ctrl *ctrl = dev_id;
+
+	u32 st = readl(ctrl->regs + ctrl->ofs->intst);
+	u32 ien = readl(ctrl->regs + ctrl->ofs->inten);
+
+	if (!(ien & st))
+		return IRQ_NONE;
+
+	if ((ien & st) == ien)
+		complete(&ctrl->complete);
+
+	writel_relaxed(st, ctrl->regs + ctrl->ofs->intclr);
+	writel_relaxed(~st & ien, ctrl->regs + ctrl->ofs->inten);
+
+	return IRQ_HANDLED;
+}
+
+static void rk_nandc_select_chip(struct nand_chip *nand, int chipnr)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	u32 reg;
+	int banknr;
+
+	reg = readl(ctrl->regs + ctrl->ofs->fmctl);
+	reg &= ~RK_NANDC_V6_FM_CE_SEL_M;
+
+	if (chipnr == -1) {
+		banknr = -1;
+	} else {
+		banknr = ctrl->cs[chipnr];
+
+		reg |= RK_NANDC_V6_FM_CE_SEL(banknr);
+	}
+
+	ctrl->selected_bank = banknr;
+
+	writel_relaxed(reg, ctrl->regs + ctrl->ofs->fmctl);
+}
+
+static int rk_nandc_hw_ecc_setup(struct nand_chip *nand,
+				 u32 strength)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	u32 reg;
+
+	nand->ecc.strength = strength;
+	/* HW ECC always request ECC bytes for 1024 bytes blocks */
+	nand->ecc.bytes = DIV_ROUND_UP(nand->ecc.strength * fls(8 * 1024), 8);
+	/* HW ECC only works with an even number of ECC bytes */
+	nand->ecc.bytes = ALIGN(nand->ecc.bytes, 2);
+
+	if (ctrl->version == VERSION_9) {
+		switch (nand->ecc.strength) {
+		case 70:
+			reg = RK_NANDC_V9_ECC_70;
+			break;
+		case 60:
+			reg = RK_NANDC_V9_ECC_60;
+			break;
+		case 40:
+			reg = RK_NANDC_V9_ECC_40;
+			break;
+		case 16:
+			reg = RK_NANDC_V9_ECC_16;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (nand->ecc.strength) {
+		case 60:
+			reg = RK_NANDC_V6_ECC_60;
+			break;
+		case 40:
+			reg = RK_NANDC_V6_ECC_40;
+			break;
+		case 24:
+			reg = RK_NANDC_V6_ECC_24;
+			break;
+		case 16:
+			reg = RK_NANDC_V6_ECC_16;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	writel_relaxed(reg, ctrl->regs + ctrl->ofs->bchctl);
+
+	return 0;
+}
+
+static void rk_nandc_xfer_start(struct rk_nand_ctrl *ctrl,
+				u8 dir, u8 n_KB,
+				dma_addr_t dma_data,
+				dma_addr_t dma_oob)
+{
+	u32 reg;
+
+	if (ctrl->version == VERSION_6) {
+		reg = readl(ctrl->regs + ctrl->ofs->bchctl);
+		reg = (reg & (~(RK_NANDC_V6_BCH_REGION_M <<
+				RK_NANDC_V6_BCH_REGION_S))) |
+		      (ctrl->selected_bank << RK_NANDC_V6_BCH_REGION_S);
+		writel_relaxed(reg, ctrl->regs + ctrl->ofs->bchctl);
+	}
+
+	reg = RK_NANDC_V6_DMA_CFG_WR_ST |
+	      RK_NANDC_V6_DMA_CFG_WR(dir) |
+	      RK_NANDC_V6_DMA_CFG_BUS_MODE |
+	      RK_NANDC_V6_DMA_CFG_HSIZE_32 |
+	      RK_NANDC_V6_DMA_CFG_BURST_16 |
+	      RK_NANDC_V6_DMA_CFG_INCR_NUM(16);
+	writel_relaxed(reg, ctrl->regs + ctrl->ofs->dma_cfg);
+	writel_relaxed((u32)dma_data, ctrl->regs + ctrl->ofs->dma_buf0);
+	writel_relaxed((u32)dma_oob, ctrl->regs + ctrl->ofs->dma_buf1);
+
+	reg = RK_NANDC_V6_FL_DIR(dir) |
+	      RK_NANDC_V6_FL_XFER_EN |
+	      RK_NANDC_V6_FL_XFER_COUNT |
+	      RK_NANDC_V6_FL_ACORRECT |
+	      RK_NANDC_V6_FL_PAGE_NUM(n_KB) |
+	      RK_NANDC_V6_FL_ASYNC_TOG_MIX;
+	writel_relaxed(reg, ctrl->regs + ctrl->ofs->flctl);
+	reg |= RK_NANDC_V6_FL_XFER_START;
+	writel_relaxed(reg, ctrl->regs + ctrl->ofs->flctl);
+}
+
+static int rk_nandc_wait_for_xfer_done(struct rk_nand_ctrl *ctrl)
+{
+	u32 reg;
+	int ret;
+
+	void __iomem *ptr = ctrl->regs + ctrl->ofs->flctl;
+
+	ret = readl_poll_timeout_atomic(ptr, reg,
+					reg & RK_NANDC_V6_FL_XFER_READY,
+					1, RK_NANDC_DEF_TIMEOUT);
+
+	return ret;
+}
+
+static void rk_nandc_hw_ecc_setup_helper(struct nand_chip *nand,
+					 int page, bool entry)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	struct rk_nand_chip *rk_nand = to_rk_nand(nand);
+
+	int pages_per_blk = mtd->erasesize / mtd->writesize;
+
+	/* only bank 0 used for boot rom blocks */
+	if ((page < pages_per_blk * rk_nand->idbresblknum) &&
+	    rk_nand->bootromblocks &&
+	    !ctrl->selected_bank &&
+	    entry)
+		rk_nandc_hw_ecc_setup(nand, RK_NANDC_IDB_Ecc_Bits);
+	else
+		rk_nandc_hw_ecc_setup(nand, rk_nand->ecc_mode);
+}
+
+static int rk_nandc_hw_syndrome_ecc_read_page(struct nand_chip *nand,
+					      u8 *buf,
+					      int oob_required,
+					      int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	int max_bitflips = 0;
+	dma_addr_t dma_data, dma_oob;
+	int ret, i;
+	int bch_st;
+	int dma_oob_size = ecc->steps * 128;
+
+	rk_nandc_select_chip(nand, ctrl->selected_bank);
+
+	rk_nandc_hw_ecc_setup_helper(nand, page, true);
+
+	nand_read_page_op(nand, page, 0, NULL, 0);
+
+	dma_data = dma_map_single(ctrl->dev, ctrl->page_buf, mtd->writesize,
+				  DMA_FROM_DEVICE);
+	dma_oob = dma_map_single(ctrl->dev, ctrl->oob_buf, dma_oob_size,
+				 DMA_FROM_DEVICE);
+
+	reinit_completion(&ctrl->complete);
+	writel_relaxed(RK_NANDC_V6_INT_DMA, ctrl->regs + ctrl->ofs->inten);
+	rk_nandc_xfer_start(ctrl, 0, ecc->steps, dma_data, dma_oob);
+
+	ret = wait_for_completion_timeout(&ctrl->complete, msecs_to_jiffies(5));
+
+	if (!ret) {
+		dev_err(ctrl->dev, "wait_for_completion_timeout\n");
+		ret = -ETIMEDOUT;
+		goto unmap_dma;
+	}
+
+	ret = rk_nandc_wait_for_xfer_done(ctrl);
+
+	if (ret) {
+		dev_err(ctrl->dev, "rk_nandc_wait_for_xfer_done\n");
+		ret = -ETIMEDOUT;
+	}
+
+unmap_dma:
+	dma_unmap_single(ctrl->dev, dma_data, mtd->writesize, DMA_FROM_DEVICE);
+	dma_unmap_single(ctrl->dev, dma_oob, dma_oob_size, DMA_FROM_DEVICE);
+
+	if (ret)
+		goto ecc_setup;
+
+	memcpy(buf, ctrl->page_buf, mtd->writesize);
+
+	if (oob_required) {
+		u8 *oob;
+		u32 tmp;
+
+		for (i = 0; i < ecc->steps; i++) {
+			oob = nand->oob_poi +
+			      i * (ecc->bytes + nand->ecc.prepad);
+			if (ctrl->version == VERSION_9) {
+				tmp = ctrl->oob_buf[i];
+			} else {
+				u8 oob_step = (to_rk_nand(nand)->ecc_mode <= 24)
+					      ? 64 : 128;
+				tmp = ctrl->oob_buf[i * oob_step / 4];
+			}
+			*oob++ = (u8)tmp;
+			*oob++ = (u8)(tmp >> 8);
+			*oob++ = (u8)(tmp >> 16);
+			*oob++ = (u8)(tmp >> 24);
+		}
+	}
+
+	if (ctrl->version == VERSION_9) {
+		for (i = 0; i < ecc->steps / 2; i++) {
+			bch_st = readl(ctrl->regs +
+				       ctrl->ofs->bchst +
+				       i * 4);
+			if (bch_st & RK_NANDC_V9_BCH0_ST_ERR ||
+			    bch_st & RK_NANDC_V9_BCH1_ST_ERR) {
+				mtd->ecc_stats.failed++;
+				max_bitflips = -1;
+			} else {
+				ret = RK_NANDC_V9_ECC_ERR_CNT0(bch_st);
+				mtd->ecc_stats.corrected += ret;
+				max_bitflips = max_t(unsigned int,
+						     max_bitflips, ret);
+
+				ret = RK_NANDC_V9_ECC_ERR_CNT1(bch_st);
+				mtd->ecc_stats.corrected += ret;
+				max_bitflips = max_t(unsigned int,
+						     max_bitflips, ret);
+			}
+		}
+	} else {
+		for (i = 0; i < ecc->steps / 2; i++) {
+			bch_st = readl(ctrl->regs +
+				       ctrl->ofs->bchst +
+				       i * 4);
+			if (bch_st & RK_NANDC_V6_BCH0_ST_ERR ||
+			    bch_st & RK_NANDC_V6_BCH1_ST_ERR) {
+				mtd->ecc_stats.failed++;
+				max_bitflips = -1;
+			} else {
+				ret = RK_NANDC_V6_ECC_ERR_CNT0(bch_st);
+				mtd->ecc_stats.corrected += ret;
+				max_bitflips = max_t(unsigned int,
+						     max_bitflips, ret);
+
+				ret = RK_NANDC_V6_ECC_ERR_CNT1(bch_st);
+				mtd->ecc_stats.corrected += ret;
+				max_bitflips = max_t(unsigned int,
+						     max_bitflips, ret);
+			}
+		}
+	}
+
+	ret = max_bitflips;
+	if (max_bitflips == -1) {
+		dev_err(ctrl->dev, "BCH status error\n");
+		ret = -ENODATA;
+	}
+
+ecc_setup:
+	rk_nandc_hw_ecc_setup_helper(nand, page, false);
+
+	return ret;
+}
+
+static int rk_nandc_hw_syndrome_ecc_write_page(struct nand_chip *nand,
+					       const u8 *buf,
+					       int oob_required,
+					       int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	dma_addr_t dma_data, dma_oob;
+	int i, ret;
+	int dma_oob_size = ecc->steps * 128;
+
+	rk_nandc_select_chip(nand, ctrl->selected_bank);
+
+	rk_nandc_hw_ecc_setup_helper(nand, page, true);
+
+	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+
+	for (i = 0; i < ecc->steps; i++) {
+		u32 tmp;
+
+		if (oob_required) {
+			u8 *oob;
+
+			oob = nand->oob_poi +
+			      i * (ecc->bytes + nand->ecc.prepad);
+			tmp = oob[0] |
+			      (oob[1] << 8) |
+			      (oob[2] << 16) |
+			      (oob[3] << 24);
+		} else {
+			tmp = 0xFFFFFFFF;
+		}
+		if (ctrl->version == VERSION_9) {
+			ctrl->oob_buf[i] = tmp;
+		} else {
+			u8 oob_step = (to_rk_nand(nand)->ecc_mode <= 24)
+				      ? 64 : 128;
+			ctrl->oob_buf[i * oob_step / 4] = tmp;
+		}
+	}
+
+	memcpy(ctrl->page_buf, buf, mtd->writesize);
+
+	dma_data = dma_map_single(ctrl->dev, ctrl->page_buf, mtd->writesize,
+				  DMA_TO_DEVICE);
+	dma_oob = dma_map_single(ctrl->dev, ctrl->oob_buf, dma_oob_size,
+				 DMA_TO_DEVICE);
+
+	reinit_completion(&ctrl->complete);
+	writel_relaxed(RK_NANDC_V6_INT_DMA, ctrl->regs + ctrl->ofs->inten);
+	rk_nandc_xfer_start(ctrl, 1, ecc->steps, dma_data, dma_oob);
+
+	ret = wait_for_completion_timeout(&ctrl->complete,
+					  msecs_to_jiffies(10));
+
+	if (!ret) {
+		dev_err(ctrl->dev, "wait_for_completion_timeout\n");
+		ret = -ETIMEDOUT;
+		goto unmap_dma;
+	}
+
+	ret = rk_nandc_wait_for_xfer_done(ctrl);
+
+	if (ret) {
+		dev_err(ctrl->dev, "rk_nandc_wait_for_xfer_done\n");
+		ret = -ETIMEDOUT;
+	}
+
+unmap_dma:
+	dma_unmap_single(ctrl->dev, dma_data, mtd->writesize, DMA_TO_DEVICE);
+	dma_unmap_single(ctrl->dev, dma_oob, dma_oob_size, DMA_TO_DEVICE);
+
+	rk_nandc_hw_ecc_setup_helper(nand, page, false);
+
+	if (!ret)
+		ret = nand_prog_page_end_op(nand);
+
+	return ret;
+}
+
+static int rk_nandc_hw_ecc_read_oob(struct nand_chip *nand, int page)
+{
+	u8 *buf = nand_get_data_buf(nand);
+
+	return nand->ecc.read_page(nand, buf, true, page);
+}
+
+static int rk_nandc_hw_ecc_write_oob(struct nand_chip *nand, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	int ret;
+	u8 *buf = nand_get_data_buf(nand);
+
+	memset(buf, 0xFF, mtd->writesize);
+	ret = nand->ecc.write_page(nand, buf, true, page);
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(nand);
+}
+
+static void rk_nandc_read_buf(struct nand_chip *nand, u8 *buf, int len)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	int offs = 0;
+	void __iomem *bank_base = RK_REG_DATA(ctrl);
+
+	for (offs = 0; offs < len; offs++)
+		buf[offs] = readb(bank_base);
+}
+
+static void rk_nandc_write_buf(struct nand_chip *nand, const u8 *buf, int len)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	int offs = 0;
+	void __iomem *bank_base = RK_REG_DATA(ctrl);
+
+	for (offs = 0; offs < len; offs++)
+		writeb(buf[offs], bank_base);
+}
+
+static void rk_nandc_write_cmd(struct nand_chip *nand, u8 cmd)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+
+	void __iomem *bank_base = RK_REG_CMD(ctrl);
+
+	writeb(cmd, bank_base);
+}
+
+static void rk_nandc_write_addr(struct nand_chip *nand, u8 addr)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+
+	void __iomem *bank_base = RK_REG_ADDR(ctrl);
+
+	writeb(addr, bank_base);
+}
+
+static int rk_nandc_dev_ready(struct nand_chip *nand)
+{
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+
+	if (readl(ctrl->regs + ctrl->ofs->fmctl) & RK_NANDC_V6_FM_FREADY)
+		return 1;
+
+	return 0;
+}
+
+static int rk_nandc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	if (section >= nand->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (nand->ecc.bytes + nand->ecc.prepad) * section +
+			    nand->ecc.prepad;
+	oobregion->length = nand->ecc.steps * nand->ecc.bytes;
+
+	return 0;
+}
+
+static int rk_nandc_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	if (section >= nand->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (nand->ecc.bytes + nand->ecc.prepad) * section;
+	oobregion->length = nand->ecc.steps * nand->ecc.prepad;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops rk_nandc_oob_ops = {
+	.ecc = rk_nandc_ooblayout_ecc,
+	.free = rk_nandc_ooblayout_free,
+};
+
+static int rk_nandc_buffer_init(struct nand_chip *nand)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+
+	ctrl->page_buf = devm_kzalloc(ctrl->dev,
+				      mtd->writesize,
+				      GFP_KERNEL | GFP_DMA);
+	if (!ctrl->page_buf)
+		return -ENOMEM;
+
+	ctrl->oob_buf = devm_kzalloc(ctrl->dev,
+				     nand->ecc.steps * 128,
+				     GFP_KERNEL | GFP_DMA);
+	if (!ctrl->oob_buf) {
+		devm_kfree(ctrl->dev, ctrl->page_buf);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int rk_nandc_hw_ecc_ctrl_init(struct nand_chip *nand)
+{
+	u8 strengths_v6[] = {60, 40, 24, 16};
+	u8 strengths_v9[] = {70, 60, 40, 16};
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct rk_nand_ctrl *ctrl = nand_get_controller_data(nand);
+	struct rk_nand_chip *rk_nand = to_rk_nand(nand);
+	int max_strength;
+	u32 i, ver;
+
+	if (nand->options & NAND_IS_BOOT_MEDIUM)
+		rk_nand->bootromblocks = true;
+	else
+		rk_nand->bootromblocks = false;
+
+	nand->ecc.prepad = 4;
+	nand->ecc.steps = mtd->writesize / nand->ecc.size;
+
+	max_strength = ((mtd->oobsize / nand->ecc.steps) - 4) * 8 / 14;
+	if (ctrl->version == VERSION_9) {
+		rk_nand->max_ecc_strength = 70;
+		ver = readl(ctrl->regs + RK_NANDC_REG_V9_VER);
+		if (ver != RK_NANDC_ID_V900)
+			dev_err(mtd->dev.parent,
+				"unsupported nandc version %x\n", ver);
+
+		if (max_strength > rk_nand->max_ecc_strength)
+			max_strength = rk_nand->max_ecc_strength;
+
+		for (i = 0; i < ARRAY_SIZE(strengths_v9); i++) {
+			if (max_strength >= strengths_v9[i])
+				break;
+		}
+
+		if (i >= ARRAY_SIZE(strengths_v9)) {
+			dev_err(mtd->dev.parent,
+				"unsupported strength\n");
+			return -ENOTSUPP;
+		}
+
+		rk_nand->ecc_mode = strengths_v9[i];
+	} else {
+		rk_nand->max_ecc_strength = 60;
+
+		ver = readl(ctrl->regs + RK_NANDC_REG_V6_VER);
+		if (ver == RK_NANDC_ID_V801)
+			rk_nand->max_ecc_strength = 16;
+		else if (ver == RK_NANDC_ID_V600 ||
+			 ver == RK_NANDC_ID_V622 ||
+			 ver == RK_NANDC_ID_V701 ||
+			 ver == RK_NANDC_ID_V800)
+			rk_nand->max_ecc_strength = 60;
+		else
+			dev_err(mtd->dev.parent,
+				"unsupported nandc version %x\n", ver);
+
+		if (max_strength > rk_nand->max_ecc_strength)
+			max_strength = rk_nand->max_ecc_strength;
+
+		for (i = 0; i < ARRAY_SIZE(strengths_v6); i++) {
+			if (max_strength >= strengths_v6[i])
+				break;
+		}
+
+		if (i >= ARRAY_SIZE(strengths_v6)) {
+			dev_err(mtd->dev.parent,
+				"unsupported strength\n");
+			return -ENOTSUPP;
+		}
+
+		rk_nand->ecc_mode = strengths_v6[i];
+	}
+	rk_nandc_hw_ecc_setup(nand, rk_nand->ecc_mode);
+
+	mtd_set_ooblayout(mtd, &rk_nandc_oob_ops);
+
+	if (mtd->oobsize < ((nand->ecc.bytes + nand->ecc.prepad) *
+			    nand->ecc.steps)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk_nandc_attach_chip(struct nand_chip *nand)
+{
+	int ret;
+
+	switch (nand->ecc.mode) {
+	case NAND_ECC_HW_SYNDROME:
+	case NAND_ECC_HW:
+		ret = rk_nandc_hw_ecc_ctrl_init(nand);
+		if (ret)
+			return ret;
+		ret = rk_nandc_buffer_init(nand);
+		if (ret)
+			return -ENOMEM;
+		nand->ecc.read_page = rk_nandc_hw_syndrome_ecc_read_page;
+		nand->ecc.write_page = rk_nandc_hw_syndrome_ecc_write_page;
+		nand->ecc.read_oob = rk_nandc_hw_ecc_read_oob;
+		nand->ecc.write_oob = rk_nandc_hw_ecc_write_oob;
+		break;
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk_nandc_exec_op(struct nand_chip *nand,
+			    const struct nand_operation *op,
+			    bool check_only)
+{
+	int i;
+	unsigned int op_id;
+	const struct nand_op_instr *instr = NULL;
+
+	rk_nandc_select_chip(nand, op->cs);
+
+	if (check_only)
+		return 0;
+
+	for (op_id = 0; op_id < op->ninstrs; op_id++) {
+		instr = &op->instrs[op_id];
+
+		switch (instr->type) {
+		case NAND_OP_CMD_INSTR:
+			rk_nandc_write_cmd(nand, instr->ctx.cmd.opcode);
+			break;
+		case NAND_OP_ADDR_INSTR:
+			for (i = 0; i < instr->ctx.addr.naddrs; i++)
+				rk_nandc_write_addr(nand,
+						    instr->ctx.addr.addrs[i]);
+			break;
+		case NAND_OP_DATA_IN_INSTR:
+			rk_nandc_read_buf(nand, instr->ctx.data.buf.in,
+					  instr->ctx.data.len);
+			break;
+		case NAND_OP_DATA_OUT_INSTR:
+			rk_nandc_write_buf(nand, instr->ctx.data.buf.out,
+					   instr->ctx.data.len);
+			break;
+		case NAND_OP_WAITRDY_INSTR:
+			rk_nandc_dev_ready(nand);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct nand_controller_ops rk_nand_controller_ops = {
+	.attach_chip = rk_nandc_attach_chip,
+	.exec_op = rk_nandc_exec_op,
+};
+
+static int rk_nandc_chip_init(struct rk_nand_ctrl *ctrl,
+			      struct device_node *np)
+{
+	struct rk_nand_chip *rk_nand;
+	struct nand_chip *nand;
+	struct mtd_info *mtd;
+	int nsels, ret, i;
+	u32 cs, val;
+
+	nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
+	if (nsels <= 0) {
+		dev_err(ctrl->dev, "missing/invalid reg property\n");
+		return -EINVAL;
+	}
+
+	rk_nand = devm_kzalloc(ctrl->dev, sizeof(*rk_nand), GFP_KERNEL);
+	if (!rk_nand)
+		return -ENOMEM;
+
+	rk_nand->idbresblknum = RK_NANDC_IDB_Res_Blk_Num;
+
+	for (i = 0; i < nsels; i++) {
+		ret = of_property_read_u32_index(np, "reg", i, &cs);
+		if (ret) {
+			dev_err(ctrl->dev,
+				"could not retrieve reg property: %d\n",
+				ret);
+			return ret;
+		}
+
+		if (cs >= ctrl->cap->max_cs) {
+			dev_err(ctrl->dev,
+				"invalid reg value: %u (max CS = %d)\n",
+				cs,
+				ctrl->cap->max_cs);
+			return -EINVAL;
+		}
+
+		if (test_and_set_bit(cs, &ctrl->assigned_cs)) {
+			dev_err(ctrl->dev,
+				"CS %d already assigned\n",
+				cs);
+			return -EINVAL;
+		}
+
+		ctrl->cs[i] = cs;
+
+		/* only bank 0 used for boot rom blocks */
+		if (!of_property_read_u32_index(np, "rockchip,idb-res-blk-num",
+						i, &val)) {
+			if (!cs && val >= 2) {
+				rk_nand->idbresblknum = val;
+			} else {
+				dev_err(ctrl->dev,
+					"invalid idb-res-blk-num\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	nand = &rk_nand->nand;
+
+	nand_set_flash_node(nand, np);
+	nand_set_controller_data(nand, ctrl);
+
+	nand->controller = &ctrl->controller;
+	nand->controller->ops = &rk_nand_controller_ops;
+
+	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
+	nand->ecc.size = 1024;
+	nand->ecc.strength = 40;
+
+	nand->options = NAND_SKIP_BBTSCAN | NAND_NO_SUBPAGE_WRITE;
+
+	mtd = nand_to_mtd(nand);
+	mtd->dev.parent = ctrl->dev;
+	mtd->name = devm_kasprintf(ctrl->dev, GFP_KERNEL, "%s",
+				   dev_name(ctrl->dev));
+
+	ret = nand_scan(nand, nsels);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(ctrl->dev, "mtd device register failed: %d\n", ret);
+		nand_cleanup(nand);
+		return ret;
+	}
+
+	list_add_tail(&rk_nand->node, &ctrl->chips);
+
+	return 0;
+}
+
+static void rk_nandc_cleanup_chips(struct rk_nand_ctrl *ctrl)
+{
+	struct rk_nand_chip *entry, *temp;
+
+	list_for_each_entry_safe(entry, temp, &ctrl->chips, node) {
+		nand_release(&entry->nand);
+		list_del(&entry->node);
+	}
+}
+
+static int rk_nandc_chips_init(struct rk_nand_ctrl *ctrl)
+{
+	struct device_node *np = ctrl->dev->of_node;
+	struct device_node *nand_np;
+	int nchips;
+	int ret;
+
+	nchips = of_get_child_count(np);
+
+	if (nchips > ctrl->cap->max_cs) {
+		dev_err(ctrl->dev, "too many NAND chips: %d (max CS = %d)\n",
+			nchips,
+			ctrl->cap->max_cs);
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(np, nand_np) {
+		ret = rk_nandc_chip_init(ctrl, nand_np);
+		if (ret) {
+			rk_nandc_cleanup_chips(ctrl);
+			of_node_put(nand_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rk_nandc_probe(struct platform_device *pdev)
+{
+	struct rk_nand_ctrl *ctrl;
+	const struct rk_nandc_data *data;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	data = of_device_get_match_data(dev);
+	if (!data)
+		return -ENODEV;
+
+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	ctrl->dev = dev;
+	ctrl->version = data->version;
+	ctrl->ofs = data->ofs;
+	ctrl->cap = data->cap;
+
+	ctrl->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(ctrl->regs)) {
+		dev_err(dev, "ioremap failed\n");
+		return PTR_ERR(ctrl->regs);
+	}
+
+	ctrl->irq = platform_get_irq(pdev, 0);
+	if (ctrl->irq < 0) {
+		dev_err(dev, "get irq failed\n");
+		return ctrl->irq;
+	}
+
+	ctrl->hclk = devm_clk_get(dev, "hclk_nandc");
+	if (IS_ERR(ctrl->hclk)) {
+		dev_err(dev, "get hclk_nandc failed\n");
+		return PTR_ERR(ctrl->hclk);
+	}
+
+	ret = clk_prepare_enable(ctrl->hclk);
+	if (ret)
+		return ret;
+
+	ctrl->clk = devm_clk_get(dev, "clk_nandc");
+	if (!(IS_ERR(ctrl->clk))) {
+		clk_set_rate(ctrl->clk, 150 * 1000 * 1000);
+
+		ret = clk_prepare_enable(ctrl->clk);
+		if (ret)
+			goto err_disable_hclk;
+	} else {
+		dev_dbg(dev, "get clk_nandc failed\n");
+	}
+
+	writel_relaxed(0, ctrl->regs + ctrl->ofs->inten);
+	ret = devm_request_irq(dev, ctrl->irq, rk_nandc_interrupt,
+			       0, "nandc", ctrl);
+	if (ret)
+		goto err_disable_clk;
+
+	init_completion(&ctrl->complete);
+	nand_controller_init(&ctrl->controller);
+	INIT_LIST_HEAD(&ctrl->chips);
+
+	rk_nandc_init(ctrl);
+
+	ret = rk_nandc_chips_init(ctrl);
+	if (ret) {
+		dev_err(dev, "init nand chips failed\n");
+		goto err_disable_clk;
+	}
+
+	platform_set_drvdata(pdev, ctrl);
+
+	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(ctrl->clk);
+err_disable_hclk:
+	clk_disable_unprepare(ctrl->hclk);
+
+	return ret;
+}
+
+static int rk_nandc_remove(struct platform_device *pdev)
+{
+	struct rk_nand_ctrl *ctrl = platform_get_drvdata(pdev);
+
+	rk_nandc_cleanup_chips(ctrl);
+
+	clk_disable_unprepare(ctrl->clk);
+	clk_disable_unprepare(ctrl->hclk);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static void rk_nandc_shutdown(struct platform_device *pdev)
+{
+	struct rk_nand_ctrl *ctrl = platform_get_drvdata(pdev);
+
+	rk_nandc_cleanup_chips(ctrl);
+
+	clk_disable_unprepare(ctrl->clk);
+	clk_disable_unprepare(ctrl->hclk);
+	platform_set_drvdata(pdev, NULL);
+}
+
+static const struct rk_nandc_data rk_nandc_V600_data = {
+	.version = VERSION_6,
+	.ofs = (void *)&rk_nandc_V6_reg_offset,
+	.cap = (void *)&rk_nandc_V600_cap,
+};
+
+static const struct rk_nandc_data rk_nandc_V622_data = {
+	.version = VERSION_6,
+	.ofs = (void *)&rk_nandc_V6_reg_offset,
+	.cap = (void *)&rk_nandc_V622_cap,
+};
+
+static const struct rk_nandc_data rk_nandc_V701_data = {
+	.version = VERSION_6,
+	.ofs = (void *)&rk_nandc_V6_reg_offset,
+	.cap = (void *)&rk_nandc_V701_cap,
+};
+
+static const struct rk_nandc_data rk_nandc_V801_data = {
+	.version = VERSION_6,
+	.ofs = (void *)&rk_nandc_V6_reg_offset,
+	.cap = (void *)&rk_nandc_V801_cap,
+};
+
+static const struct rk_nandc_data rk_nandc_V900_data = {
+	.version = VERSION_9,
+	.ofs = (void *)&rk_nandc_V9_reg_offset,
+	.cap = (void *)&rk_nandc_V900_cap,
+};
+
+static const struct of_device_id of_rk_nandc_match[] = {
+	{
+		.compatible = "rockchip,px30-nand-controller",
+		.data = &rk_nandc_V900_data,
+	},
+	{
+		.compatible = "rockchip,rk3066-nand-controller",
+		.data = &rk_nandc_V600_data,
+	},
+	{
+		.compatible = "rockchip,rk3228-nand-controller",
+		.data = &rk_nandc_V701_data,
+	},
+	{
+		.compatible = "rockchip,rk3288-nand-controller",
+		.data = &rk_nandc_V622_data,
+	},
+	{
+		.compatible = "rockchip,rk3308-nand-controller",
+		.data = &rk_nandc_V801_data,
+	},
+	{
+		.compatible = "rockchip,rk3368-nand-controller",
+		.data = &rk_nandc_V622_data,
+	},
+	{
+		.compatible = "rockchip,rv1108-nand-controller",
+		.data = &rk_nandc_V622_data,
+	},
+	{ /* sentinel */ },
+};
+
+static struct platform_driver rk_nandc_driver = {
+	.probe  = rk_nandc_probe,
+	.remove = rk_nandc_remove,
+	.shutdown = rk_nandc_shutdown,
+	.driver = {
+		.name = "rockchip-nand-controller",
+		.of_match_table = of_rk_nandc_match,
+	},
+};
+module_platform_driver(rk_nandc_driver);
+
+MODULE_LICENSE("GPL v2");
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 03/10] ARM: dts: rockchip: add nandc node for rk3066a/rk3188
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 02/10] mtd: rawnand: rockchip: Add NAND controller driver Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 04/10] ARM: dts: rockchip: add nandc node for rk322x Johan Jonker
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Chris Zhong <zyw@rock-chips.com>

Add nandc node for rk3066a/rk3188.

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/boot/dts/rk3xxx.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 97307a405..221c30314 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -273,6 +273,15 @@
 		status = "disabled";
 	};
 
+	nandc: nand-controller@10500000 {
+		compatible = "rockchip,rk3066-nand-controller";
+		reg = <0x10500000 0x4000>;
+		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC0>;
+		clock-names = "hclk_nandc";
+		status = "disabled";
+	};
+
 	pmu: pmu@20004000 {
 		compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
 		reg = <0x20004000 0x100>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 04/10] ARM: dts: rockchip: add nandc node for rk322x
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (2 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 03/10] ARM: dts: rockchip: add nandc node for rk3066a/rk3188 Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 05/10] ARM: dts: rockchip: add nandc nodes for rk3288 Johan Jonker
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Wenping Zhang <wenping.zhang@rock-chips.com>

Add nandc node for rk322x.

Signed-off-by: Wenping Zhang <wenping.zhang@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/boot/dts/rk322x.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 340ed6ccb..2f5122206 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -707,6 +707,15 @@
 		status = "disabled";
 	};
 
+	nandc: nand-controller@30030000 {
+		compatible = "rockchip,rk3228-nand-controller";
+		reg = <0x30030000 0x4000>;
+		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
 	usb_otg: usb@30040000 {
 		compatible = "rockchip,rk3228-usb", "rockchip,rk3066-usb",
 			     "snps,dwc2";
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 05/10] ARM: dts: rockchip: add nandc nodes for rk3288
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (3 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 04/10] ARM: dts: rockchip: add nandc node for rk322x Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 06/10] ARM: dts: rockchip: add nandc node for rv1108 Johan Jonker
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Jianqun Xu <jay.xu@rock-chips.com>

Add nandc nodes for rk3288.

Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 415c75f57..ebb833a1a 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -30,6 +30,8 @@
 		mshc1 = &sdmmc;
 		mshc2 = &sdio0;
 		mshc3 = &sdio1;
+		nandc0 = &nandc0;
+		nandc1 = &nandc1;
 		serial0 = &uart0;
 		serial1 = &uart1;
 		serial2 = &uart2;
@@ -596,6 +598,24 @@
 		status = "disabled";
 	};
 
+	nandc0: nand-controller@ff400000 {
+		compatible = "rockchip,rk3288-nand-controller";
+		reg = <0x0 0xff400000 0x0 0x4000>;
+		interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC0>, <&cru SCLK_NANDC0>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
+	nandc1: nand-controller@ff410000 {
+		compatible = "rockchip,rk3288-nand-controller";
+		reg = <0x0 0xff410000 0x0 0x4000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC1>, <&cru SCLK_NANDC1>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb@ff500000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xff500000 0x0 0x100>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 06/10] ARM: dts: rockchip: add nandc node for rv1108
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (4 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 05/10] ARM: dts: rockchip: add nandc nodes for rk3288 Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 07/10] arm64: dts: rockchip: add nandc node for px30 Johan Jonker
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Jon Lin <jon.lin@rock-chips.com>

Add nandc node for rv1108.

Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/boot/dts/rv1108.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi
index 5876690ee..d7b9aadbd 100644
--- a/arch/arm/boot/dts/rv1108.dtsi
+++ b/arch/arm/boot/dts/rv1108.dtsi
@@ -456,6 +456,15 @@
 		#reset-cells = <1>;
 	};
 
+	nandc: nand-controller@30100000 {
+		compatible = "rockchip,rv1108-nand-controller";
+		reg = <0x30100000 0x1000>;
+		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
 	emmc: dwmmc@30110000 {
 		compatible = "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc";
 		reg = <0x30110000 0x4000>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 07/10] arm64: dts: rockchip: add nandc node for px30
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (5 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 06/10] ARM: dts: rockchip: add nandc node for rv1108 Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:29 ` [RFC PATCH v2 08/10] arm64: dts: rockchip: add nandc node for rk3308 Johan Jonker
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Dingqiang Lin <jon.lin@rock-chips.com>

Add nandc node for px30.

Signed-off-by: Dingqiang Lin <jon.lin@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm64/boot/dts/rockchip/px30.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi
index 8812b70f3..5560e5b35 100644
--- a/arch/arm64/boot/dts/rockchip/px30.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30.dtsi
@@ -865,6 +865,18 @@
 		status = "disabled";
 	};
 
+	nandc: nand-controller@ff3b0000 {
+		compatible = "rockchip,px30-nand-controller";
+		reg = <0x0 0xff3b0000 0x0 0x4000>;
+		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		assigned-clocks = <&cru SCLK_NANDC>;
+		assigned-clock-parents = <&cru SCLK_NANDC_DIV50>;
+		power-domains = <&power PX30_PD_MMC_NAND>;
+		status = "disabled";
+	};
+
 	vopb: vop@ff460000 {
 		compatible = "rockchip,px30-vop-big";
 		reg = <0x0 0xff460000 0x0 0xefc>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 08/10] arm64: dts: rockchip: add nandc node for rk3308
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (6 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 07/10] arm64: dts: rockchip: add nandc node for px30 Johan Jonker
@ 2020-01-24 16:29 ` Johan Jonker
  2020-01-24 16:30 ` [RFC PATCH v2 09/10] arm64: dts: rockchip: add nandc node for rk3368 Johan Jonker
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:29 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Dingqiang Lin <jon.lin@rock-chips.com>

Add nandc node for rk3308.

Signed-off-by: Dingqiang Lin <jon.lin@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3308.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 8bdc66c62..a6c98edfb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -627,6 +627,15 @@
 		status = "disabled";
 	};
 
+	nandc: nand-controller@ff4b0000 {
+		compatible = "rockchip,rk3308-nand-controller";
+		reg = <0x0 0xff4b0000 0x0 0x4000>;
+		interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
 	cru: clock-controller@ff500000 {
 		compatible = "rockchip,rk3308-cru";
 		reg = <0x0 0xff500000 0x0 0x1000>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 09/10] arm64: dts: rockchip: add nandc node for rk3368
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (7 preceding siblings ...)
  2020-01-24 16:29 ` [RFC PATCH v2 08/10] arm64: dts: rockchip: add nandc node for rk3308 Johan Jonker
@ 2020-01-24 16:30 ` Johan Jonker
  2020-01-24 16:30 ` [RFC PATCH v2 10/10] ARM: dts: rockchip: rk3066a-mk808: enable nandc node Johan Jonker
  2020-01-24 17:17 ` [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Miquel Raynal
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:30 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

From: Zhaoyifeng <zyf@rock-chips.com>

Add nandc node for rk3368.

Signed-off-by: Zhaoyifeng <zyf@rock-chips.com>
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3368.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index fd8618801..22a1feed5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -508,6 +508,15 @@
 		status = "disabled";
 	};
 
+	nandc: nand-controller@ff400000 {
+		compatible = "rockchip,rk3368-nand-controller";
+		reg = <0x0 0xff400000 0x0 0x4000>;
+		interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru HCLK_NANDC0>, <&cru SCLK_NANDC0>;
+		clock-names = "hclk_nandc", "clk_nandc";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb@ff500000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xff500000 0x0 0x100>;
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 10/10] ARM: dts: rockchip: rk3066a-mk808: enable nandc node
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (8 preceding siblings ...)
  2020-01-24 16:30 ` [RFC PATCH v2 09/10] arm64: dts: rockchip: add nandc node for rk3368 Johan Jonker
@ 2020-01-24 16:30 ` Johan Jonker
  2020-01-24 17:17 ` [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Miquel Raynal
  10 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-24 16:30 UTC (permalink / raw)
  To: miquel.raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

This patch enables the nandc node for a MK808 with rk3066 processor.

Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/boot/dts/rk3066a-mk808.dts | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/rk3066a-mk808.dts b/arch/arm/boot/dts/rk3066a-mk808.dts
index 365eff621..e33c85699 100644
--- a/arch/arm/boot/dts/rk3066a-mk808.dts
+++ b/arch/arm/boot/dts/rk3066a-mk808.dts
@@ -133,6 +133,17 @@
 	status = "okay";
 };
 
+&nandc {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	nand@0 {
+		reg = <0>;
+		nand-is-boot-medium;
+	};
+};
+
 &pinctrl {
 	usb-host {
 		host_drv: host-drv {
-- 
2.11.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808
  2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
                   ` (9 preceding siblings ...)
  2020-01-24 16:30 ` [RFC PATCH v2 10/10] ARM: dts: rockchip: rk3066a-mk808: enable nandc node Johan Jonker
@ 2020-01-24 17:17 ` Miquel Raynal
  2020-01-25 22:28   ` Johan Jonker
  10 siblings, 1 reply; 14+ messages in thread
From: Miquel Raynal @ 2020-01-24 17:17 UTC (permalink / raw)
  To: Johan Jonker
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

Hi Johan,

Johan Jonker <jbx6244@gmail.com> wrote on Fri, 24 Jan 2020 17:29:51
+0100:

> DISCLAIMER: Use at your own risk.
> Status: For testing only!
> 
> Version: V2
> 
> Title: Enable RK3066 NANDC for MK808.
> 
> The majority of Rockchip devices use a closed source FTL driver
> to reduce wear leveling. This patch serie proposes
> an experimental raw NAND controller driver for basic tasks
> in order to get the bindings and the nodes accepted for in the dts files.
> 
> What does it do:
> 
> On module load this driver will reserve its resources.
> After initialization the MTD framework will then try to detect
> the type and number of NAND chips. When all conditions are met,
> it registers it self as MTD device.
> This driver is then ready to receive user commands
> such as to read and write NAND pages.
> 
> Test examples:
> 
> # dd if=/dev/mtd0 of=dd.bin bs=8192 count=4
> 
> # nanddump -a -l 32768 -f nanddump.bin /dev/mtd0
> 
> Not tested:
> 
> NANDC version 9.
> NAND raw write.

nandbiterrs -i /dev/mtd<x> to validate it works!

> RK3066 still has no support for Uboot.
> Any write command would interfere with data structures made by the boot loader.
> 
> Etc.
> 
> Problems:
> 
> No bad block support. Most devices use a FTL bad block map with tags
> that must be located on specific page locations which is outside
> the scope of the raw MTD framework.

I don't understand this story of bad block map. Are you comparing with
a vendor kernel?

If vendors invent new ways to handle MTD blocks it's sad but they will
never be compatible with mainline. It's a fact. However for an upstream
version, I don't get if there is any real issue? The location of the
BBM is not related to your controller driver but depends on the NAND
chip and as you say below we know provide three possible positions in
a block.

What you refer as the FTL is the equivalent of UBI in Linux, which
indeed offers to the user a linear logical view of all the valid blocks
while physically the data is spread across all the available
eraseblocks.

> 
> hynix_nand_init() add extra option NAND_BBM_LASTPAGE for H27UCG8T2ATR-BC.
> 
> No partition support. A FTL driver will store at random locations and
> a linear user specific layout does not fit within
> the generic character of this basic driver.
> 
> Driver assumes that IO pins are correctly set by the boot loader.

Which pins are you talking about? Are you missing a pinctrl driver?

> 
> Fixed timing setting.
> 
> RK3228A/RK3228B compatibility version 701 unknown
> RV1108 nand version unknown
> 
> Etc.
> 
> Todo:
> 
> MLC ?

This is not related to your NAND controller driver neither.


Cheers,
Miquèl

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808
  2020-01-24 17:17 ` [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Miquel Raynal
@ 2020-01-25 22:28   ` Johan Jonker
  0 siblings, 0 replies; 14+ messages in thread
From: Johan Jonker @ 2020-01-25 22:28 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: mark.rutland, devicetree, vigneshr, richard, shawn.lin,
	linux-kernel, linux-rockchip, robh+dt, linux-mtd, yifeng.zhao,
	linux-arm-kernel, heiko

Hi Miquel,

See below.
Btw, what is your impression of the other V2 'improvements'?

Thanks

[..]

>> Not tested:
>>
>> NANDC version 9.
>> NAND raw write.
>
> nandbiterrs -i /dev/mtd<x> to validate it works!
>
>> RK3066 still has no support for Uboot.
>> Any write command would interfere with data structures made by the
boot loader.
>>
>> Etc.
>>
>> Problems:
>>
>> No bad block support. Most devices use a FTL bad block map with tags
>> that must be located on specific page locations which is outside
>> the scope of the raw MTD framework.
>
> I don't understand this story of bad block map. Are you comparing with
> a vendor kernel?

Two separate things:

-Rockchip FTL has it's own FTL storage format.
The original factory BBM (marker) information is lost, so it stores
a BB (bad block) map/table at the (last erase block - n) and then downwards.
See source below. Not usable for raw MTD. It's the situation most user will
find on there NAND.


- For raw MTD to use it's own BB map in this stage the proposed solution
for raw MTD just didn't gave me something/results that I understand,
so I leave it out for now. For an empty NAND without Rockchip FTL this could
work as long as it stays out of our bootrom blocks.
It's fine that MTD is 'rigid', but not all Socs fit, so find solutions
that are maybe second best. MTD has most components already in place,
see what we can make out of it.

>
> If vendors invent new ways to handle MTD blocks it's sad but they will
> never be compatible with mainline. It's a fact. However for an upstream
> version, I don't get if there is any real issue? The location of the
> BBM is not related to your controller driver but depends on the NAND
> chip and as you say below we know provide three possible positions in
> a block.
>

Handling of MTD blocks remains the same AFAICT.
It transfers data and oob byte to MTD data structures.
Just find a way to tell MTD not mess with bootrom blocks.
Programming/reading in Uboot and Linux is something that Open Source
has to find a solution for.

> What you refer as the FTL is the equivalent of UBI in Linux, which
> indeed offers to the user a linear logical view of all the valid blocks
> while physically the data is spread across all the available
> eraseblocks.

When I refer to FTL it's to the Rockchip FTL.
In this current EXPERIMENTAL driver stage I just warn a potential
unaware user
of the things that are at play on that NAND. UBI might work fine, but
not now.

>
>>
>> hynix_nand_init() add extra option NAND_BBM_LASTPAGE for H27UCG8T2ATR-BC.
>>

Example:
To see what happens when a partition is placed over the bootrom erase
blocks.
From the previous log example it seems that it somehow does do a read
command
at the end of this partition. That what tests are for.

>> No partition support. A FTL driver will store at random locations and
>> a linear user specific layout does not fit within
>> the generic character of this basic driver.
>>

MTD partition support works fine. It's just the current content of my
RK3066 NAND
written with a Rockchip FTL loader that makes write tests not so smart
as I have
to reprogram then with USB. Chicken egg problem.

>> Driver assumes that IO pins are correctly set by the boot loader.
>
> Which pins are you talking about? Are you missing a pinctrl driver?
>

No, NAND share the same data IO pins as emmc.
Set direct in grfReg, not with pinctrl.
Every Rockchip grfReg is different, so leave it out for now.
For my Linux TEST driver not a issue as that is already done
by the loader.

Would you like this grf thing included in a Linux driver for every Soc?

>>
>> Fixed timing setting.

Mentioned for completeness.

>>
>> RK3228A/RK3228B compatibility version 701 unknown
>> RV1108 nand version unknown

Can Shawn Lin or someone else help here?
RV1108 TRM (manual) is still missing?

>>

[..]

Have fun!

/////////////////////
From rk3066a.dtsi:
SPDX-License-Identifier: (GPL-2.0+ OR MIT)
Copyright (c) 2013 MundoReader S.L.

		emmc {
			emmc_clk: emmc-clk {
				rockchip,pins = <3 RK_PD7 2 &pcfg_pull_default>;
			};

			emmc_cmd: emmc-cmd {
				rockchip,pins = <4 RK_PB1 2 &pcfg_pull_default>;
			};

			emmc_rst: emmc-rst {
				rockchip,pins = <4 RK_PB2 2 &pcfg_pull_default>;
			};

			/*
			 * The data pins are shared between nandc and emmc and
			 * not accessible through pinctrl. Also they should've
			 * been already set correctly by firmware, as
			 * flash/emmc is the boot-device.
			 */
		};

/////////////////////
From pinctrl_rk3066.c:
SPDX-License-Identifier:     GPL-2.0+
Copyright 2017 Paweł Jarosz

static void pinctrl_rk3066_nand_config(struct rk3066_grf *grf)
{
	rk_clrsetreg(&grf->soc_con0,
		     EMMC_FLASH_SEL_MASK,
		     0 << EMMC_FLASH_SEL_SHIFT);
	rk_clrsetreg(&grf->gpio3d_iomux,
		     GPIO3D7_MASK,
		     GPIO3D7_FLASH_DQS << GPIO3D7_SHIFT);
}

/////////////////////
For EMMC:

GRF_GPIO_IOMUX[3].GPIOD_IOMUX = ((0x3<<14)<<16)|(0x2<<14); // dqs
GRF_GPIO_IOMUX[4].GPIOB_IOMUX = ((0xf<<2)<<16)|(0xa<<2);   // cmd,rstn
GRF_SOC_CON[0] = ((0x1<<11)<<16)|(0x1<<11);                // emmc
data0-7,wp

/////////////////////

GRF_SOC_CON0 RK3066:
Bit Attr Reset Value        Description
31:16 RW 0x0 write_enable   bit 0~bit 15 write enable

11    RW 0x0 emmc_flash_sel emmc flash select used for iomux
                            IO_FLASH_DATA[7:0] , IO_FLASH_WP are
                            selected for emmc instead of flash

/////////////////////////////////////////////////////////////

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2019, Johan Jonker <jbx6244@gmail.com>
 *
 * Based on:
 *
https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/rk_nand/rk_ftl_arm_v7.S
 *
https://raw.githubusercontent.com/rockchip-linux/kernel/develop-4.4/drivers/rk_nand/rk_ftl_arm_v7.S
 * Copyright (c) 2016-2018, Fuzhou Rockchip Electronics Co., Ltd
 * SPDX-License-Identifier: GPL-2.0+
 *
 *
https://github.com/rockchip-linux/u-boot/blob/next-dev/drivers/rknand/rk_ftl_arm_v7.S
 *
https://raw.githubusercontent.com/rockchip-linux/u-boot/next-dev/drivers/rknand/rk_ftl_arm_v7.S
 * Copyright (c) 2016-2018, Fuzhou Rockchip Electronics Co., Ltd
 * SPDX-License-Identifier: GPL-2.0+
 */

struct nand_req {
	uint32_t status;
	uint32_t page_addr;
	uint32_t *p_data;
	uint16_t *p_spare;
	uint32_t lpn;
	uint32_t res2;
	uint32_t res3;
	uint32_t res4;
	uint32_t res5;
};

struct tagBbtInfo {
	uint16_t id;
	uint16_t page;
	uint16_t region;
	uint16_t counter;
	uint32_t index;
	uint16_t blk_cnt[8];
	uint32_t *map[8];
};

struct tag_sys_spare_buf {
	uint16_t tag;
	uint16_t id;
	uint32_t index;
	uint16_t region;
	uint16_t bb_num;
	uint32_t sys_blks_per_plane;
};

struct tagBbtInfo gBbtInfo;
struct nand_req req_sys;

uint32_t FtlBbmIsBadBlock(uint32_t lbn)
{
	return (gBbtInfo.map[(uint16_t)(lbn / c_ftl_nand_blks_per_die)]
		[lbn % c_ftl_nand_blks_per_die >> 5] >>
		(lbn % c_ftl_nand_blks_per_die & 0x1F)) & 1;
}

int FtlLoadBbt(void)
{
	struct tag_sys_spare_buf *p_spare;
	uint32_t counter;
	int i;
	uint32_t index;
	uint16_t page1;
	uint32_t page2;
	uint8_t *p_buf;
	uint32_t *p_map1;
	uint8_t *p_map2;
	uint16_t region;
	size_t size;
	uint16_t sys_blks_per_plane;
	uint32_t tmp;

	FTL_DBG();

	req_sys.p_data = p_sys_data_buf;
	p_spare = (struct tag_sys_spare_buf *)p_sys_spare_buf;
	req_sys.p_spare = p_sys_spare_buf;
	FtlBbtMemInit();
	for (i = (uint16_t)(c_ftl_nand_blks_per_die - 1);
	     c_ftl_nand_blks_per_die - 47 <= i;
	     i = (uint16_t)(i - 1)) {
		req_sys.page_addr = i << 10;
		FlashReadPages(&req_sys, 1u, 1u);
		if (req_sys.status == NAND_STS_ERROR) {
			++req_sys.page_addr;
			FlashReadPages(&req_sys, 1u, 1u);
		}
		if (req_sys.status != NAND_STS_ERROR &&
		    p_spare->tag == ID_BBTB) {
			index = p_spare->index;
			gBbtInfo.id = i;
			gBbtInfo.index = index;
			gBbtInfo.region = p_spare->region;
			break;
		}
	}
	if (gBbtInfo.id == 0xFFFF)
		return -1;
	if (gBbtInfo.region != 0xFFFF) {
		req_sys.page_addr = gBbtInfo.region << 10;
		FlashReadPages(&req_sys, 1u, 1u);
		if (req_sys.status != NAND_STS_ERROR &&
		    p_spare->tag == ID_BBTB &&
		    p_spare->index > gBbtInfo.index) {
			gBbtInfo.index = p_spare->index;
			region = p_spare->region;
			gBbtInfo.id = gBbtInfo.region;
			gBbtInfo.region = region;
		}
	}
	page1 = FtlGetLastWrittenPage(gBbtInfo.id, 1u);
	page2 = (uint16_t)page1;
	gBbtInfo.page = page1 + 1;
	while ((page2 & 0x80000000) == 0) {
		req_sys.page_addr = page2 | (gBbtInfo.id << 10);
		req_sys.p_data = p_sys_data_buf;
		FlashReadPages(&req_sys, 1u, 1u);
		if (req_sys.status != NAND_STS_ERROR &&
		    p_spare->tag == ID_BBTB) {
			goto label_1;
		}
		page2 = (uint16_t)(page2 - 1);
	}
	FTL_ERR();
label_1:
	sys_blks_per_plane = p_spare->sys_blks_per_plane;
	gBbtInfo.counter = p_spare->bb_num;
	if (sys_blks_per_plane != 0xFFFF &&
	    sys_blks_per_plane != c_ftl_nand_sys_blks_per_plane) {
		tmp = (uint32_t)c_ftl_nand_blk_per_plane >> 2;
		if (c_ftl_nand_sys_blks_per_plane < tmp &&
		    sys_blks_per_plane < tmp) {
			FtlSysBlkNumInit(sys_blks_per_plane);
		}
	}
	p_map1 = (uint32_t *)&gBbtInfo.blk_cnt[6];
	counter = 0;
	while (counter < c_ftl_nand_die_num) {
		p_map2 = (uint8_t *)p_map1[1];
		++p_map1;
		size = 4 * c_ftl_nand_bbm_buf_size;
		p_buf = (uint8_t *)req_sys.p_data + counter++ * size;
		ftl_memcpy(p_map2, p_buf, size);
	}
	return 0;
}

void FtlBbmTblFlush(void)
{
	struct tag_sys_spare_buf *p_spare;
	uint32_t bb_num;
	uint16_t counter1;
	uint32_t counter2;
	uint32_t die_counter;
	uint16_t lbn1;
	uint32_t lbn2;
	uint32_t *p_map;
	uint32_t sector;
	uint8_t *tmp_p_map;

	FTL_DBG();

	die_counter = 0;
	if (!g_flash_read_only_en) {
		p_map = (uint32_t *)&gBbtInfo.blk_cnt[6];
		req_sys.p_spare = p_sys_spare_buf;
		req_sys.p_data = p_sys_data_buf;
		ftl_memset(
			p_sys_data_buf,
			g_flash_read_only_en,
			c_ftl_nand_byte_per_page);
		while ((uint32_t)die_counter < c_ftl_nand_die_num) {
			tmp_p_map = (uint8_t *)p_map[1];
			++p_map;
			sector = die_counter++
				 * c_ftl_nand_bbm_buf_size;
			ftl_memcpy(
				&req_sys.p_data[sector],
				tmp_p_map,
				4 * c_ftl_nand_bbm_buf_size);
		}
		p_spare = (struct tag_sys_spare_buf *)req_sys.p_spare;
		counter1 = 0;
		counter2 = 0;
		ftl_memset(req_sys.p_spare, 0xFFu, 16u);
		p_spare->tag = ID_BBTB;
		p_spare->index = gBbtInfo.index;
		p_spare->id = gBbtInfo.id;
		p_spare->region = gBbtInfo.region;
		p_spare->bb_num = gBbtInfo.counter;
		p_spare->sys_blks_per_plane = c_ftl_nand_sys_blks_per_plane;
		do {
			while (1) {
				req_sys.p_data = p_sys_data_buf;
				bb_num = p_spare->bb_num;
				req_sys.p_spare = p_sys_spare_buf;
				req_sys.status = NAND_STS_OK;
				req_sys.page_addr = gBbtInfo.page
						    | (gBbtInfo.id << 10);
				FTL_INFO(
					"FtlBbmTblFlush id=%x,page=%x,"
					"previd=%x cnt=%d\n",
					gBbtInfo.id,
					gBbtInfo.page,
					gBbtInfo.region,
					bb_num);
				if (gBbtInfo.page >=
				    c_ftl_nand_page_per_slc_blk - 1) {
					lbn1 = gBbtInfo.id;
					gBbtInfo.page = 0;
					p_spare->index = ++gBbtInfo.index;
					p_spare->region = lbn1;
					lbn2 = gBbtInfo.region;
					gBbtInfo.region = lbn1;
					gBbtInfo.id = lbn2;
					req_sys.page_addr = lbn2 << 10;
					req_erase->page_addr = lbn2 << 10;
					FlashEraseBlocks(
						req_erase,
						1u,
						1u);
				}
				FlashProgPages(&req_sys, 1u, 1u, 1u);
				++gBbtInfo.page;
				if (req_sys.status == NAND_STS_ERROR)
					break;
				if (++counter2 != 1 &&
				    req_sys.status != NAND_STS_REFRESH) {
					return;
				}
			}
			++counter1;
			FTL_INFO(
				"FtlBbmTblFlush error:%x\n",
				req_sys.page_addr);
		} while (counter1 <= 3u);
		FTL_INFO(
			"FtlBbmTblFlush error = %x error count = %d\n",
			req_sys.page_addr,
			counter1);
		g_flash_read_only_en = 1;
	}
}

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings
  2020-01-24 16:29 ` [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings Johan Jonker
@ 2020-02-03 15:45   ` Rob Herring
  0 siblings, 0 replies; 14+ messages in thread
From: Rob Herring @ 2020-02-03 15:45 UTC (permalink / raw)
  To: Johan Jonker
  Cc: mark.rutland, devicetree, heiko, richard, shawn.lin,
	linux-kernel, linux-rockchip, linux-mtd, miquel.raynal,
	yifeng.zhao, linux-arm-kernel, vigneshr

On Fri, Jan 24, 2020 at 05:29:52PM +0100, Johan Jonker wrote:
> Add the Rockchip NAND controller bindings.
> 
> Signed-off-by: Johan Jonker <jbx6244@gmail.com>
> ---
>  .../bindings/mtd/rockchip,nand-controller.yaml     | 92 ++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
> 
> diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
> new file mode 100644
> index 000000000..5c725f972
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
> @@ -0,0 +1,92 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip NAND Controller Device Tree Bindings
> +
> +allOf:
> +  - $ref: "nand-controller.yaml#"
> +
> +maintainers:
> +  - Heiko Stuebner <heiko@sntech.de>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,px30-nand-controller
> +      - rockchip,rk3066-nand-controller
> +      - rockchip,rk3228-nand-controller
> +      - rockchip,rk3288-nand-controller
> +      - rockchip,rk3308-nand-controller
> +      - rockchip,rk3368-nand-controller
> +      - rockchip,rv1108-nand-controller
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    minItems: 1
> +    maxItems: 2
> +
> +  clock-names:
> +    minItems: 1
> +    items:
> +      - const: hclk_nandc
> +      - const: clk_nandc
> +
> +patternProperties:
> +  "^nand@[a-f0-9]+$":
> +    type: object
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 3
> +
> +      nand-is-boot-medium: true
> +
> +      rockchip,idb-res-blk-num:

What is idb? Rather than define, maybe just 'rockchip,boot-blks'?

> +        minimum: 2

is there a max?

> +        default: 16
> +        allOf:
> +        - $ref: /schemas/types.yaml#/definitions/uint32
> +        description:
> +          For legacy devices where the bootrom can only handle 24 bit BCH/ECC.
> +          If specified it indicates the number of erase blocks in use by
> +          the bootloader that need a lower BCH/ECC setting.
> +          Only used in combination with 'nand-is-boot-medium'.
> +
> +    additionalProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/rk3188-cru-common.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    nandc: nand-controller@10500000 {
> +      compatible = "rockchip,rk3066-nand-controller";
> +      reg = <0x10500000 0x4000>;
> +      interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
> +      clocks = <&cru HCLK_NANDC0>;
> +      clock-names = "hclk_nandc";
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +
> +      nand@0 {
> +        reg = <0>;
> +        nand-is-boot-medium;
> +      };
> +    };
> +
> +...
> -- 
> 2.11.0
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2020-02-03 15:46 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-24 16:29 [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 01/10] dt-bindings: mtd: add rockchip nand controller bindings Johan Jonker
2020-02-03 15:45   ` Rob Herring
2020-01-24 16:29 ` [RFC PATCH v2 02/10] mtd: rawnand: rockchip: Add NAND controller driver Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 03/10] ARM: dts: rockchip: add nandc node for rk3066a/rk3188 Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 04/10] ARM: dts: rockchip: add nandc node for rk322x Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 05/10] ARM: dts: rockchip: add nandc nodes for rk3288 Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 06/10] ARM: dts: rockchip: add nandc node for rv1108 Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 07/10] arm64: dts: rockchip: add nandc node for px30 Johan Jonker
2020-01-24 16:29 ` [RFC PATCH v2 08/10] arm64: dts: rockchip: add nandc node for rk3308 Johan Jonker
2020-01-24 16:30 ` [RFC PATCH v2 09/10] arm64: dts: rockchip: add nandc node for rk3368 Johan Jonker
2020-01-24 16:30 ` [RFC PATCH v2 10/10] ARM: dts: rockchip: rk3066a-mk808: enable nandc node Johan Jonker
2020-01-24 17:17 ` [RFC PATCH v2 00/10] Enable RK3066 NANDC for MK808 Miquel Raynal
2020-01-25 22:28   ` Johan Jonker

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).