U-Boot conventions for i.MX6 (Nitrogen6X and SabreLite)

A little convention make things easy to use, but only if you know the convention.

In this blog post, we’ll explain three key environment variable conventions used on the Nitrogen6X (and Sabre Lite before it).

For the impatient:

  • Both of these devices ship with U-Boot configured to load and run a boot script named 6q_upgrade from the root of either SD card.
  • A pre-configured command upgradeu can be used to upgrade U-Boot in serial flash
  • Another pre-configured command clearenv will erase the environment variables in serial flash.

For those that want an explanation:

Both of these boards boot to SPI EEPROM (serial flash), and both U-Boot and its’ environment variables are stored there.

Convention for many modern ARM boards, including i.MX in recent years has been to boot directly to SD card, either by using unformatted areas of the disk or carefully placing special files in prescribed areas of a filesystem.

We jokingly refer to this as a game of “Hide the U-Boot”, and don’t want to play.

Instead, we added a serial flash chip and store the boot loader there. The flash device size is 2MB, which is plenty of space for the boot loader and environment, but not enough for a complete O/S, and we defer that to SD card, which brings us to the first environment variable:

bootcmd

We’ve pre-configured the bootcmd environment variable to load and launch a boot script from the root directory of either SD card slot by using the looping features of the Hush parser:

for disk in 0 1 ; do
	mmc dev ${disk} ;
        for fs in fat ext2 ; do
                ${fs}load mmc ${disk}:1 10008000 /6q_bootscript &&
                source 10008000 ;
        done ;
done

If you’re not familiar with U-Boot boot scripts, we wrote a backgrounder in this blog post.

To make compiling boot scripts a bit easier, we created a web-based tool to compile them for you. There’s also a bash snippet to make this easy from the command-line.

upgradeu

Once you’re running U-Boot from serial EEPROM, the question is how do you upgrade it?

The easy answer is that you ask U-Boot to do it:

MX6Q SABRELITE U-Boot > run upgradeu
...bunch of debug spew
## Executing script at 10008000
check U-Boot
Loading file "u-boot.bin" from mmc device 1:1 (xxb1)
179632 bytes read
...more debug spew...
SUCCESS
Total of 179632 bytes were the same
------- U-Boot versions match

If it’s not entirely obvious to you what this example illustrated, let’s dig a little deeper.

If you run print at the U-Boot prompt, you’ll see that upgradeu is defined to contain some U-Boot commands:

MX6Q SABRELITE U-Boot > print
bootdelay=3
...
upgradeu=for disk in 0 1 ; do mmc dev ${disk} ;for fs in fat ext2 ; do ${fs}load mmc ${disk}:1 10008000 /6q_upgrade && source 10008000 ; done ; ...
Environment size: 908/8188 bytes

That’s a pretty long command-line, but is essentially the same loop as we described in the bootcmd section of this post. It will try to read a script named 6q_upgrade from either SD card using either the FAT or ext2/3/4 filesystem and source it. The source command simply executes a boot script.

If you’ve followed along this far, you may have just realized that we haven’t really followed either the full boot path or the upgrade path because we’ve waved our hands over what the script does. We’ll address that in a later section.

clearenv

The final convention may be the most useful for the programmer. If a Sabre Lite or Nitrogen6X board spends much time on your desk, you’ll invariably set something in the U-Boot environment. Perhaps you’re bypassing all of these conventions and booting over NFS (the topic of another blog post). Maybe you’re booting to a SATA drive or a USB stick or tweaking some kernel parameters.

If so, you may ultimately want to put things back the way you found them before you hand the device off to someone else. If you know the layout of the serial EEPROM, you can simply erase the sector(s) containing the environment variables and go back to the compiled-in defaults.

I’m assuming you don’t (know or remember the flash layout) because I don’t and I helped come up with it. This is where the clearenv variable or command comes into play. Going back to the print example will tell you:

MX6Q SABRELITE U-Boot > print
bootdelay=3
...
clearenv=sf probe 1 && sf erase 0xc0000 0x2000 && echo restored environment to factory default
...
Environment size: 908/8188 bytes

Aha! The environment is stored at offset 0xc0000 (768k) and is 0x2000 (8192) bytes long!

And if you want to clear it, you can simply run run clearenv from the shell.

The gory details


Unless you’re as much of a U-Boot geek as I am, you’re probably wishing you’d stopped at the for the impatient section, but you may someday need the details, so I’m going to describe a handful of additional things that will help in the use and deployment of boot scripts for your use.

To begin with, I promised the details of the boot script itself, but I lied.

I can’t really give that to you because the things needed really depend on your environment. If you’ve spent time with various embedded Linux distributions, you’ll find that many of them require different sorts of kernel command-line parameters. Also, some distributions, like Android require the use of a RAM disk, but others don’t. These differences (additions) are best expressed in the actual userspace image, so we add them there.

Here’s an example of what we shipped on SabreLite boards with Ubuntu:

Ubuntu boot script

set bootargs $bootargs root=/dev/mmcblk0p1 rootwait fixrtc ;
ext2load mmc ${disk}:1 10800000 /boot/uImage && bootm 10800000 ;
echo "Error loading kernel image"

If you look closely, you’ll see that it’s adding a couple of things to the bootargs environment variable, then loading the kernel from /boot/uImage and booting it using bootm and that it’s printing an error message in case something fails. The bootm command will normally not return.

Also note that this script uses the disk variable that was defined in the loop from which it was called, so the boot script must reside on the same disk as the kernel.

Android boot script

Here’s another example of loading Android ICS on an i.MX6:

${fs}load mmc ${disk}:1 10800000 uimage &&
${fs}load mmc ${disk}:1 12800000 uramdisk.img &&
bootm 10800000 12800000 ;
echo "Error loading kernel image"

This one doesn’t add anything to the bootargs, and uses the && operators liberally, but the primary thing it does differently from the Ubuntu script is load a ram disk (uramdisk.img). It also uses the fs parameter from the calling loop in the same way the Ubuntu script used the disk variable.

A lot more could be done inside this boot script. The Android boot script could (and probably should) handle recovery mode. Both of them should probably loop in the case of errors, although we don’t yet have display support in i.MX6 U-Boot.

We should also add support for SATA into our default environment, but those are topics for another day and perhaps another blog post.

Upgrade script

The content of the 6q_upgrade script is a little more complex, but shouldn’t be too surprising. It tries to load a file named u-boot.bin from the same partition in which the script was found and compares it against the content of the serial EEPROM. If the two are different, it will wait for 10 seconds before (re)programming the flash to match the content of the SD card. It will also perform a verification pass before telling you that things are good:

echo "check U-Boot" ;
if ${fs}load mmc ${disk}:1 12000000 u-boot.bin ; then
      echo "read $filesize bytes from SD card" ;
      if sf probe 1 27000000 ; then
	   echo "probed SPI ROM" ;
           if sf read 0x12400000 0 $filesize ; then
               if cmp.b 0x12000000 0x12400000 $filesize ; then
                   echo "------- U-Boot versions match" ;
               else
                   echo "Need U-Boot upgrade" ;
                   echo "Program in 10 seconds" ;
                   for n in 9 8 7 6 5 4 3 2 1 0 ; do
                        echo $n ;
                        sleep 1 ;
                   done
		   echo "erasing" ;
                   sf erase 0 0x40000 ;
		   # two steps to prevent bricking
		   echo "programming" ;
                   sf write 0x12000000 0 $filesize ;
		   echo "verifying" ;
                   if sf read 0x12400000 0 $filesize ; then
                       if cmp.b 0x12000000 0x12400000 $filesize ; then
                           while echo "---- U-Boot upgraded. reset" ; do
				sleep 120
			   done
                       else
                           echo "Read verification error" ;
                       fi
                   else
                        echo "Error re-reading EEPROM" ;
                   fi
               fi
           else
               echo "Error reading boot loader from EEPROM" ;
           fi
      else
           echo "Error initializing EEPROM" ;
      fi ;
else
     echo "No U-Boot image found on SD card" ;
fi

Recap and best practices

I should probably move this section to the top of the document, but here’s some additional rationale for how and why we use the boot script scheme.

Two-file U-Boot upgrades

To build an SD card to upgrade U-Boot, you can copy just two files (6q_upgrade and u-boot.bin)to a fresh, out-of-the-box SD card (which tend to come formatted as FAT32), insert the card and run run upgradeu.

Single partition Ubuntu

To run Ubuntu, LTIB or Timesys single-partition images, you can create an SD card by simply formatting an ext2/3/4 partition and copy your filesystem image, boot script and kernel using cp. There’s no need to use dd or any other special formatting commands.

Windows CE, too

I guess I should say Windows Embedded 7. As the name implies, U-Boot is the Universal Boot Loader, and it can load and launch Windows Embedded using a boot script in a very similar manner as Linux. In this environment, you shouldn’t need to format the SD card at all: FAT32 should work.

And NFS

It may not be clear, but the use of a boot script on SD can also be useful in booting over NFS. This may sound like an oxymoron, but it’s often more convenient to write a network load script and copy it to an SD card than it is to hook up a serial port and tweak settings there.

This is especially true for those that infrequently use a serial port or when devices are enclosed in a manner that makes access to the serial port difficult.

Best practices

If U-Boot and environment variables are all stored on SD card, you don’t have much choice about what goes where, and environment variables are often used and changed to reflect the combination of distribution-related variables like whether or not a RAM disk is loaded and machine-specific variables like ethernet addresses or display settings.

When the two are separated as they are in SabreLite and Nitrogen6 boards, you should try to use environment variables for only those things which are tied to the board, such as the type of display. Any distribution-related bootargs should be added by the boot script.

If we haven’t yet convinced you that this is a good idea, I hope that at least you’ll understand what you’re seeing when you receive a board on your desk. At that point, I’ll refer you to the Linaro way, which allows you to override all of this and play “Hide the U-Boot” using a small shim in SPI ROM.

For what it’s worth, you can load and program that using the upgradeu command and the 6q_upgrade script by naming the shim u-boot.bin.

Tags:

25 Responses to “U-Boot conventions for i.MX6 (Nitrogen6X and SabreLite)”

  1. tleung July 16, 2012 3:32 pm #

    I have the Nitrogen6w board booting from SD, but is does not boot from a connected sata drive with the boot switches at “fuses” and does not boot from USB when the switches is set for USB. What do I need to change for U-boot to be able to boot from USB or sata ( preferrably sata ). If I abort the sd boot, and issue the “sata” command via console, it does not see the device.

  2. Henrik Jacobsen July 31, 2012 6:58 am #

    Hi,

    “We jokingly refer to this as a game of “Hide the U-Boot”, and don’t want to play. ”

    Sorry, I simply don’t get the point!

    I almost overlooked that you, contrary to the FS i.MX53 reference designs, have added this serial flash device. Using the SabreLITE design as reference for a real product adds unnecessary cost – however little – to the product, and makes SW management more complicated. The “unbricking” guide wouldn’t be needed if U-boot is on the SD card – you then “unbrick” simply by rewriting the SD card in another computer.

    I assume that getting rid of the serial flash is just a matter of adjusting the eFUSEs BOOT_CFG[7:4] settings, right? Is there some important point about this that I misssed?

    Best regards
    Henrik

    • ericn July 31, 2012 12:32 pm #

      Hi Henrik,

      Thanks for the feedback.

      You’re absolutely right about a few things:

      • · Adding a serial EEPROM adds cost, and
      • · Unbricking isn’t needed if you boot to removable media and have a reader/writer on another machine, and
      • ·The choice of “Boot to SPI NOR” versus “Boot to SD” is made by eFUSES

      I think that whether booting to serial EEPROM makes SW management more difficult depends on what tools you expect users to have. Do you need them to have ready access to ‘dd’ and instructions for use? USB Image Creator? Freescale’s Manufacturing Tool? Fastboot? FWIW, we’ve tried to reduce that number.

      We’re also aiming for a place we’re at on our i.MX5x boards, where you get a display immediately on boot so you can prompt a user to “Insert an SD card”. We’re not quite there yet, but Fabio’s recent patches to main-line U-Boot get us close.

  3. Henrik Jacobsen August 1, 2012 4:04 am #

    Hi Eric,

    Thanks for your prompt reply! I think you can say that it comes down to whether your end product is the development board – as in your case, or it’s some other kind of appliance. For instance, in our product we don’t see much idea in an “Please insert SD card” message, as the SD card is physically inaccessible to the end user. But yes, I do see that there are some advantages in having the 1st level boot code stored separately.

    Best regards
    Henrik

    • ericn August 1, 2012 2:19 pm #

      Context is everything.

  4. Konstantinos Margaritis October 11, 2012 12:18 am #

    Hi,

    trying to update the flash in my sabrelite, using https://wiki.linaro.org/Boards/MX6QSabreLite, in particular, here is the output captured from serial:

    U-Boot 2009.08-00381-gc41f1c6-dirty (Nov 03 2011 – 07:05:05)

    CPU: Freescale i.MX 6 family 0.0V at 792 MHz
    mx6q pll1: 792MHz
    mx6q pll2: 528MHz
    mx6q pll3: 480MHz
    mx6q pll8: 50MHz
    ipg clock : 66000000Hz
    ipg per clock : 66000000Hz
    uart clock : 80000000Hz
    cspi clock : 60000000Hz
    ahb clock : 132000000Hz
    axi clock : 264000000Hz
    emi_slow clock: 29333333Hz
    ddr clock : 528000000Hz
    usdhc1 clock : 200000000Hz
    usdhc2 clock : 200000000Hz
    usdhc3 clock : 200000000Hz
    usdhc4 clock : 200000000Hz
    nfc clock : 24000000Hz
    Board: MX6Q-SABRELITE:[ POR]
    Boot Device: I2C
    I2C: ready
    DRAM: 1 GB
    MMC: FSL_USDHC: 0,FSL_USDHC: 1
    JEDEC ID: 0xbf:0x25:0x41
    Reading SPI NOR flash 0xc0000 [0x2000 bytes] -> ram 0x276009b8
    SUCCESS

    *** Warning – bad CRC, using default environment

    In: serial
    Out: serial
    Err: serial
    Net: got MAC address from IIM: 00:19:b8:00:e5:40
    FEC0 [PRIME]
    Hit any key to stop autoboot: 0
    mmc0 is current device

    ** Unable to use mmc 0:1 for fatload **
    ** Bad partition 1 **
    Card did not respond to voltage select!
    mmc1(part 0) is current device
    MMC: block number 0x1 exceeds max(0x0)
    ** Can’t read from device 1 **

    ** Unable to use mmc 1:1 for fatload **
    ** Bad partition 1 **
    MX6Q SABRELITE U-Boot > mmc dev 0
    mmc0 is current device
    MX6Q SABRELITE U-Boot > mmc read 0x10800000 0 200

    MMC read: dev # 0, block # 0, count 512 … 512 blocks read: OK
    MX6Q SABRELITE U-Boot > sf probe 1
    JEDEC ID: 0x00:0x00:0x00
    Failed to initialize SPI flash at 0:1

    I’m having trouble updating flash, could you please recommend some way to get past this?

    • ericn October 11, 2012 7:00 am #

      Hi Konstantinos,

      It appears that your SD card is formatted without a partition table, so the fatload statement is failing.
      Can you run fatls mmc 0 and see the files? How about ext2ls mmc 0?

      • Konstantinos Margaritis October 22, 2012 9:48 am #

        Actually, and rather surprisingly I managed to flash u-boot, by booting from Linaro’s u-boot (following the instructions in this blog post in this site:

        http://boundarydevices.com/running-linaro-ubuntu-on-i-mx6-sabre-lite-and-nitrogen6x/

        Afterwards, rerunning sf probe 1 and the rest of instructions seemed to work fine.

        Thanks again

        • Louis Koziarz January 25, 2013 1:10 pm #

          Konstantinos,

          I’m not sure if you’re still following up to this thread but I’m seeing the same problem on my board. It doesn’t seem to be a badly formatted SD card, but the “sf probe” command might be the cause.

          I’ve tried asking for help via email, via imxcommunity.org, and now here. Hopefully someone is listening….

          • VarsMolta March 6, 2013 1:59 pm
            #

            Hi Konstantinos, any luck with this error? I am getting it as well. Thanks

          • ericn March 6, 2013 5:28 pm
            #

            Hi Louis (and Vars),

            This seemed to have slipped past me. Can you post the output from the version and print commands under U-Boot?

            The sf probe command changed when we made the move from Freescale’s 2009.08 code base to the main-line 2013-01.

            In U-Boot 2009.08, the command usage was sf probe 1, and under 2013.01, this is just sf probe.

            This and other subtle command incompatibilities are the reason we switched to 6x_upgrade from 6q_upgrade in previous releases.

            Please advise,

            Eric

  5. ericn January 25, 2013 4:04 pm #

    Sorry we didn’t see your post on i.MX Community previously, but I just added a reply and a link to this blog post that gives the details.

    • Louis Koziarz January 28, 2013 12:40 pm #

      Eric,

      Thanks for the clarification. I guess the root cause of my issue was that my environment was still trying to use the 6q_ script and not the 6x_. It’s kind of a tricky situation to be sure you’ve caught, perhaps adding a line in the FAQ about the JEDEC coming up as 0:0:0:0:0 could help future users. But thanks for the response, I’ve gotten the EEPROM back online and the board is running…

  6. Athanasios Silis February 21, 2013 9:25 am #

    Hello there!
    I would like to get the default image of the microSD card that comes with the development board sabre-lite.
    Is there some place I can download it from?
    Also, how can I mount this microSD card in a linux host?
    Thank you in advance for your help!

  7. embedsri May 27, 2013 12:39 am #

    These are the environment variables of uboot booting from SPI EEPROM on my SL-imx6 board.

    baudrate=115200
    bootargs=console=ttymxc0,115200 androidboot.console=ttymxc0 vmalloc=400M fbmem=28M androidboot.hardware=freescale
    bootdelay=1
    clearenv=if sf probe || sf probe || sf probe 1 ; then sf erase 0xc0000 0×2000 && echo restored environment to factory default ; fi
    console=ttymxc1
    ethact=FEC
    ethaddr=00:19:b8:01:09:97
    ethprime=FEC
    loadaddr=0×12000000
    upgradeu=for dtype in sata mmc sata mmc ; do for disk in 0 1 ; do ${dtype} dev ${disk} ;for fs in fat ext2 ; do ${fs}load ${dtype} ${disk}:1 10008000 /6x_upgrade && source 10008000 ; done ; done ; done

    Environment size: 582/8188 bytes

    Is there a way to restore default factory settings? Because the above uboot is NOT proceeding to boot from microSD card. Rather it just stops at interactive U-Boot > prompt. I might have changed bootcmd variable based on Freescale documentation. How do I restore it? Thanks.

    • ericn May 28, 2013 8:07 am #

      Hi Sri,

      You can restore the compiled-in defaults like so:

      U-Boot > run clearenv
      
      • embedsri May 29, 2013 7:04 am #

        Hi Eric,
        That’s exactly what I did. Thanks anyway.

  8. stephan June 7, 2013 2:39 am #

    Hi Eric,

    It seems my SD-Cards always registers to mmc 1:0. I can ext2ls mmc 1:0 and ext2load mmc 1:0 /*, but all your scripts aim at mmc *:1 … Why are you fixed on that and what is wrong with my Card? :)

    Thanks.

    • ericn June 7, 2013 6:38 am #

      Hi Stephan,

      On Nitrogen6x boards, there are two microSD slots (top and bottom of the board). The top is mmc 0 and the bottom is mmc 1 from U-Boot’s perspective.

      SABRE Lite (BD-SL-i.MX6) has a full-sized SD card slot on the bottom of the board that’s mmc 0 and the top-side microSD is mmc 1.

      The default bootcmd and default boot script should both be configured to use the disk loop variable so they can boot to either one.

      Are you by chance using the mx6qsabrelite_config? It does things differently.

      • dRp3pP3r June 7, 2013 6:47 am #

        Hi Eric,

        yeah, i figured the loop, the problem was the number of the partition. Mine was 0, your scripts looked in partition 1. Already firgured out that happend because I formatted the card the wrong way. (formatted /dev/sdX instead of /dev/sdX1, that destroyed the partition table and u-boot recognized the partition as 1:0 instead of 1:1, i wonder it was recognized at all…)
        Repaired the partition table, re-tar-ed the image and everything goes well.

        Thanks, anyway :)

        • ericn June 7, 2013 6:54 am #

          Glad to hear it.

          • Dhiv November 8, 2013 6:38 am
            #

            Hi eric,
            That was a useful port.
            Is there a way to modify the env in U-boot and permanently store , so that it will not be erased on reboot or SDCARD format, something like clearenv

            Thanks in advance,
            Dhiv

          • ericn November 8, 2013 7:14 am
            #

            Hi Dhiv,

            You can save environment variables using the saveenv command.

            U-Boot > setenv myvar value
            U-Boot > saveenv
            

            The environment is stored in SPI-NOR flash.

  9. Young February 10, 2014 8:10 pm #

    Hi eric, I was running “U-Boot > run upgradeu” .
    After that, bootloader does not work.
    Only screen out “U-Boot 2013.10-50829-g8d8e23c (Nov 21 2013 – 14:43:49)”
    How can I solve this problem? Please tell me.

  10. ericn February 12, 2014 7:50 pm #

    You’re probably running on a board other than a SABRE Lite or Nitrogen6X with 1GiB.

    What kind of board do you have?

    You’ll likely need to use the unbricking tool to get U-Boot running again and then run upgradeu with the proper boot file like so:

    U-Boot > bootfile=u-boot.machinetype ; run upgradeu
    

    See this post for details about the variations.

Leave a Reply