* [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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply related [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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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 MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ 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).