How To Boot from NAND Flash on the Freescale i.MX25 PDK
Table of Contents
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 the Freescale i.MX25 PDK.
Prerequisites
- Kernel uImage with the following configuration options enabled:
- CONFIG_MTD_PARTITIONS=y
- CONFIG_MTD_CMDLINE_PARTS=y (optional)
- CONFIG_MTD_OF_PARTS=y
- CONFIG_MTD_BLOCK=y
- CONFIG_MTD_NAND=y
- CONFIG_MTD_NAND_FSL_ELBC=y
- 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 RFS Images
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:
MXC MTD nand Driver 2.5 NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB 3,3V 8-bit) Searching for RedBoot partition table in NAND 2GiB 3,3V 8-bit at offset 0x7fec0000 No RedBoot partition table detected in NAND 2GiB 3,3V 8-bit Creating 5 MTD partitions on "NAND 2GiB 3,3V 8-bit": 0x00000000-0x00100000 : "nand.bootloader" 0x00100000-0x00600000 : "nand.kernel" 0x00600000-0x10600000 : "nand.rootfs" 0x10600000-0x10e00000 : "nand.configure" 0x10e00000-0x80000000 : "nand.userfs"
Based on this, you can determine the partition scheme of the device. The line
0x000000000000-0x000000100000
states that the first partition begins at offset 0 from the start of NAND, and continues until address 0x100000, giving it a size of 0x100000 bytes.
The second partition starts at 0x100000 and is 0x500000 bytes long.
The partitions are numbered in the order that they are detected, starting at 0. In the above example, there are 5 partitions on 1 NAND chip. This is the default configuration in the Timesys-provided kernel.
Device Number | Device | Offset | Size | Name |
---|---|---|---|---|
mtd0 | NAND | 0x000000000000 | 0x00100000 | nand.bootloader |
mtd1 | 0x000000100000 | 0x00500000 | nand.kernel | |
mtd2 | 0x000000600000 | 0x10000000 | nand.rootfs | |
mtd3 | 0x000010600000 | 0x00800000 | nand.configure | |
mtd4 | 0x000010e00000 | 0x6f200000 | nand.userfs |
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: 00100000 00040000 "nand.bootloader" mtd1: 00500000 00040000 "nand.kernel" mtd2: 10000000 00040000 "nand.rootfs" mtd3: 00800000 00040000 "nand.configure" mtd4: 6f200000 00040000 "nand.userfs"
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. mtd4), 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.
For this document, we will use the following scheme:
mtd1 | kernel |
mtd2 | RFS |
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 nand sections in the board specific file in arch/arm/mach-mx25.
Writing Kernel and Device Tree to NAND Flash
You can write the kernel and device tree to NAND flash using a number of methods. The simplest way may be to use your JTAG debugger. However, since there are a number of JTAG solutions available, you should consult the documentation for your setup to determine the method for writing these files to flash.
If you do not have a JTAG environment set up, you can use Redboot to write the kernel and device tree to NAND. The Redboot NAND routines are bad-block safe, which means they will automatically account for (and skip) bad blocks. The basic method for writing a file to NAND is to erase the region that you wish to write to, transfer your file into RAM, then write the file to NAND.
Writing the Kernel
- Erase the NAND chip using the fis init command. This will erase all content on the flash chip except for the bootloader and bootloader configuration.
RedBoot> fis init About to initialize [format] FLASH image system - continue (y/n)? y *** Initialize FLASH Image System ... Erase from 0x000c0000-0x00100000: . ... Program from 0x03ec0000-0x03f00000 at 0x000c0000: ..
- Transfer the kernel file to RAM address 0x100000 using TFTP.
RedBoot> load -r -b 0x100000 <kernel_image>
- Write the image to NAND using the fis create command.
RedBoot> fis create -f 0x100000 kernel ... Read from 0x03ec0000-0x03eff000 at 0x000c0000: .. ... Read from 0x03ec0000-0x03eff000 at 0x000c0000: .. ... Read from 0x03ec0000-0x03eff000 at 0x000c0000: .. ... Erase from 0x00100000-0x00300000: ........ ... Program from 0x00100000-0x002dddac at 0x00100000: ......... ... Erase from 0x000c0000-0x00100000: . ... Program from 0x03ec0000-0x03f00000 at 0x000c0000: ..
Example
We are using mtd1 for our kernel, which corresponds to offset 0x100000 from the beginning of NAND.
RedBoot> fis init RedBoot> load -r -b 0x100000 zImage-2.6.28-ts-armv5l RedBoot> fis create -f 0x100000 kernel
Writing RFS to NAND Flash
You can write the RFS to NAND flash using a number of methods. The easiest is using your JTAG, although we do not provide instructions for how to do this. Instead, please consult your JTAG documentation for help. The easiest way to write an RFS to NAND without the aid of a JTAG is to use a kernel booted with an NFS-based RFS.
Using RedBoot
NOTE: Since RedBoot can only write to NAND directly from RAM, you can only use RedBoot if your filesystem is smaller than the available RAM.
You write the file system in the same manner as the kernel and device tree. Just pick a different NAND offset.
Example
We are using mtd2 for our RFS, which corresponds to offset 0x600000 from the beginning of NAND.
RedBoot> load -r -b 0x100000 rootfs.jffs2 RedBoot> fis create -f 0x600000 rfs
Using the Kernel
NOTE: Your NFS-based RFS must have mtd-utils installed in order to modify flash from userspace.
- On the host machine, copy your flash image into your NFS directory.
- On the target machine, boot Linux into an NFS-based RFS.
- Erase the NAND partition that you wish to use using the flash_eraseall command
# flash_eraseall /dev/mtdN
Where N is the partition number that you wish to erase. - Write your image to flash using the nandwrite command
# nandwrite /dev/mtdN <image path>
Example
We are using mtd2 for our RFS, which corresponds to offset 0x600000 from the beginning of NAND.
# flash_eraseall /dev/mtd2 # nandwrite /dev/mtd2 /rootfs.jffs2
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.
- Copy the kernel into RAM using the nand read command:
RedBoot> fis load kernel
This command will read the image stored in the kernel section of NAND flash, as determined by the fis create command used earlier. - Set the kernel command line to boot from NAND flash:
=> setenv bootargs console=ttyS0,115200 rootfstype=jffs2 root=/dev/mtdblockN rw
- Boot the kernel using the exec command.
U-Boot> exec -c "console=ttymxc0,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.
Example
RedBoot> fis load kernel RedBoot> exec -c "console=ttymxc0,115200 rootfstype=jffs2 root=/dev/mtdblock2 rw"