Run the Slint demo

Choose your board, build the sample and boot a GPU-rendered Slint interface on Zephyr. This is a real-hardware demo: YakoGL drives the board's GPU.

Throughout, <user>@<board>, <board> and paths in angle brackets are yours to fill in.

On a board

All three board guides are shown below.

1. What you need

2. The workspace

python3 -m venv .venv && . .venv/bin/activate && pip install west
west init -m https://github.com/signal-slot/yakogl --mr main yakogl-ws
cd yakogl-ws && west update
pip install -r zephyr/scripts/requirements-base.txt

The manifest (west.yml) pins Zephyr to the revision the samples were built and run against and imports only the modules they need. The repository lands in yakogl-ws/yakogl and is a Zephyr module by itself; each sample adds the drivers on its own. A first triangle on each board, before the Slint demo, is in driver/samples/zephyr/README.md.

3. The no_std Slint tree

The demo links Slint, femtovg and glow, which have no no_std form upstream. The repository carries the patches; you recreate the trees once, outside the workspace:

WORK=<a directory of yours>
P=<workspace>/yakogl/examples/nostd    # the patches
git clone https://github.com/slint-ui/slint.git $WORK/slint-nostd/slint
(cd $WORK/slint-nostd/slint && git checkout 1007c032ca1573e60dce2113e802e0ccb91c2641 &&
 patch -p1 < $P/slint-nostd.patch)
# femtovg 0.26.0 and glow 0.18.0 from the cargo registry, patched, into $WORK/nostd

The femtovg and glow steps and the details are in examples/nostd/README.md.

4. Build

AM62P only: provide the GPU firmware

The PowerVR needs Imagination's firmware rgx.fw.36.53.104.796. It is not part of YakoGL and is never distributed with it. Take it, under its licence, from the board's /lib/firmware under TI's Linux, or from TI's graphics binary release (ti-img-rogue-umlibs). Do not use linux-firmware's powervr/rogue_36.53.104.796_v1.fw: that is a different firmware, which this loader cannot boot. Turn it into a header, from the top of the workspace:

yakogl/driver/tools/mkfwblob.sh /path/to/rgx.fw.36.53.104.796

It writes yakogl/driver/src/fw/pvr_fw_blob.h. Never commit that file.

Compile the sample

RUSTUP_TOOLCHAIN=nightly west build -p always -b <board> -d build/slint \
    yakogl/examples/slint -- \
    -DSLINT_NOSTD_DIR=$WORK/slint-nostd/slint -DNOSTD_PATCH_DIR=$WORK/nostd

<board> is verdin_am62p/am62p54/a53, verdin_imx8mp/mimx8ml8/a53 or rpi_4b.

The image is build/slint/zephyr/zephyr.bin. (Without -DNOSTD_PATCH_DIR the build looks in <SLINT_NOSTD_DIR>/../nostd.)

5. Boot it from the board's own storage

Verdin AM62P and Verdin iMX8M Plus (U-Boot, eMMC)

Torizon's root file system, partition 1 of the eMMC, is read-only, but /var is writable and lives on the same partition (a bind mount of /ostree/deploy/torizon/var), so U-Boot can read a file you put there:

scp build/slint/zephyr/zephyr.bin <user>@<board>:
ssh <user>@<board> 'sudo mkdir -p /var/yakogl && sudo cp zephyr.bin /var/yakogl/ && sync && findmnt -T /var/yakogl'

findmnt must show /dev/mmcblk0p1 on the AM62P: the partition U-Boot reads as mmc 0:1.

findmnt must show /dev/mmcblk2p1 on the i.MX8MP: the partition U-Boot reads as mmc 2:1.

Boot it once (changes nothing): reboot, stop autoboot at the U-Boot prompt, and type

# Verdin AM62P
ext4load mmc 0:1 0x82000000 /ostree/deploy/torizon/var/yakogl/zephyr.bin && dcache off && icache off && go 0x82000000
# Verdin iMX8M Plus
ext4load mmc 2:1 0x60000000 /ostree/deploy/torizon/var/yakogl/zephyr.bin && dcache off && icache off && go 0x60000000

go, not booti, with both caches off. The environment is untouched, so the next reset boots Linux again.

Make it the default (a persistent boot configuration change). First write down Torizon's bootcmd with printenv bootcmd; you need it to go back. Then use the command for your board:

# Verdin AM62P
setenv bootcmd 'ext4load mmc 0:1 0x82000000 /ostree/deploy/torizon/var/yakogl/zephyr.bin && dcache off && icache off && go 0x82000000'
saveenv
# Verdin iMX8M Plus
setenv bootcmd 'ext4load mmc 2:1 0x60000000 /ostree/deploy/torizon/var/yakogl/zephyr.bin && dcache off && icache off && go 0x60000000'
saveenv

From now on only the U-Boot prompt brings Linux back: setenv bootcmd '<the value you wrote down>', saveenv, boot. If the file is missing, the load fails and U-Boot stops at its prompt instead of booting Linux.

For shared boards the repository has a reversible form: a U-Boot hook in front of Torizon's bootcmd that boots an image once, or a counted number of times, and then Linux by itself, driven from Linux by tools/board.sh (install, default <image> <N>, nodefault). See docs/standalone-boot.md.

Raspberry Pi 4 (firmware, SD card)

No U-Boot: the Pi's boot loader reads the SD card's first FAT partition. Start from a Raspberry Pi OS Lite (64-bit) card and keep its firmware files (start4.elf, fixup4.dat, bcm2711-rpi-4-b.dtb, overlays/overlay_map.dtb, cmdline.txt). Add zephyr.bin and this configuration:

[all]
kernel=zephyr.bin
arm_64bit=1
enable_uart=1
uart_2ndstage=1
hdmi_group=2
hdmi_mode=87
hdmi_timings=1920 1 50 44 50 720 1 10 20 50 0 0 0 60 0 99070000 1

The hdmi_* lines describe the 1920x720 panel the results were taken on.

Boot it once: from Raspberry Pi OS, copy zephyr.bin to /boot/firmware/, save the lines above as /boot/firmware/tryboot.txt and run sudo reboot '0 tryboot'. The firmware reads tryboot.txt instead of config.txt for that one boot; the next reset boots Linux. This is how every Pi 4 result on this site was booted.

Make it the default: keep Linux's config.txt as config-linux.txt and save the lines above as config.txt. To go back, put the card in a PC and copy config-linux.txt over config.txt. (This literal swap has not yet been run on our board; the tryboot path has.)

Known gaps