Bootstrapping the OpenGlow


#1

Bootstrapping

Taking an embedded system from power-on-reset to a running operating system seems like a simple task. In practice, it can be surprisingly complex, and If you are new to embedded systems, the learning curve can be rather steep. In this post, I’ll try to demystify some of what of happens.

The OpenGlow uses the i.MX6 family, with the prototype carrying an i.MX 6Dual processor. There are a few subtleties between processors that are beyond the focus of this post, so we’ll focus only on the 6Dual/6Quad and only as it relates to the Boundary Devices (BD) SOM v2.

i.MX6 Boot ROM

When the processor’s reset logic detects a Power-On-Reset, it starts the execution of the on-chip boot ROM code. This code handles boot device selection, loading of the bootloader code into RAM, and hands off execution to the CPU.

Mode Selection
The boot ROM reads the state of two external pins (BOOT_MODE[1:0]) to determine how it should proceed. BD has tied the pin for BOOT_MODE[1] low, and given us a switch (SW1) to determine the state of BOOT_MODE[0]. This leaves us with two boot options: eFUSEs and Serial Downloader (USB OTG port):

BOOT_MODE[1:0] Boot Mode SW1
00 From eFUSEs OFF
01 Serial Downloader ON
10 Internal N/A
11 Reserved N/A

The eFUSEs are one-time-programmable registers that control the primary boot device. This device can be set to NOR Flash, NAND Flash, OneNAND Flash, SD/MMC, SATA, or Serial NOR Flash/EEPROM (SPI or I2C). BD has taken the liberty to pre-program these to boot from the on-board SPI Serial NOR Flash.

The Serial Downloader is a protocol that allows the bootloader, flattened device tree, and kernel images to be transferred over a special USB serial connection. This is useful for bringing up a green processor, and a handy way to de-brick the device should a bootloader upgrade go sideways.

BD also pre-programmed the NOR Flash with their own bootloader that expects the SOM to be mounted on one of their carrier boards, so it won’t boot properly on the OpenGlow board without some extra work. More on that later…

Loading the Bootloader
Simply: The boot ROM loads the bootloader image from the Serial NOR Flash into RAM, and tells the processor to execute the code. In our case, that bootloader image is U-Boot. It’s only slightly more complex than that, and those complexities don’t really impact us, so I’ll leave them out.

Das U-Boot

Like so many things in the embedded world, U-Boot started out as a simple bootloader with one job: Start the operating system. It has since grown into a complex beast that can perform an insane amount of functions. For our purposes, we’re limiting it to some very basic functions.

Hardware Initialization

When U-Boot first executes, it does some very basic hardware setup. These include setting some important RAM timings, configuring additional storage devices, and setting the states of some key I/O ports. I’ll cover all of these in a future post that details the customization of U-Boot for OpenGlow.

One of those configured devices is the serial console. Once that is initialized, we get to see what’s happening behind the scenes:

U-Boot 2018.01-dirty (Feb 21 2018 - 12:01:26 -0500)

CPU:   Freescale i.MX6D rev1.2 at 792 MHz
Reset cause: POR
Board: OpenGlow STD Prototype 1
DRAM:  1 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
SF: Detected sst25vf016b with page size 256 Bytes, erase size 4 KiB, total 2 MiB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot:  0 

Load Kernel and FDT
Next, U-Boot looks for the boot device we have configured: currently SDHC device 0, partition 0, which is the removable SD card slot on the OpenGlow board. From that device, it will load the kernel and the flattened device tree into RAM:

reading openglow_std.dtb
44641 bytes read in 19 ms (2.2 MiB/s)
reading zImage
5960032 bytes read in 294 ms (19.3 MiB/s)

and finally, it will execute the kernel:

Kernel image @ 0x12000000 [ 0x000000 - 0x5af160 ]
## Flattened Device Tree blob at 13000000
   Booting using the fdt blob at 0x13000000
   Loading Device Tree to 4f584000, end 4f591e60 ... OK

Starting kernel ...

There you have it, in a nutshell…

In my next post, we’ll take a more detailed look at U-Boot, how to create a custom board package, and how to install it on the OpenGlow board.