Introduction

This page gives an overview of Zynq Ultrascale+ MPSoC nand driver which is located at drivers/mtd/nand/arasan_nfc.c. link: nand source file
NAND driver provides basic functions that are required for accessing the nand flash memory including the support for hw ecc and bad block management.

HW IP Features

Controller Features

  • Complies with the ONFI 3.1 specification
  • Supports interleaving operations
  • Supports BCH error correction code (ECC) data widths of 4, 8, 12, and 24 bits.
  • All ONFI 3.1 commands
  • PIO and MDMA support
  • SDR and NVDDR modes
  • supports only 8-bit bus support
  • Hardware ECC (Hamming code and BCH)
  • Page size up to 16K
  • Programmable timing modes
  • 64-bit dma support.
  • Supports multiple chip selects (up to 2)

Driver Features

  • Supports only the mandatory ONFI 3.1 commands. i.e Reset, Read status, Read ID, Read Parameter Page, Read Page, Program Page, Erase Block, Set/Get Features
  • Supports SDR/DDR modes
  • Supports timing modes 0-5
  • Supports PIO and MDMA support
  • Support for multiple chip selection
  • Support 64-bit dma
  • Support BBT management
  • Hardware ECC (Hamming code and BCH upto 24 bits)

Missing features, Known Issues, limitations

  • No support for interleaved and all optional ONFI 3.1 commands

Bad Block management

Bad block management implementation is same as Linux MTD bad block management with the exception of reserving number of blocks to store Bad Block Table (BBT) from default 4 blocks to 64 blocks. This is because one of the Micron flash part MT29F32G08ABCDB has last 32 blocks as bad most of the times. Since it was difficult to store bad block table in last 4 blocks, the number of blocks are increased to 64 blocks.

Kernel Configuration Options

The following config options should be enabled in order to build Zynq Ultrascale+ MPSoC
CONFIG_MTD_NAND_ARASAN
CONFIG_MTD_NAND
config MTD_NAND_ARASAN
    tristate "Support for Arasan Nand Flash controller"
    depends on MTD_NAND
    help
      Enables the driver for the Arasan Nand Flash controller in ZynqMP SoC.

Device Tree Settings



More information on nand device tree node details, refer the link nand device tree

Example for device tree


                nand0: nand@ff100000 {
                        compatible = "arasan,nfc-v3p10";
                        reg = <0x0 0xff100000 0x0 0x1000>;
                        clock-names = "clk_sys", "clk_flash";
                        interrupt-parent = <&gic>;
                        interrupts = <0 14 4>;
                        #address-cells = <2>;
                        #size-cells = <1>;
                };
 

Nand Partition details


Below example assumes that controller is using 2 chip select lines
&nand0 {
    status = "okay";
    arasan,has-mdma;
    nand@0 {
        reg = <0x0>;
        #address-cells = <0x2>;
        #size-cells = <0x1>;
 
        partition@0 {    /* for testing purpose */
            label = "nand-fsbl-uboot";
            reg = <0x0 0x0 0x400000>;
        };
        partition@1 {    /* for testing purpose */
            label = "nand-linux";
            reg = <0x0 0x400000 0x1400000>;
        };
        partition@2 {    /* for testing purpose */
            label = "nand-device-tree";
            reg = <0x0 0x1800000 0x400000>;
        };
        partition@3 {    /* for testing purpose */
            label = "nand-rootfs";
            reg = <0x0 0x1C00000 0x1400000>;
        };
        partition@4 {    /* for testing purpose */
            label = "nand-bitstream";
            reg = <0x0 0x3000000 0x400000>;
        };
        partition@5 {    /* for testing purpose */
            label = "nand-misc";
            reg = <0x0 0x3400000 0xFCC00000>;
        };
    };
    nand@1 {
        reg = <0x1>;
        #address-cells = <0x2>;
        #size-cells = <0x1>;
 
        partition@0 {    /* for testing purpose */
            label = "nand1-fsbl-uboot";
            reg = <0x1 0x0 0x400000>;
        };
        partition@1 {    /* for testing purpose */
            label = "nand1-linux";
            reg = <0x1 0x400000 0x1400000>;
        };
        partition@2 {    /* for testing purpose */
            label = "nand1-device-tree";
            reg = <0x1 0x1800000 0x400000>;
        };
        partition@3 {    /* for testing purpose */
            label = "nand1-rootfs";
            reg = <0x1 0x1C00000 0x1400000>;
        };
        partition@4 {    /* for testing purpose */
            label = "nand1-bitstream";
            reg = <0x1 0x3000000 0x400000>;
        };
        partition@5 {    /* for testing purpose */
            label = "nand1-misc";
            reg = <0x1 0x3400000 0xFCC00000>;
        };
    };
};
 

Testing procedure

Prerequisites

Kernel tools

mtd layer provides a rich set of tests for validating the nand access including the performance and stress tests
Following kernel config options should be enabled for mtd tests
CONFIG_MTD_TESTS

user space tools

Below test cases requires the following user space tools
mtd_debug, nandtest
All these tools are part of the mtd-utils and source is available from link http://git.infradead.org/mtd-utils.git

Note: expected output may not be same and its all depends on the flash device and configuration of the target system.

Driver Probe

Assuming the target has nand flash memory installed

How to Run

Boot the target till Linux and ensure that nand driver is enabled.

Expected Output

nand: device found, Manufacturer ID: 0x2c, Chip ID: 0x44
nand: Micron MT29F32G08ABCDBJ4

Block Erase test

How to Run

After linux boot,
root@zynqmp:~# mtd_debug erase /dev/mtd0 0x00000000 0x400000

Expected Output

Erased 4194304 bytes from address 0x00000000 in flash

Write Page test

How to Run

After linux boot,
Create a test image
root@zynqmp:~# dd if=/dev/urandom of=/tmp/test1.img bs=1024 count=16
 
root@zynqmp:~# mtd_debug write /dev/mtd0 0x00000000 0x4000 /tmp/test1.img
 

Expected Output

Copied 16384 bytes from /tmp/test1.img to address 0x00000000 in flash

Read Page and Data integrity test

How to Run

After linux boot,
root@zynqmp:~# mtd_debug read /dev/mtd0 0x00000000 0x4000 /tmp/test2.img
 
root@zynqmp:~# cmp /tmp/test1.img /tmp/test2.img
 
root@zynqmp:~# md5sum /tmp/test1.img /tmp/test2.img
 

Expected Output

Copied 16384 bytes from address 0x00000000 in flash to /tmp/test2.img
 
7a0c68453dfb8028fca49f30d5cc798f  /tmp/test1.img
7a0c68453dfb8028fca49f30d5cc798f  /tmp/test2.img
 

Data integrity test using nandtest utility

How to Run

After linux boot,
root@zynqmp:~# nandtest /dev/mtd0

Expected Output

ECC corrections: 0
ECC failures   : 0
Bad blocks     : 0
BBT blocks     : 0
 
00000000: erasing...
00000000: writing...
00000000: reading...[  403.220080] random: nonblocking pool is initialized
 
00000000: checking...
00400000: erasing...
00400000: writing...
00400000: reading...
 256 bit(s) ECC corrected at 00400000
 
00400000: checking...
00800000: erasing...
00800000: writing...
00800000: reading...
00800000: checking...
00c00000: erasing...
00c00000: writing...
00c00000: reading...
00c00000: checking...
01000000: erasing...
01000000: writing...
01000000: reading...
 256 bit(s) ECC corrected at 01000000
 
01000000: checking...
01400000: erasing...
01400000: writing...
01400000: reading...
 256 bit(s) ECC corrected at 01400000
 
01400000: checking...
01800000: erasing...
01800000: writing...
01800000: reading...
01800000: checking...
01c00000: erasing...
01c00000: writing...
01c00000: reading...
 256 bit(s) ECC corrected at 01c00000
 
01c00000: checking...
Finished pass 1 successfully.
 

MTD oob test

How to Run

After linux boot,
root@zynqmp:~# insmod /lib64/modules/3.18.0/kernel/drivers/mtd/tests/mtd_oobtest.ko dev=0 bitflip_limit=2

Expected Output

mtd_oobtest: MTD device: 0
mtd_oobtest: MTD device size 4194304, eraseblock size 4194304, page size 16384, count of eraseblocks 1, pages per eraseblock 256, OOB size 1216
mtd_test: scanning for bad eraseblocks
mtd_test: block 0 is bad
mtd_test: scanned 1 eraseblocks, 1 are bad
mtd_oobtest: test 1 of 5
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written 1 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified 1 eraseblocks
mtd_oobtest: test 2 of 5
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written 1 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified 1 eraseblocks
mtd_oobtest: test 3 of 5
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written 1 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified 1 eraseblocks
mtd_oobtest: test 4 of 5
mtd_oobtest: attempting to start write past end of OOB
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: attempting to start read past end of OOB
mtd_oobtest: an error is expected...
mtd_oobtest: error occurred as expected
mtd_oobtest: skipping end of device tests because last block is bad
mtd_oobtest: test 5 of 5
mtd_oobtest: writing OOBs of whole device
mtd_oobtest: written 0 eraseblocks
mtd_oobtest: verifying all eraseblocks
mtd_oobtest: verified 0 eraseblocks
mtd_oobtest: finished with 0 errors

MTD speed test

How to Run

After Linux boot,
root@zynqmp:~# insmod /lib64/modules/3.18.0/kernel/drivers/mtd/tests/mtd_speedtest.ko dev=1

Expected Output

[ 1095.837999] mtd_speedtest: MTD device: 1
[ 1095.843829] mtd_speedtest: MTD device size 20971520, eraseblock size 4194304, page size 16384, count of eraseblocks 5, pages per eraseblock 256, OOB size 1216
[ 1099.402522] mtd_test: scanning for bad eraseblocks
[ 1099.412007] mtd_test: scanned 5 eraseblocks, 0 are bad
[ 1099.425916] mtd_speedtest: testing eraseblock write speed
[ 1102.011923] mtd_speedtest: eraseblock write speed is 32050 KiB/s
[ 1102.018596] mtd_speedtest: testing eraseblock read speed
[ 1104.348730] mtd_speedtest: eraseblock read speed is 105567 KiB/s
[ 1104.361921] mtd_speedtest: testing page write speed
[ 1107.066150] mtd_speedtest: page write speed is 31459 KiB/s
[ 1107.073483] mtd_speedtest: testing page read speed
[ 1109.440204] mtd_speedtest: page read speed is 105025 KiB/s
[ 1109.452175] mtd_speedtest: testing 2 page write speed
[ 1112.037846] mtd_speedtest: 2 page write speed is 31653 KiB/s
[ 1112.045696] mtd_speedtest: testing 2 page read speed
[ 1114.389894] mtd_speedtest: 2 page read speed is 103434 KiB/s
[ 1114.396947] mtd_speedtest: Testing erase speed
[ 1114.407803] mtd_speedtest: erase speed is 1575384 KiB/s
[ 1114.414640] mtd_speedtest: Testing 2x multi-block erase speed
[ 1114.426056] mtd_speedtest: 2x multi-block erase speed is 3413333 KiB/s
[ 1114.434134] mtd_speedtest: Testing 4x multi-block erase speed
[ 1114.445505] mtd_speedtest: 4x multi-block erase speed is 3413333 KiB/s
[ 1114.453594] mtd_speedtest: Testing 8x multi-block erase speed
[ 1114.464981] mtd_speedtest: 8x multi-block erase speed is 3413333 KiB/s
[ 1114.473070] mtd_speedtest: Testing 16x multi-block erase speed
[ 1114.484568] mtd_speedtest: 16x multi-block erase speed is 3413333 KiB/s
[ 1114.492770] mtd_speedtest: Testing 32x multi-block erase speed
[ 1114.504277] mtd_speedtest: 32x multi-block erase speed is 3413333 KiB/s
[ 1114.512469] mtd_speedtest: Testing 64x multi-block erase speed
[ 1114.523069] mtd_speedtest: 64x multi-block erase speed is 3413333 KiB/s
[ 1114.531180] mtd_speedtest: finished

MTD stress test

How to Run

After Linux boot,
root@zynqmp:~# insmod /lib64/modules/3.18.0/kernel/drivers/mtd/tests/mtd_stresstest.ko count=100 dev=1

Expected Output

[ 1507.464980] mtd_stresstest: MTD device: 1
[ 1507.470160] mtd_stresstest: MTD device size 20971520, eraseblock size 4194304, page size 16384, count of eraseblocks 5, pages per eraseblock 256, OOB size 1216
[ 1514.872670] mtd_test: scanning for bad eraseblocks
[ 1514.882396] mtd_test: scanned 5 eraseblocks, 0 are bad
[ 1514.888324] mtd_stresstest: doing operations
[ 1514.895249] mtd_stresstest: 0 operations done
[ 1717.343065] mtd_stresstest: finished, 100 operations done

MTD page read test

How to Run

After Linux boot,
root@zynqmp:~# insmod /lib64/modules/3.18.0/kernel/drivers/mtd/tests/mtd_readtest.ko dev=0

Expected Output

[ 1072.411150] mtd_readtest: MTD device: 0
[ 1072.416201] mtd_readtest: MTD device size 4194304, eraseblock size 4194304, page size 16384, count of eraseblocks 1, pages per eraseblock 256, OOB size 1216
[ 1072.441654] mtd_test: scanning for bad eraseblocks
[ 1072.447700] mtd_test: scanned 1 eraseblocks, 0 are bad
[ 1072.454315] mtd_readtest: testing page read
[ 1075.527773] mtd_readtest: finished
Note: Paths for the modules and tool names may vary from release to release. Please cross verify before starting the test.

Change Log

  • 2016.3

  • 2016.4

    • Summary
      • None
    • Commits
      • None
  • 2017.1

    • Summary
      • Update Arasan Nand flash controller as per latest kernel change
      • Change ref clk in SDR modes 2 to 5 to less than 90MHz
    • Commits
      • 6c59929: Update Arasan Nand flash controller driver
      • cab8221: Change ref clk in SDR modes 2 to 5
  • 2017.2

    • Summary
      • Add on-die ecc support
      • Use nand helpers to correct bit flips in the data
    • Commits
      • 59440b6 Add on-die ecc support
      • 6216d9d2 Add nand helper functions to correct data bitflips
  • 2017.3

    • Summary
      • Add 64bit dma support
      • Add runtime support
    • Commits

Related Links