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).
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.
For this example you will need the following:
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.
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.
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.
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.
DEVICE | PART NUMBER | PAGE SIZE | BLOCK SIZE |
---|---|---|---|
DM644x | K9F1208R0B | 0x200 | 0x4000 |
DM355 | MT29F16G08FAA | 0x800 | 0x20000 |
DM355 | MT29F4G08AAA | 0x800 | 0x20000 |
DM6467 | NAND01GW3B2AZA6 | 0x800 | 0x20000 |
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
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.
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.
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.
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.
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.
DVEVM# saveenv DVEVM# boot
DVEVM# setenv bootargs 'mem=120M console=ttyS0,115200n8 root=/dev/hda1 rw init=/bin/sh noinitrd'