Booting up a modern microprocessor is more like a journey than a recipe. The Texas Instruments Sitara AM3358 processor, powering the BeagloBone Black is no different.

The journey starts when the Power Management IC brings up the different voltage lines of the CPU in the correct order. The CPU initialises itself and starts executing its ROM bootloader code.

The ROM bootloader reads in the status of the 16 SYSBOOT pins. According to the BeagleBone Black’s System Reference Manual (section 6.7.1, local copy), the board has these pins wired to 0b01 00 00 0 0 00 1 11100, but pin SYSBOOT[2] can be pulled down by pushing S2. The Technical Reference Manual (section, local copy) will tell you the important difference between these 2 options is mainly the boot sequence:

  • Normal mode: MMC1, MMC0, UART0, USB0
  • With S2 pushed: SPI0, MMC0, USB0, UART0

Since the BeagleBone’s eMMC is connected to MMC1 (cfr BBB SRM section 6.4.2), and the micro SD card slot to MMC0, S2 effectively allows you to skip the eMMC when booting, and boot straight from SD.

The bootloader will (cfr section of the TRM) read 4 sectors (sector nr 0, 256, 512 and 768) and look for a TOC structure. If found, it will load the next bootloader from there. If this fails, the bootloader looks for an active primary FAT12/16 or FAT32 partition in the MBR partition table, and tries to load a file named MLO (which seems to stand for Mmc LOader) from the root directory. This next bootloader, usually U-Boot’s Second Program Loader, then takes over. The ROM bootloader provides some information about the boot (e.g. which device is currently booted from), but it’s up to this new bootloader to use this info.

What actually happens

You can see what actually happens by connecting to the BBB with a TTL-level (3.3V) RS232 adapter. The J1 connector (6 pins, above the P9 header) is connected to UART0 as follows:

  • pin 1 (marked with a dot): GND
  • pin 4: Rx (i.e. to BBB)
  • pin 5: Tx (i.e. from BBB)

The (default) parameters are 115200 baud, 8 databits, no parity, 1 stopbit. I use kermit to provide a terminal emulator on a second device (but other options are possible).

The boot-up of the build-in eMMC starts off like this:

U-Boot SPL 2014reading args
spl_load_image_fat_os: error reading image args, err - -1
reading u-boot.img
reading u-boot.img

This looks like the SPL loading the 3rd stage bootloader (located in u-boot.img). The 2nd stage bootloader (the MLO file) needs to fit in on-chip RAM (slightly over 100kB usable), which is not enough for a full fledged boot-loader, hence this split in 2 (additional) stages. The boot goes on:

U-Boot 2014.04-00014-g47880f5 (Apr 22 2014 - 13:23:54)

I2C: ready
DRAM: 512 MiB
*** Warning - readenv() failed, using default environment

Net:  not set. Validating first E-fuse MAC
cpsw, usb_ether
Hit any key to stop autoboot: 0
gpio: pin 53 (gpio 53) value is 1
Card did not respond to voltage select!
mmc0(part 0) is current device
Card did not respond to voltage select!
gpio: pin 56 (gpio 56) value is 0
gpio: pin 55 (gpio 55) value is 0
gpio: pin 54 (gpio 54) value is 0
mmc1(part 0) is current device
gpio: pin 54 (gpio 54) value is 1
SD/MMC found on device 1
reading uEnv.txt
1709 bytes read in 7 ms (238.3 KiB/s)

This looks like U-Boot tries to boot of MMC0 (the SD-card slot) first, even though the ROM-bootloader choose MMC1 first. Since there is no SD-card inserted, this fails, and U-Boot continues on to MMC1 (the on-board eMMC), where it reads the uEnv.txt file.

Note that in this setup, U-Boot runs its compiled-in boot script. So overriding the bootcmd variable in uEnv.txt is useless, since it’s loaded too late. The default boot script loads this uEnv.txt file, and executes the uenvcmd variable, if defined. So you can use that variable to customise your boot.