Writing Kernel Image to NAND Flash

From Texas Instruments Wiki
Jump to: navigation, search

Writing Kernel Image to NAND Flash

Often times it is useful to write the image of the kernel for your device into a permanent storage media such as NAND flash. This eliminates the need to download the kernel image each time the system is booted. Below you will find steps on how to write a previously compiled kernel image into NAND flash on the following DaVinci EVMs(DVEVM).

  • DM355
  • DM644x
  • DM6467

Note: This article assumes that you already have U-Boot running on the target. If not, e.g. your board is completely empty, see the RBL, UBL and host program article for instructions on how to get U-Boot bootloader on your board first. After you did this and have U-Boot running on your board, you can go on with steps below.

Alternatively, you can program your NAND flash with JTAG. This is useful for post mortem / rejuvenation of bricked NAND images, especially if you can't change the boot device select pins easily.

Prerequisites

For this example you will need the following:

  1. A previously compiled kernel image (uImage)
  2. A tftp server for downloading the image
  3. A terminal application for communicating with the DVEVM. i.e. minicom or hyperterminal

Downloading the Kernel Image to the DVEVM

This section assumes that you have a kernel image (uImage) already compiled. For information on compiling the Linux kernel for the DVEVM please see the Getting Started Guide (GSG) for your product (section 4.5) or compiling DaVinci open source git kernel. The commands specified below with the "DVEVM#" prompt are performed at the u-boot prompt.

  • Copy the kernel image to the /tftpboot directory
   host$ cp <path to kernel image>/uImage /tftpboot

NOTE: If your tftp directory is not the default tftpboot please replace tftpboot above with the proper directory.

  • Download the Linux kernel image via TFTP
   DVEVM# setenv serverip <tftp server ip address>
   DVEVM# setenv bootfile uImage
   DVEVM# dhcp

You should see output like the following:

   BOOTP broadcast 1
   DHCP client bound to address <dvevm ip address>
   TFTP from server <tftp server ip address>; our IP address is <dvevm ip address>
   Filename 'uImage'
   Load address: 0x80700000
   Loading:
   ######################################################################################
   ######################################################################################
   .
   .
   .
   ######################################################################################
   #######################################################
   done
   Bytes transferred = 1397368 (155278 hex)

The dhcp command obtains IP settings and then downloads the Linux kernel image (as specified by the serverip and bootfile environment variables). Make a note of the Load address (0x80700000) and Bytes transferred (0x155278), as these are needed in the following steps.

Preparing to Write the Kernel Image

Since the NAND flash requires that I/O operations be done in increments of page size you must round up the size of your kernel to the next full page in order for the reads and writes to succeed.

The below example is based on the DM644x. For other EVMs it will be necessary to adjust the page sizes and write locations.

  • Determine the page size of your NAND flash. You can find this in the manufacturer datasheet for your NAND device. The table below also has the block and page sizes for the NAND devices on the DaVinci EVMs.
DaVinci EVM NAND Chips
DEVICE PART NUMBER PAGE SIZE BLOCK SIZE
DM644x K9F1208R0B 0x200 0x4000
DM355 MT29F16G08FAA 0x800 0x20000
DM355 MT29F4G08AAA 0x800 0x20000
DM6467 NAND01GW3B2AZA6 0x800 0x20000


  • Calculate the number of pages to be erased and written by rounding the kernel image size up to next page. For example:
    Kernel size = 0x155278
    Number of pages = 0x155278/0x200 = AA9.3C rounded up = 0xAAA
    Rounded size = <number of pages> * <page size> = 0xAAA * 0x200 = 0x155400
NOTE: Sometimes the NAND device may not like the Roundded size = <number of pages > * <page size>. Instead do the calculation in the following way.
: Kernel size = 0x155278
: Number of BLOCKS (or SECTORS) = 0x155278/0x4000 = 55.49E  ~= 56 BLOCKS (SECTORS)
: Rounded size = <number of blocks> * <size of a block> =  0x56 * 0x4000 = 0x158000
NOTE:  If you have the space available in the NAND flash you can always round up to the next block (sometimes called sector) which is always a
multiple of the page size.  To determine the block size you can use the nand info command in u-boot.

   DVEVM# nand info

You should see output like the following:

   Device 0: Samsung K9K1208Q0C at 0x2000000 (64 MB, 16 kB sector)

The sector size is listed at the end of the output from the nand info command. 

In this example the sector size is 16 kB which is 0x4000. So the following calculation can be done:

Kernel size = 0x155278
Number of sectors = 0x155278/0x4000 = 0x55.49E rounded up = 0x56
Rounded size = <number of sectors> * <sector size> = 0x56 * 0x4000 = 0x158000
  • Erase the flash where the kernel is to be written using the rounded size calculated in the previous step. For each device, the kernel is written to different locations in flash. Use the table below to determine where the kernel image will be placed.


KERNEL OFFSET
DEVICE OFFSET
DM644x 0x2060000
DM355 0x400000
DM6467 0xa0000


   DVEVM# nand erase 0x2060000 0x155400

You should see output like the following:

   NAND erase: device 0 offset 393216, size 1397760 ... OK

Here the amount to erase is the size of the kernel rounded up to the next sector which was calculated above. The offset 0x2060000 was chosen to allow the first sectors to be used for the ubl and u-boot boot loaders. You MUST erase the NAND flash before writing to it.

Writing the Kernel Image into NAND Flash

Now that the NAND flash where the kernel image will be stored has been erased it is time to write the kernel image into the flash memory.

   DVEVM# nand write 0x80700000 0x2060000 0x155400

You should see output like the following:

   NAND write: device 0 offset 393216, size 1397760 ... 1397760
   bytes written: OK

The nand write command will take the image stored at 0x80700000 (this is where the kernel was downloaded above) and write 0x155400 bytes to the NAND flash at address 0x2060000.

Updating a kernel from a linux prompt

If you want to be able to update your kernel or uboot image in NAND (I'm using a DM355 platform, but this should work for others) *while* your system is running and without the use of a JTAG device, these are the commands that can be used to do this:

   /usr/sbin/flash_eraseall -j /dev/mtd2
   /usr/sbin/nandwrite -p /dev/mtd2 uImage

An example:

   root@(none):~# /usr/sbin/flash_eraseall -j /dev/mtd2
   Erasing 128 Kibyte @ 3e0000 -- 96 % complete. Cleanmarker written at 3e0000.
   root@(none):~# nandwrite -p /dev/mtd2 uImage
   Writing data to block 0
   Writing data to block 20000
   Writing data to block 40000
   Writing data to block 60000
   Writing data to block 80000
   Writing data to block a0000
   Writing data to block c0000
   Writing data to block e0000
   Writing data to block 100000
   Writing data to block 120000
   Writing data to block 140000
   Writing data to block 160000
   Writing data to block 180000

This example updates the kernel. It is assumed that /dev/mtd2 is your NAND kernel partition. Uboot would be /dev/mtd0. To find the existing NAND partitions:

   root@(none):~# cat /proc/mtd
   dev:    size   erasesize  name
   mtd0: 003c0000 00020000 "bootloader"
   mtd1: 00040000 00020000 "params"
   mtd2: 00400000 00020000 "kernel"
   mtd3: 20000000 00020000 "filesystem1"
   mtd4: 1f800000 00020000 "filesystem2"

Also if you see any bad blocks during the erase operation you'll need to make sure they don't occur in the middle of your kernel code. It seems that the bootloader doesn't understand bad blocks and will NOT skip them. So you need to have a contiguous set of good blocks for your kernel or you will see a CRC failure message when booting.

Setting u-boot to Boot the Kernel from NAND Flash

You must now tell u-boot to boot the kernel image stored in NAND flash. This means that u-boot will copy the kernel image from NAND flash into DDR memory and then boot the kernel.

  • Setting the bootcmd environment variable
   DVEVM# setenv bootcmd 'nboot 80700000 0 2060000; bootm'

The nboot command will copy the kernel image at 0x2060000 on device 0 to address 0x80700000 in DDR. The bootm command will then boot the image located in memory at address 0x80700000.

  • The system is now ready to boot the kernel from NAND Flash so save the environment variables and boot.
   DVEVM# saveenv
   DVEVM# boot
  • Note: If you have issues with the Kernel panicking because it cannot find the ROMDISK, try noinitrd:
   DVEVM# setenv bootargs 'mem=120M console=ttyS0,115200n8 root=/dev/hda1 rw init=/bin/sh noinitrd'