U-boot adaptation guide

Basic assumptions / scope

 * This guide is meant for converting a working u-boot to boot to mer / nemo from SD card or internal eMMC.
 * "loadaddr" environment variable is defined
 * It is assumed that you have some way of accessing u-boot console
 * Mer / Nemo / etc image with separate FAT or Ext2 boot partition and a root partition on your boot media (SD or eMMC)
 * in case of device internal eMMC you need HW specific flashing tools to transfer the image to it


 * u-boot features needed:
 * working mmc/SD card driver for your board
 * "fat load" or ext2load support (CONFIG_CMD_FAT, CONFIG_CMD_EXT2)
 * hush shell support (CONFIG_SYS_HUSH_PARSER)

Minimum path to boot
What are the absolute minimum things to get u-boot boot a linux-kernel from a SD card or eMMC for mer/nemo?

Here is the list:


 * load the kernel uImage from a disk to memory
 * fat load / ext2load / mmc load
 * start the kernel
 * bootm ${loadaddr}
 * pass right parameters to kernel in "bootargs" environment variable
 * parameters specific for the HW (typically just re-use what is there already in bootargs)
 * Mer/Nemo root FS location
 * systemd.unit=start.getty

Device Setup

 * Insert SD card with nemo image (uImage on ext2 or vfat boot partition, and rootfs on second partition)
 * Boot the device to u-boot console

u-boot environment
Then we need to setup the above minimum things in u-boot environment in place. Start with running "printenv" $ printenv bootcmd=run emmcboot bootdelay=1 baudrate=115200 verify=n rdinit=init loadaddr=0x00100000 console=ttyAMA2,115200n8 ...

Now you see what is the current environment, it's good idea to copy-paste this somewhere safe just in case you make a mess of it ;)

Generic u-boot script for booting
Now then, the steps to success were to load the kernel and boot it, so we set up a generic script to do that (copy paste below command to u-boot prompt):

setenv nemo_bootcmd 'for j in 2 1 0; do \ echo stepj $j; \ mmc rescan $j; for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19; do \ mmc rescan $j; \ if fat load mmc $j:$i ${loadaddr} /uImage; then \ bootm ${loadaddr}; \ fi; \ if fat load mmc $j:$i ${loadaddr} /boot/uImage; then \ bootm ${loadaddr}; \ fi; \ if ext2load mmc $j:$i ${loadaddr} /uImage; then \ bootm ${loadaddr}; \ fi; \ if ext2load mmc $j:$i ${loadaddr} /boot/uImage; then \ bootm ${loadaddr}; \ fi; \ echo no device found in mmc $j partition $i; \ done; \ done'

The command above sets up a new environment variable "nemo_bootcmd", that, if run, goes through mmc devices 2, 1, and 0 and tries loading uImage from partitions 1 to 25 on each of those devices. It tries to load the kernel uImage with fat load (in case it's a FAT partition) and ext2load (in case it's ext2 partition) from / and /boot/ folders (the most likely locations). If a image is found and loaded successfully it is started with the bootm command.

Setting up boot arguments for kernel
Next, before we boot, we need to make sure kernel gets right bootargs passed so it knows where the root filesystem is. On my SD card the boot partition is partition 1 and root fs partition is 2. Check what does is set for bootargs when you run "printenv". Let's say the bootargs looks like this: bootargs=cachepolicy=writealloc noinitrd hwtoolonuart= rdinit=init init=init board_id=1 crashkernel=crashkernel=1M@0x5600000 logo.nologo startup_graphics=1 root=/dev/mmcblk2p2 console=ttyAMA2,115200n8

Now there already is a "root" parameter there (root=/dev/mmcblk2p2), but it's pointing to mmc dev 2 (mmcblk2), the partition is correct (p2). With mmcinfo command I find out that my 8GB SD card is in mmc dev 1, like this

$ mmc list EMMC: 0 MMC: 1 $ mmcinfo 1 Device: MMC Manufacturer ID: 2 OEM: 544d Name: SA08G Tran Speed: 25000000 Rd Block Len: 512 SD version 2.0 High Capacity: Yes Capacity: 7973371904 Bus Width: 4-bit

So we need to change the kernel arguments to match that. Also SD cards often wakes up slowly, so additional "rootwait" parameter is needed so that kernel will wait for the SD card to appear. For systemd we also need this parameter "systemd.unit=start.getty".

So let's redefine the boot arguments with following: setenv bootargs 'cachepolicy=writealloc noinitrd hwtoolonuart= rdinit=init init=init board_id=1 \ crashkernel=crashkernel=1M@0x5600000 logo.nologo startup_graphics=1 root=/dev/mmcblk1p2 rootwait \ console=ttyAMA2,115200n8 systemd.unit=start.getty'

Boot the kernel!
Now then, everything should be set up for successfull boot. Let's try running our script:

$ run nemo_bootcmd U8500 $ run nemo_bootcmd Writing partition block (if needed)... eMMC partition block exists now MMC Device 2 not found MMC Device 2 not found ** Invalid boot device ** MMC Device 2 not found ** Invalid boot device ** MMC Device 2 not found ** Block device mmc 2 not supported MMC Device 2 not found ** Block device mmc 2 not supported no device found in mmc 2 partition 0  ....  ** Invalid boot device ** MMC Device 2 not found ** Block device mmc 2 not supported MMC Device 2 not found ** Block device mmc 2 not supported no device found in mmc 2 partition 19 ** Partition 0 not valid on device 1 ** ** Unable to use mmc 1:0 for fatload ** ** Partition 0 not valid on device 1 ** ** Unable to use mmc 1:0 for fatload ** Loading file "/uImage" from mmc device 1 Failed to mount ext2 filesystem... ** Bad ext2 partition or disk - mmc 1:0 ** Loading file "/boot/uImage" from mmc device 1 Failed to mount ext2 filesystem... ** Bad ext2 partition or disk - mmc 1:0 ** no device found in mmc 1 partition 0 Reading /uImage 4764960 bytes read Image Name:  Linux-3.0.8.20121218.2 Image Type:  ARM Linux Kernel Image (uncompressed) Data Size:   4764896 Bytes =  4.5 MB    Load Address: 00008000 Entry Point: 00008000 Loading Kernel Image ... OK OK Starting kernel ... arch 3293 Uncompressing Linux... done, booting the kernel.
 * 1) Booting kernel from Legacy Image at 00100000 ...

So now the kernel was found and booted from partition 1 of mmc dev 1 (which was my SD card). Nice!

Making it automatic for your device
The above steps were nice to get Nemo booted once, but how to make it automatic so you don't need to type in the changes above on every boot.


 * Run the steps above again, except do not run the nemo_bootcmd.

If you don't stop u-boot to command prompt during normal boot, u-boot will automatically execute the environment variable "bootcmd". Let's see what is in bootcmd now: $ printenv ... bootcmd=run emmcboot ...

On my device the default bootcmd runs another script that boots a kernel from eMMC. Let's edit this a bit to add our boot there as well:

setenv bootcmd 'run nemo_bootcmd; run emmcboot'

Now our "nemo_bootcmd" boot script will be run first. In case our boot script does not find anything to boot, the old boot command will still get executed as backup.

Lastly and most importantly, you must save the changes to flash in order for this to work automatically.

$ saveenv Saving Environment to EMMC... Writing to EMMC... done

Now reboot your device and do not interrupt u-boot for console. Congratulations, you have automatic boot setup!

Maintainers view
The previous hacker's view guide was for single device, but how about if you have a big number of devices to convert. Or you want to give easier way for (non-hacker) end-users to convert their devices to using Nemo. Next we find some ways to do that.

Creating a u-boot-env.bin

 * Assumption is that you also have access to HW specific flashing tool

The environment that you see when you run "printenv" is actually stored as part of the u-boot binary on the device flash. There is dedicated space reserved for it and it's size is defined in CONFIG_ENV_SIZE in u-boot sources (typically /include/configs/ .h).

If you have the proper flashing tools available to access the u-boot flash space, you can also create a flashable image of the environment and just write that to the devices.

The way to do that is nice host PC tool mk_envimg that comes with u-boot. You can compile it with hostcc like this: cd u-boot/tools/mk_envimg make

Now you have the tool, then you need a plain text file that has the environment. The format of the file is same as what you get with printenv, so run printenv on your device: $ printenv bootdelay=1 baudrate=115200 ..

Then just copy paste what was printed to the console to a text file my-env.txt. If you already did the hacker's view guide above, you should already have all right parameters there. But for certainty, please check and if missing add the same changes. The nemo_bootcmd can be copy pasted from below if missing:

nemo_bootcmd=for j in 2 1 0; do mmc rescan $j; for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19; do if fat load mmc $j:$i ${loadaddr} /uImage; then bootm ${loadaddr}; fi; if fat load mmc $j:$i ${loadaddr} /boot/uImage; then bootm ${loadaddr}; fi; if ext2load mmc $j:$i ${loadaddr} /uImage; then bootm ${loadaddr}; fi; if ext2load mmc $j:$i ${loadaddr} /boot/uImage; then bootm ${loadaddr}; fi; echo no device found in mmc $j partition $i; done; done

Then, the last step is to just create the flashable u-boot-env.img

tools/mk_envimg/mk_envimg u-boot-env.bin my-env.txt

Now you have a flashable u-boot-env.bin, which you can flash with the flash tools to the u-boot environment location on eMMC and make them boot nemo.

Automating env-image creation to OBS
To build automatically the environment binary in OBS you need to:
 * Add my-env.txt to your board's u-boot package source (u-boot source root folder expected in this example)
 * following changes to your spec file:

make -C tools/mk_envimg %{?jobs:-j%jobs} tools/mk_envimg/mk_envimg u-boot-env.bin my-env.txt
 * Under %build
 * 1) Additional tools


 * Under %install

install -m 644 u-boot-env.bin %{buildroot}/boot install -m 755 tools/mk_envimg/mk_envimg %{buildroot}%{_bindir}


 * Under %files

/boot/u-boot-env.bin

%{_bindir}/mk_envimg
 * Under %files tools

Now when you build your OBS package, a environment binary will be created. And if you include u-boot to your mic image, you can find the environment binary from the Nemo SD card boot partition and take it from there for the flasher.


 * Also MIC can be configured to extract the u-boot-env.bin from the image to the build folder, so you get a downloadable image automatically from build machinery

eMMC boot
If you have a valid ext2 or fat filesystem in the eMMC boot partition, the generic SD card script will find your uImage also from eMMC, so nothing special is needed in that case.