The AM335X contains ROM code that can load a bootloader from external memory such as the on-board eMMC. On reset, this ROM code searches for the bootloader and then copies it to the internal RAM before executing it. The internal RAM on the AM335X is 128KB, but due to various limitations, only 109KB is available for the initial bootloader for program memory, heap and stack.
A fully featured version of U-Boot can be over 400KB, hence it is not possible to load this immediately. For this reason, a cut down version of U-Boot called U-Boot SPL (Second Program Loader) is loaded first, and once it has initialised the CPU, it chain loads a fully featured version of U-Boot (u-boot.img).
By default, the ROM code in the Sitara AM3359 will boot from the MMC1 interface first (the onboard eMMC), followed by MMC0 (external uSD), UART0 and USB0.
If the boot switch (S2) is held down during power-up, the ROM will boot from the SPI0 Interface first, followed by MMC0 (external uSD), USB0 and UART0. This allows the BeagleBone Black to bypass the onboard eMMC and boot from the removable uSD (provided no valid boot device is found on SPI0.) This can be used to recover from a corrupted onboard eMMC/U-Boot.
The ROM code will try to load and execute the first stage bootloader called "MLO" (U-Boot SPL) from a Fat 12/16 or 32 bit MBR based filesystem. Alternatively, if using eMMC, the bootloader can be loaded using RAW mode.
Early BeagleBone Black images included MLO (and u-boot.img) on a FAT file-system in the root directory of the active primary partition. The card would contain two partitions, a FAT32 partition and Linux ext3/4. The full/second stage U-Boot would contain hard-coded environment variables to load uEnv.txt as the environment variables couldn't be saved using saveenv.
In more recent times, the RAW mode has been adopted. In RAW mode, the ROM code will search sector #0 (offset 0x00000), sector #256 (0x20000), sector #512 (0x40000) and sector #768 (0x60000) for a TOC structure/Configuration Header.
If you still want to use the MMC as a disk, then it must have a Master Boot Record (MBR) containing one or more partition table entries at 0x00000. This prevents placing U-Boot SPL/MLO there. As the ROM Code will search four sectors, it makes sense to place U-Boot SPL/MLO at 0x20000 (sector #256).
U-boot SPL can then load the fully featured U-Boot second stage bootloader at 0x60000. One of the advantages of running U-Boot from block memory is the environment variables can be stored. This method means you can now modify and save the environment variables, negating the need to load uEnv.txt.
Don't panic that you are encroaching into partitions on the disk. Most primary partitions will start at sector 2048, and with 512B per sector you have an entire 1MB to play with:
Disk /dev/sdb: 7.4 GiB, 7948206080 bytes, 15523840 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x00000000 Device Boot Start End Sectors Size Id Type /dev/sdb1 * 2048 198655 196608 96M e W95 FAT16 (LBA) /dev/sdb2 198656 7577599 7378944 3.5G 83 Linux
Download the latest version of U-Boot, extract the files to a working folder and patch:
wget ftp://ftp.denx.de/pub/u-boot/u-boot-latest.tar.bz2 tar -xjf u-boot-latest.tar.bz2 cd u-boot-2015.10 wget https://rcn-ee.com/repos/git/u-boot-patches/v2015.10/0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch patch -p1 < 0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch
Now cross compile U-Boot using the am335x BeagleBone Black configuration:
make CROSS_COMPILE=arm-linux-gnueabihf- distclean make CROSS_COMPILE=arm-linux-gnueabihf- am335x_boneblack_config make CROSS_COMPILE=arm-linux-gnueabihf-
Compiling should conclude with output similar to below showing that an image of MLO - the first stage uBoot Bootloader is generated.
LD spl/u-boot-spl OBJCOPY spl/u-boot-spl.bin MKIMAGE MLO CFG spl/u-boot-spl.cfg
Scrolling up the output messages, you should find where the second stage U-Boot bootloader (u-boot.img) is generated.
LDS u-boot.lds LD u-boot OBJCOPY u-boot.bin MKIMAGE u-boot.img OBJCOPY u-boot.srec CFG u-boot.cfg
If desired, you can test the second stage bootloader by loading it to RAM:
setenv ipaddr 192.168.0.250 setenv serverip 192.168.0.251 tftp 0x80800000 u-boot.bin go 0x80800000
Copy the files to the start of the uSD Card (/dev/sdb) or MMC Flash (/dev/mmcblk0):
dd if=MLO of=/dev/mmcblk0 bs=512 seek=256 count=256 conv=notrunc dd if=u-boot.img of=/dev/mmcblk0 bs=512 seek=768 count=1024 conv=notrunc
If you are writing to removable uSD Card, you can finish by flushing the cache with:
sudo blockdev --flushbufs /dev/sdb
As you can now modify & save the environment variables within U-Boot, this is an example of my setup loading an image from TFTP and booting to a NFS root filesystem.
Run the following commands within U-Boot:
setenv fdtaddr 0x80F80000 setenv loadaddr 0x80007fc0 setenv ipaddr 192.168.0.250 setenv serverip 192.168.0.251 setenv loadfdt 'tftpboot ${fdtaddr} am335x-boneblack.dtb' setenv loadimage 'tftpboot ${loadaddr} uImage-BBB' setenv bootargs 'console=ttyO0,115200n8 root=/dev/nfs rw nfsroot=192.168.0.251:/home/cpeacock/export/rootfs ip=192.168.0.250:::::eth0' setenv bootcmd 'run loadimage; run loadfdt; bootm ${loadaddr} - ${fdtaddr}'
Save your changes:
saveenv
Holding down S2 enables booting from the MMC0 interface (uSD Card). If you wish to always boot from the uSD Card, you can erase the contents of the on-board MMC. The ROM code will attempt to load a bootloader from the on-board MMC and fail over to the next interface, the uSD Card.
From U-Boot, erase the contents of the on-board MMC by executing:
U-Boot# mmc erase 0 1000 MMC erase: dev # 1, block # 0, count 4096 ... 4096 blocks erased: OK
By default, U-Boot will attempt to load/store environment variables from MMC Device 1 (On-board MMC), Part 2.
This is specified in include/configs/am335x_evm.h:
#elif defined(CONFIG_EMMC_BOOT) #undef CONFIG_ENV_IS_NOWHERE #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SPL_ENV_SUPPORT <B>#define CONFIG_SYS_MMC_ENV_DEV 1 #define CONFIG_SYS_MMC_ENV_PART 2</B> #define CONFIG_ENV_OFFSET 0x0 #define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) #define CONFIG_SYS_REDUNDAND_ENVIRONMENT #endif
If you move your uSD Card between BeagleBones, it may be advantageous to store the environment area on the uSD card.
To enable this, modify the above block of defines found in include/configs/am335x_evm.h to:
#elif defined(CONFIG_EMMC_BOOT) #undef CONFIG_ENV_IS_NOWHERE #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SPL_ENV_SUPPORT #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_ENV_OFFSET 0xE0000 #endif
and recompile.