How to Boot from NAND Flash on the Atmel SAM9 Boards

NFS-based root file systems are very useful in a development environment. However, once you start to move to a production system, it is no longer a viable option. Instead, you will want your device to boot from some sort of persistent memory, such as NAND flash. This document explains how to boot a complete system from NAND flash on an Atmel SAM9-based system.

If you are looking for instructions for writing bootloaders to NAND flash, please see the following document: HOWTO Write Bootloaders to Flash on Atmel SAM9 Boards.

Prerequisites

  • AT91 Bootstrap Loader source or Binary
  • U-Boot source or Binary
  • Kernel uImage with the following configuration options enabled:
    • CONFIG_MTD_PARTITIONS=y
    • CONFIG_MTD_CMDLINE_PARTS=y (optional)
    • CONFIG_MTD_BLOCK=y
    • CONFIG_MTD_NAND=y
    • CONFIG_MTD_NAND_ATMEL=y
    • CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y (SAM-BA uses soft ECC)
    • CONFIG_MTD_UBI=y (If using UBI and UBIFS)
    • CONFIG_UBIFS_FS=y (If using UBI and UBIFS)
    • CONFIG_JFFS2_FS=y (If using JFFS2)
    • CONFIG_JFFS2_SUMMARY=y (If using JFFS2 with summary support)
  • RFS file (typically JFFS2 or UBI)

Building the Bootloader Images

If you do not have binary versions of the bootloaders, you must build them from source. See the following documents for more information:

Configuring U-Boot for NAND flash

In the most recent versions of U-Boot (v2009.01 and newer), you can specify NAND flash as the environment by using the following configuration command:

# make <board name>_nandflash_config

In some versions of U-Boot, you must patch the U-Boot source in order to boot from NAND flash:

Affected Versions:

  • v1.1.5-at91
  • v1.1.5-at91.2
  • v1.1.5-at91.3

Modify the file include/configs/<board name>.h as follows:

#define CFG_ENV_IS_IN_NAND 1
#undef  CFG_ENV_IS_IN_DATAFLASH

Affected Versions:

  • v2008.10

Modify the file include/configs/<board name>.h as follows:

#undef CFG_USE_DATAFLASH
#define CFG_USE_NANDFLASH               1

Building RFS Images

Writing Bootloaders to NAND Flash

Determining your Flash Partitions

The kernel has the ability to divide a single flash device into multiple partitions. We can take advantage of this to keep the kernel from using sections of the flash that have been reserved for the kernel and bootloaders. To determine the partition scheme of the NAND flash, you can look at the kernel output at boot time. Here is an example:

NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
AT91 NAND: 8-bit, Software ECC
Scanning device for bad blocks
Bad eraseblock 1020 at 0x07f80000
Bad eraseblock 1280 at 0x0a000000
Creating 2 MTD partitions on "atmel_nand":
0x00000000-0x00040000 : "Partition 1"                                           
0x00040000-0x10000000 : "Partition 2" 

Based on this, you can determine the partition scheme of the device. The line

0x00000000-0x00040000 : "Partition 1"

states that the first partition begins at offset 0 from the start of NAND, and continues until address 0x40000, giving it a size of 0x40000 bytes.

The second partition starts at 0x40000 and is 0xffc0000 bytes long.

If there are no other MTD devices on the board, such as DataFlash or NOR flash, then these will correspond to /dev/mtdblock0 and /dev/mtdblock1, respectively.

If you are able to boot into a filesystem, you can use the file /proc/mtd to see the exact partitioning scheme for all MTDs on your board:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00020000 "Partition 1" 
mtd1: 0ffc0000 00020000 "Partition 2" 

size corresponds to the density (in bytes), and erasesize corresponds to the Physical Erase Block size (in Bytes).

Use this information to determine where to put your kernel and RFS. The RFS should have its own partition all to itself (e.g. mtd1), while the kernel can share a partition with a bootloader, size permitting. Make a note of the offsets that you are using for each one, since they will be used in a later step.

Modifying NAND Partitioning

If the partitions in the kernel are not adequate, as in the example above, you can use command line MTD partitioning to modify the layout:

You can also modify the partitions in the Linux kernel by changing the ek_nand_partition array in the file arch/arm/mach-at91/board-sam9xxx.c in the kernel source tree.

Writing Kernel to NAND Flash

  1. Start up SAM-BA, if it is not already open.
  2. Burn Kernel to NAND Flash
    1. Click the NandFlash tab
    2. Select Enable NandFlash under the Scripts dropdown and click Execute
    3. Click the Browse button next to Send File Name under the Download/Upload File section. Navigate to your uImage file and click Open.
    4. Set the Address box to the address that you wish to store the kernel.
    5. Click Send File
  3. If you are not writing an RFS to flash, close SAM-BA and reset the board. Otherwise, you may leave it open.

Writing RFS to NAND Flash

  1. Start up SAM-BA, if it is not already open.
  2. Burn RFS to NAND Flash
    1. Click the NandFlash tab
    2. Select Enable NandFlash under the Scripts dropdown and click Execute
    3. Click the Browse button next to Send File Name under the Download/Upload File section. Navigate to your rfs file and click Open.
    4. Set the Address box to the address that marks the beginning of the RFS partition.
    5. Click Send File
  3. Close SAM-BA and reset the board.

Boot procedure

In order to boot from NAND, you must load the kernel from NAND into memory, and then tell the kernel where to look for the RFS, and how to load it.

  1. Copy the kernel into RAM using the nand read command:
    U-Boot> nand read <address> <offset> <size>

    This command will read <size> bytes from NAND address <offset> and move it to <address> in RAM. <size> should be greater than or equal to the size of the kernel. <offset> should be the start of the kernel partition in NAND, the same value used in the section Writing Kernel to NAND Flash above. <address> should be some location in RAM. The values 0x22000000 or 0x21400000 have been tested and work.
  2. Set the kernel command line to boot from NAND flash:
    U-Boot> setenv bootargs console=ttyS0,115200 rootfstype=jffs2 root=/dev/mtdblockN rw

    You should substitute the proper MTD device number for N in the root parameter above. See the UBIFS doc for information about how to use UBI.
  3. Boot the kernel using the bootm command.
    U-Boot> bootm <address>

    <address> is the same address that was used in the NAND read command above.

Important Notes

NAND flash Errata

On the at91sam9260, at91sam9261, and at91sam9263 revision A processors, there is an issue with NAND timings in the boot ROM silicon. This means that you cannot load AT91 Bootstrap from the NAND flash chip. This means that you must load AT91 Bootstrap from Dataflash. It is still possible to run U-Boot from NAND, however. If you wish to use this configuration, put the bootloaders in the following locations:

  1. nandflash_<board name>.bin at Dataflash address 0x0
  2. u-boot.bin at NAND flash address 0x20000