Zynq/PetaLinux U-Boot Quirks and Hints

U-Boot is the second stage bootloader for most ARM systems, including the one internal to the Zynq found on the UUB. It is loaded after the First Stage Bootloader (FSBL) which is a significantly simpler program designed to initialize only the hardware required to get U-Boot loaded. Once U-Boot is running, then the full Linux kernel can be booted with a variety of different methods. U-Boot, for instance, contains networking support, filesystem support, can read compressed files, and has a (very limited) shell script interface.

However, U-Boot is also fairly quirky. So this page is intended to help document quirks in the UUB Zynq implementation of U-Boot as they are found.

U-Boot doesn’t really have a configuration system

If you look at U-Boot’s directory structure, there are a lot of Kconfig files, and if you type ‘make menuconfig’ in the top directory, you get something that looks like the Linux kernel configuration screen. Don’t be fooled. Most of U-Boot’s configuration options have not been integrated into the config files yet. Most of them are just still hidden as #defines in a header file.

In PetaLinux, the ‘top-level’ U-Boot configuration file is located in ${project_directory}/subsystems/linux/configs/u-boot/platform-top.h . PetaLinux will preserve this header file and not overwrite it, so this is where you should put all #defines.

PetaLinux’s default U-Boot environment has wrong “console”

PetaLinux always leaves the “default” U-Boot environment as having the variable “console” equal to “console=ttyPS0,115200.” For the UUB this should be “console=ttyPS1,9600.” This might not seem like a problem, as when U-Boot is loaded, everything seems fine, right? Text prints out fine on the serial port.

That’s because U-Boot has a default console, too. And PetaLinux does set up the default console correctly. But whenever the “console” environment variable is changed, U-Boot switches the console to wherever the environment variable says. This means that if you save U-Boot’s environment in flash, when U-Boot starts up and reads that environment off of flash, it switches the console output over to ttyPS0 and you’re stuck, because the “console” variable changed (even though it changed to exactly what it was before).

We actually need to totally overwrite U-Boot’s “default” environment – the one in ${project_directory}/subsystems/linux/configs/platform-auto.h. This is because the DEFAULT_MTDPARTS define doesn’t actually work in U-Boot: it needs a real “mtdparts” environment variable, and it needs to have it before it loads an environment off of flash. So the correct console settings are located in ${project_directory}/subsystems/linux/configs/u-boot/platform-top.h.

There is a similar problem in that PetaLinux doesn’t set up the “bootargs” entry correctly in the Device Tree Structure (DTS), either, which results in Linux also jumping to the wrong console. (You should be noticing a pattern here that PetaLinux doesn’t like it when you change things).

U-Boot doesn’t reset the SPI flash properly

U-Boot doesn’t attempt to fully reset the SPI flash back to its “default” initial state (single bit output, page register 0, etc.) currently. This ends up being a problem because if you attempt to load Linux via petalinux-boot (over JTAG), the FSBL doesn’t know that you’re trying to load something over JTAG, by default. So it immediately launches the on-flash program. If that program is U-Boot itself, in the amount of time petalinux-boot waits to load U-Boot over JTAG, the on-flash U-Boot mucks with the SPI flash, and then the newly-loaded U-Boot can’t talk to it at all.

This is a similar problem to when the FSBL is loaded via JTAG as well – if the SPI flash was not in its default mode, the FSBL will fail to load as well. This has been fixed directly inside the FSBL (by me, with magic, as far as I can tell, but it works, so I’m not complaining) but the solution has not propagated over to U-Boot.

The ‘temporary’ solution right now is to put an FSBL which forcibly waits for JTAG in the ${project_directory}/pre-built/ directory. This guarantees that the FSBL actually resets the QSPI, and U-Boot starts clean.

U-Boot’s UBI implementation auto-formats when attaching

If you attach an MTD partition to UBI under Linux, it scans it, and if it sees that it’s empty (blank flash), it goes ahead and formats the whole thing for UBI. This can take a long time – over an hour in the case of the main UBI partition. But obviously Linux is threaded, and so it’s obvious that the system isn’t in fact frozen, but is busy doing something.

U-Boot’s UBI implementation also does this. But U-Boot is single threaded, so it’s not obvious that the system isn’t frozen. In fact, when U-Boot launches, it attempts to attach the UBI partition to find its environment. Which then leads to the UBI partition being formatted. So it really can look like the system locked up during boot.

Short take: if you see

UBI: attaching mtd1 to ubi0
UBI: scanning is finished

and it seems like the system has hung, just be patient. It’s formatting the flash, which can take a while. This should not happen normally, except when U-Boot is first programmed. Every time after that, the UBI attach process should be immediate.

U-Boot doesn’t autodetect number bases, wants hexadecimal

U-Boot tends to use “simple_strtoul” with a forced base of 16. This means that lots of commands will just screw up entirely if you try to give them the decimal value, as they’ll interpret it as hex. This is a non-exhaustive list – just what I’ve found so far.

  • sf erase/write
  • ubi create

Of course most of those utilities actually report the number of bytes written/read in decimal, leading to complete confusion.

PetaLinux ends up somehow passing U-Boot the wrong device tree

U-Boot somehow ends up with its “Model” set to “Zynq ZC702 Development Board” and the total RAM content equal to 1 GiB. I haven’t been able to find where this is coming from yet.

PetaLinux uses a non-compatible flash in its device tree

This isn’t a U-Boot thing but I needed a place to put it. PetaLinux doesn’t bother asking you what SPI flash you’re using. It just puts a default of “micron,n25q128” or something like that in the device tree. Problem is that this isn’t actually one of the flashes that’s listed as compatible in m25p80.c, so the MTD device never gets loaded! Solution is to actually specify the correct SPI flash in system-top.dts, overwriting the nonsense one in system-conf.dtsi.

Leave a Reply

Your email address will not be published. Required fields are marked *