Mainline NAND Howto

This page describes how to enable NAND support in Linux mainline kernel.

= Current status = See MTD Driver

= Prerequisites =


 * Mainline kernel >= 4.10.0-rc1
 * NAND detection/initialization patchset patch-v5

= Kernel Configuration = To use MTD driver with Linux mainline kernel you should enable: Device Drivers ---> <*> Memory Technology Device (MTD) support ---> <*>  OpenFirmware partitioning information support <*>  NAND Device Support  ---> <*>  Support for NAND on Allwinner SoCs

= Known issues =

Many bad blocks
To fix many bad blocks issue you should: 1. Disable nand-on-flash-bbt in your dts 2. Remove this test: http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_base.c?v=4.7#L2940 3. Boot your new kernel and erase chip with flash_erase /dev/mtd[0-X] 4. Re-introduce the bad block check removed in 2, re-enable nand-on-flash-bbt and boot the new kernel

Patch to disable nand bad block check from here https://lkml.org/lkml/2014/10/21/546 diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts index 1ef937b..65ac8af 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts @@ -33,6 +33,7 @@ 				nand-ecc-mode = "hw"; nand-rnd-mode = "hw"; +				/* 				nand-on-flash-bbt; boot0@0 { @@ -74,6 +75,7 @@ 						0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>; }; +				*/ 			}; 		}; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7311063..153b323 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3312,8 +3312,10 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, 					chip->page_shift, 0, allowbbt)) { 			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); +			/* 			instr->state = MTD_ERASE_FAILED; 			goto erase_exit; +			*/ 		}

= Adding a new device =

Add NAND controller pin definitions
Most of boards use the same pins for NAND controller, so you should add pin definitions in SoC's DTSI

For example, Allwinner A10/A20 have the same pins used for NAND: nand_pins_a: nand_base0@0 { allwinner,pins = "PC0", "PC1", "PC2", "PC5", "PC8", "PC9", "PC10", "PC11", "PC12", "PC13", "PC14", "PC15", "PC16"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_cs0_pins_a: nand_cs@0 { allwinner,pins = "PC4"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_cs1_pins_a: nand_cs@1 { allwinner,pins = "PC3"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_cs2_pins_a: nand_cs@2 { allwinner,pins = "PC17"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_cs3_pins_a: nand_cs@3 { allwinner,pins = "PC18"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_rb0_pins_a: nand_rb@0 { allwinner,pins = "PC6"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

nand_rb1_pins_a: nand_rb@1 { allwinner,pins = "PC7"; allwinner,function = "nand0"; allwinner,drive = ; allwinner,pull = ; };

Add NFC node to SoC's DTSI
Once you define pins, you should add NFC node.

Example for Allwinner A10: nfc: nand@01c03000 { compatible = "allwinner,sun4i-a10-nand"; reg = ; interrupts = <37>; clocks = <&ahb_gates 13>, <&nand_clk>; clock-names = "ahb", "mod"; dmas = <&dma SUN4I_DMA_DEDICATED 3>; dma-names = "rxtx"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; }; Since Allwinner A20 SoCs have it's own interrupt controller, interrupts line should be changed.

Example for A20: nfc: nand@01c03000 { compatible = "allwinner,sun4i-a10-nand"; reg = ; interrupts = ;; clocks = <&ahb_gates 13>, <&nand_clk>; clock-names = "ahb", "mod"; dmas = <&dma SUN4I_DMA_DEDICATED 3>; dma-names = "rxtx"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };

Enable NAND in board's DTS
Once you have done with SoC's DTSI changes, you should enable NAND in your board DTS file.

In a single-chip configuration, chip usually connected to base nand pins, cs0(Chip Select) and rb0(Ready/Busy) pins. &nfc { pinctrl-names = "default"; pinctrl-0 = <&nand_pins_a>, <&nand_cs0_pins_a>, <&nand_rb0_pins_a>; status = "okay";

nand@0 { #address-cells = <2>; #size-cells = <2>; reg = <0>; allwinner,rb = <0>;

nand-ecc-mode = "hw"; nand-on-flash-bbt; }; };

Define NAND partitions in DTS
If you want, you can define partitions on your NAND. See mtd partitions documentation

For example, if your board have 4G NAND chip, you can split it to 5 partitions:

This lines should be placed in NFC node of your board's DTS. boot0@0 { label = "boot0"; reg = /bits/ 64 ; };

boot0-rescue@200000 { label = "boot0-rescue"; reg = /bits/ 64 ; };

uboot@400000 { label = "uboot"; reg = /bits/ 64 ; };

uboot-rescue@600000 { label = "uboot-rescue"; reg = /bits/ 64 ; };

main@800000 { label = "main"; reg = /bits/ 64 ; };

Armbian has a full device tree definition in their dt-overlay git repo https://github.com/armbian/sunxi-DT-overlays/blob/e4dfea8304d66cb3403e5e1b73d2f346349124ec/sun7i-a20/sun7i-a20-nand.dts = Booting from NAND = TODO


 * Howto for the experimental NAND support - http://lists.denx.de/pipermail/u-boot/2015-May/214959.html