Running upstream OpenSBI on SpacemiT K1

The SpacemiT K1 is a rather interesting RISC-V SoC, found for instance on boards like the Banana Pi BPI-F3 board. It's one of those platforms that looked promising on paper, but took a bit of time before things really started to move upstream. Things have clearly accelerated over the last few months.

Linux 7.0 brings, among other things PCIe support, making the board quite capable as a development board. SD card, CPU thermal sensor and cpufreq support are already in the pipe.

Unfortunately the situation is less advanced on the firmware side. There is only very basic support for the SpacemiT K1 in U-Boot for the second stage, and initial SPL support has been posted on the mailing list, but has not yet been merged. In practice, this means you still have to rely on the vendor U-Boot, which is based on the rather old 2022.10 release.

On the other hand, OpenSBI does have upstream support for the SpacemiT K1, however it is not compatible with the vendor U-Boot, mostly due to device tree differences.

This can be addressed by applying a few patches to the vendor U-Boot, which I have published in a git tree in the k1-bl-v2.2.y-opensbi branch (technically this can also be handled on the OpenSBI side, but I prefer using a vanilla upstream OpenSBI version). The first two patches update the configuration to get closer to the upstream U-Boot defaults, and to enable some configuration options for the Milk-V Jupiter board, which stores its firmware in SPI NOR flash, instead of eMMC for the Banana Pi BPI-F3. The following patches update the device tree by adding extra compatible entries to several devices, as expected by the upstream kernel and OpenSBI (thanks to Troy Mitchell for the hint about the UART change) and update the CPU riscv,isa properties. Finally an additional patch adds the SpacemiT P1 PMIC to the device tree, which is required for the OpenSBI reboot patchset I recently posted (this is currently done only for the Banana Pi BPI-F3 and Milk-V Jupiter boards, but extending it to other boards should be straightforward).

Building this U-Boot version is as simple as running this command in the source directory:

make k1_defconfig && make

On a Banana Pi BPI-F3 board, the resulting U-Boot can be flashed with:

echo 0 > /sys/block/mmcblk0boot0/force_ro
dd if=FSBL.bin of=/dev/mmcblk0boot0 bs=512 seek=1
dd if=u-boot.itb of=/dev/mmcblk0p1

Building upstream OpenSBI is also fairly simple, and can be done by running this command in the source directory:

make PLATFORM=generic

On a Banana Pi BPI-F3 board, the resulting OpenSBI can be flashed with:

dd if=fw_dynamic.itb of=/dev/mmcblk0p2

Note that the vendor U-Boot version is patched to install OpenSBI in a separate partition instead of embedding, as the upstream U-Boot does. While this works well on the Banana Pi BPI-F3, the corresponding partition in the Milk-V Jupiter SPI NOR flash is too small for the upstream OpenSBI version, and can't be easily resized without breaking compatibility. To address this, the branch k1-bl-v2.2.y-opensbi-embedded contains an additional patch (a bit hackish I admit) to somehow restore the upstream approach. The build process remains simple, first build OpenSBI with the following command:

make PLATFORM=generic

Then build U-Boot, specifying the patch to the just built OpenSBI firmware:

make k1_defconfig && make OPENSBI=/path/to/opensbi/build/platform/generic/firmware/fw_dynamic.bin

On a Milk-V Jupiter board, the resulting combined U-Boot/OpenSBI can be flashed with:

modprobe mdtblock
dd bs=4k if=FSBL.bin of=/dev/mtdblock2
dd bs=4k if=u-boot.itb of=/dev/mtdblock5

This combined U-Boot/OpenSBI can also be used on a Banana Pi BPI-F3, using the same flashing procedure as above, while skipping the OpenSBI part (although running it won't cause any issue, it will simply be unused).

All of this is admittedly a bit hackish, but enabling the use of upstream OpenSBI is already one step forward. Hopefully, in a few months, we will be able to rely entirely on upstream U-Boot.