How to get U-boot SPL working on Apalis TK1

Apalis Evaluation Board Rev 1.1 with TK1 Rev 1.2A
U-boot 2022.4 (but same issue with 2020.10 and toradex version 2019.7)

We have been using the TK1 SOM in our product using U-boot 2020.10 for some time. Now we want to move to booting using the SPL, leveraging it to implement an A/B choice for U-boot proper, and possibly add a recovery boot from usb.

The first naive attempt was to take the u-boot-spl.bin already built by our configuration(
defconfig (47.0 KB)
) and try to boot with that (after using cbootimage to include the BCT). Not only did that not work, but it did not even produce any output on boot.

Tracing the flow from arch/arm/cpu/armv7/start.S to arch/arm/lib/crt0.S and common/spl/spl.c there seems to be no board specific board_init_f() for the TK1. Whereas the one for uboot itself in common/board_f.c seems not to be used for SPL? Since it already prints the U-boot banner and initializes serial, which for SPL seems to be done in spl/spl.c(preloader_console_init()).

Using the generic board_init_f() by enabling CONFIG_SPL_FRAMEWORK_BOARD_INIT_F=y did not produce any output either.

As a next step I eliminated all code from the regular board_init_f() and minimized the device tree (u-boot.dts (3.2 KB)) to get a u-boot that is not “booting through” anymore, but is still capable of serial output. That code was then duplicated to a new board_init_f() in mach-tegra/spl.c and all dts nodes were tagged with u-boot,dm-spl; (u-boot-spl.dts (1.7 KB)). This did not produce any output either.

Since this started to feel like groping in the dark (while throwing stuff against a wall and (not) seeing what sticks…) it would be good if we can get at least some output working to see how far along the SPL actually gets. For this I tried to enable lowlevel debugging using:

CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_DEBUG_LL_INCLUDE=“debug/8250.S”
CONFIG_DEBUG_UART_PHYS=0x70006000
CONFIG_DEBUG_UART_VIRT=0x70006000
CONFIG_DEBUG_UART_8250_SHIFT=2

and added a few printascii() calls to the start of board_init_f() and in init_sequence_f. Testing this with normal U-boot (to go from a known working situation) produced no extra output.

Secondly I tried using the debug uart with:

CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_BASE=0x70006000
CONFIG_DEBUG_UART_CLOCK=408000000
CONFIG_DEBUG_UART_NS16550=y
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_ANNOUNCE=y

Again tested with normal U-boot, this killed all output.

There is also the option of using the pre console buffer (CONFIG_PRE_CONSOLE_BUFFER), but that does not really help, since in SPL the console is not working yet. (And it requires an address for the buffer (CONFIG_PRE_CON_BUF_ADDR), for which I am currently not sure what a safe/usable value would be.)

I also looked at using a gpio to control a led as a sign of first life, but it seems spl_gpio_output() is not implemented for the TK1?

I tested the above also using the stock tk1 defconfig (
defconfig-apalis-tk1 (46.1 KB)
) to make sure we did not break anything in our config, but that made no difference.

So with all that, we’re stuck at the moment. How do we get at least debug output over the uart to work? Or better yet, how do we get the SPL to at least a point that it has working serial output?

Interesting, what SPL has to do with A/B boot? SPL is required for devices with too small SRAM to hold whole U-Boot. (small SRAM is always available, while DDR RAM is not available until set up properly.) So you boot to small SRAM, setup DDR RAM, SPL first stage copies the rest of U-Boot to relatively unlimited DDR RAM space and continues booting from DDR. NXP devices as alternative to SPL support their DCD structure, which may be used to setup DDR first (as instructed by commands encoded in DCD), and then boot directly to DDR, so SPL is not needed. If you had it non-SPL on TK, then TK must be supporting something like that.

Do you mean in SPL first stage decide which copy of 2nd U-Boot stage to choose? This doesn’t sound right. Perhaps it is possible, but I doubt 2nd SPL stage is independent of 1st stage. I fear it is easy to hit some incompatibility between separate U-Boot builds.

If you need to roll back A<->B including U-Boot, then you may just provide extra volume or something to keep roll back copies of A/B U-Boot images to restore. Simple.

The first thing that SPL does is to initialize the console and print a message that looks like this:

U-Boot SPL 2021.07+iot+fslc+g691e634bfd (Jul 06 2021 - 11:22:14 +0000) Trying to boot from MMC1

If you do not see this message then the most likely reason is (given that your hardware is operational and you have a terminal connected to the console UART) that SPL is not loaded correctly.

On any boot medium (SD card, eMMC, and i.MX SDP bootstrapping) there has to be a 1k offset to SPL and then the remainder of u-boot starts at 69k.

If you want to use A/B banking with SPL/u-boot you can only do that by using two different hardware partitions, typically boot0 and boot1 on an eMMC. On the user partition of the eMMC you would then have two partitions for kernel (/boot) and root file system (/). You can of course combine the /boot partition into the root file system partition.

The u-boot on the hardware boot partitions would then load the kernel from the respective /boot partition and provide it with the respective partition for the root file system.

When you do an update of a bank and after the update is complete and you have verified it, you need to switch the boot partition on the eMMC.

Indeed, which is what we are trying to achieve as a first step. With “normal” U-boot serial output works fine. With SPL nothing gets printed so far. Which is why I was also looking at using a led as a sign-of-life. Currently, I don’t know whether the SPL gets properly started or how far along it gets. It seems either it is not starting correctly, or for some reason it cannot initialize the serial port correctly.

What do you mean with the 1k offset? Currently I am writing the SPL to the same location as I am writing U-boot at the start of the first boot partition:

cd /tmp ; tftp -g -r u-boot-dtb-tegra.img 192.168.11.2 ; dd if=u-boot-dtb-tegra.img of=/dev/mmcblk0boot0 

cd /tmp ; tftp -g -r u-boot-spl.img 192.168.11.2 ; dd if=u-boot-spl.img of=/dev/mmcblk0boot0

Using the toradex recovery console to tftp the binary in, and write it to the mmc. The .img files are created from the respective .bin files using cbootimage to add the BCT.

Yes, currently we already have our system A/B with regards to two boot partitions and two root fs’s. But the U-boot is still shared. What we want to do is to have SPL as first bootloader (that should never need updating), that will then start U-boot proper from either the first or the second boot partition. So if U-boot proper does need an update, and the update fails, we can safely rollback to the previous U-boot proper and boot into the pre-update system.

But before we can do all that, we need to get SPL started and producing output.

That is one use for SPL (and TPL if even SPL does not fit). But to our understanding SPL is also intended to provide other/multiple boot options, and also A/B choice. The latter is called VPL in the U-boot documentation. Though VPL seems mostly to exist in the documentation, but is not really fully implemented yet it seems. So we will have to do some work there ourselves.

SPL and U-boot proper are two different binaries. The job of the SPL is to bring the system up to a state where U-boot proper can be loaded (mostly RAM and serial). There should be minimal dependencies between SPL and U-boot proper as long as SPL can find U-boot proper and they both agree on such things as ram start addresses etc.

@Esger ,

cd /tmp ; tftp -g -r u-boot-dtb-tegra.img 192.168.11.2 ; dd if=u-boot-dtb-tegra.img of=/dev/mmcblk0boot0

You are already writing your imx u-boot to the first boot partition of the eMMC. You could save yourself some work trying to separate SPL from u-boot by simply writing your u-boot to the other eMMC boot partition and switch the boot parttion:

cd /tmp ; tftp -g -r u-boot-dtb-tegra.img 192.168.11.2 ; dd if=u-boot-dtb-tegra.img of=/dev/mmcblk0boot1

Once installed on the second boot partition run

mmc bootpart enable 2 1 /dev/mmcblk0

on your target which needs to have mmc-utils installed. When you reboot the system it will boot from /dev/mmcblk0boot1 instead of /dev/mmcblk0boot0.

If you want to continue to experiment with SPL try this first:

cd /tmp ; tftp -g -r u-boot-spl.img 192.168.11.2 ; dd if=u-boot-spl.img of=/dev/mmcblk0boot0 bs=1k seek=1

Reboot your system. It won’t boot but all the way but you should get the SPL prompt.

Yes, just for testing, I am changing between u-boot and SPL trying various things. I am not yet trying to have the SPL actually load a u-boot from another partition.

I have tried with the 1k offset, but that did not make a difference, no output. But I would suspect that 1k to need to be present/configured in the BCT too?

We’re using this for U-boot:

Version       = 0x00400001;
Bctcopy       = 1;
Bctfile       = PM375_Hynix_2GB_H5TC4G63AFR_RDA_924MHz.bct;
BootLoader    = ../../src/u-boot-2/u-boot-dtb-tegra.bin,0x80108000,0x80108000,Complete;

Note that the 0x80108000 address does not match what U-boot is actually compiled with (SYS_TEXT_BASE = 0x80110000, or 0x80120000 if we need more room for SPL), but this does not seem to matter for U-boot. It’s probably a leftover from an older U-boot we used previously.

and I have been using this for SPL:

Version       = 0x00400001;
Bctcopy       = 1;
Bctfile       = PM375_Hynix_2GB_H5TC4G63AFR_RDA_924MHz.bct;
BootLoader    = ../../src/u-boot-2/spl/u-boot-spl.bin,0x80108000,0x80108000,Complete;

(for SPL the address does match SPL_TEXT_BASE)

I am not sure why the SPL would be read from 1k further if the bootrom and bct do not differ?

appreciate the help!

@Esger ,
Apologies. I think I led you the wrong way. I thought you are using Apalis with i.MX but you are using it with Tegra. The 1k offset etc. does not apply to Tegra. My bad.

However, you should still be able to flash to boot1 the entire u-boot and switch the eMMC. That is independent of the SoC.

Hi @Esger !

Welcome to Toradex Community! :tada:

I would like to thank @Edward and @RudolfStreif for the help!

@Esger, if you would like to accelerate your development, we recommend you to go to a partner of Toradex, for example, Eltronix GmbH - Toradex Service Partner, who can certainly help you with it.

Best regards,

@henrique.tx

Actually I just stole some time with my ignorance.

@Esger, thank you very much for pointing me at new to me uncountable U-Boot features, sorry for noise.

Just a guess, xPL levels seem requiring their own U-Boot drivers, there are numerous CONFIG_xx_SPL_yy, I would check if those are alright.

Hi again @Esger !

I am sending this message just to highlight that Apalis TK1 is EOL. So maybe it is good to consider if the time invested in an EOL module is worth it.

Best regards,