Current status: a test firmware is built.
tl;dr – I maintain the devterm ArchLinuxARM distro, and now I also want to do uConsole-CM4;
As of now, please don’t follow any “instructions” here – it’s a messy dump of my head and what I did.
Please educate me if I’m doing anything wrong – thanks!
Instructions
build-kernel.sh
official kernel build doc: https://www.raspberrypi.com/documentation/computers/linux_kernel.html
official cmdline.txt doc: RPi cmdline.txt - eLinux.org
Dependencies
pacman -S xmlto docbook-xsl kmod inetutils bc git dtc
(kmod git reinstall)
git apply ../uConsole/Code/patch/cm4/20230630/0001-patch-cm4.patch
- painfully update the patch file for 6.6.y… Orz
!! note, defconfig is separated to config-sample, as we are moving from 5.x to 6.6.y!
!! official alarm config is downloaded to config-alarm-linux-aarch64
!! we then merge these two with 3-way diff to produce our version of .config
.
compare-config.py
parses two defconfig files and compare them in the following aspects:
!! note, “is_not_set” is currently considered a value
!! note, the order is incorrect
– comment out line 22
!! note, stock-5.x is suspiciously wrong
– this is because ‘git reset --hard 3a33…’ does not change the branch
– git describe --tags
gives raspberrypi-kernel_1.20210430-1, which is a raspbian release of 5.10.17
– let’s create a branch “raspbian-stock” for this → config-raspbian-stock-5.10.17
– let’s create a branch “guu” for this → patch with 0001-patch-cm4.patch → config-guu-5.10.17
!! note, our 6.6.y was the HEAD of the repo, at c04af98514c26014a4f29ec87b3ece95626059bd, not a release!!
- a == b
- a != b
- a not b
- b not a
Comparing raspbian-stock with guu, we get very clean result:
========= config-raspbian-stock-5.10.17 != config-guu-5.10.17 =========
CONFIG_REGMAP_I2C m y
CONFIG_PPP m y
CONFIG_PPP_BSDCOMP m y
CONFIG_PPP_DEFLATE m y
CONFIG_PPP_MPPE m y
CONFIG_PPPOE m y
CONFIG_PPP_ASYNC m y
CONFIG_PPP_SYNC_TTY m y
CONFIG_SLHC m y
CONFIG_I2C_BCM2835 m y
CONFIG_CRYPTO_LIB_ARC4 m y
CONFIG_CRC_CCITT m y
========= config-raspbian-stock-5.10.17 not config-guu-5.10.17 =========
<NONE!>
========= config-guu-5.10.17 not config-raspbian-stock-5.10.17 =========
CONFIG_PPTP -- m
CONFIG_INPUT_AXP20X_PEK -- y
CONFIG_CHARGER_AXP20X -- m
CONFIG_BATTERY_AXP20X -- m
CONFIG_AXP20X_POWER -- m
CONFIG_MFD_AXP20X -- y
CONFIG_MFD_AXP20X_I2C -- y
CONFIG_REGULATOR_AXP20X -- y
CONFIG_DRM_PANEL_CWD686 -- m
CONFIG_DRM_PANEL_CWU50 -- m
CONFIG_BACKLIGHT_OCP8178 -- m
CONFIG_AXP20X_ADC -- m
CONFIG_TI_ADC081C -- m
We continue to compare alarm-6.x and raspbian stock 6.x
- A lot of differences, most interesting part being stock not alarm
- 250Hz stock vs 1000Hz alarm
- raspbian config has a lot of BCM2835 things (Model 1)
- bcm2711 thermal is ‘m’ is alarm
Plans:
- Start from alarm-6.x, and apply guu tweaks
- End up with a huge huge kernel (apple m1, rockchip, …)
- Start from raspbian stock 6.x (bcm2711_defconfig), and apply guu tweaks
- Missing out all the alarm goodies
- Merge alarm-6.x and raspbian 6.x, then apply guu tweaks
- Lots of work
Currently plan 1 seems most viable, for that alarm is known to work on CM4 already.
Plan 2 may end up building a kernel not compatible with the alarm userspace.
Plan 1 produces a clean diff compared to stock alarm config:
========= config-alarm-linux-aarch64 != config-merged =========
CONFIG_PAHOLE_VERSION 123 0
CONFIG_LOCALVERSION "-ARCH" "-uConsole"
CONFIG_PPP m y
CONFIG_PPP_BSDCOMP m y
CONFIG_PPP_DEFLATE m y
CONFIG_PPP_MPPE m y
CONFIG_PPPOE m y
CONFIG_PPP_ASYNC m y
CONFIG_PPP_SYNC_TTY m y
CONFIG_SLHC m y
CONFIG_INPUT_AXP20X_PEK m y
CONFIG_I2C_BCM2835 m y
CONFIG_CRYPTO_LIB_ARC4 m y
========= config-alarm-linux-aarch64 not config-merged =========
CONFIG_GCC10_NO_ARRAY_BOUNDS y --
CONFIG_GCC_NO_STRINGOP_OVERFLOW y --
CONFIG_CC_NO_STRINGOP_OVERFLOW y --
CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION y --
CONFIG_ACPI_THERMAL_LIB y --
CONFIG_KVM_COMMON y --
CONFIG_KVM_GENERIC_MMU_NOTIFIER y --
CONFIG_ARCH_HAS_HW_PTE_YOUNG y --
CONFIG_BLK_DEV_WRITE_MOUNTED y --
CONFIG_PCP_BATCH_SCALE_MAX 5 --
CONFIG_TCP_SIGPOOL y --
CONFIG_GENERIC_CPU_DEVICES y --
CONFIG_R8169_LEDS y --
CONFIG_PINCTRL_AMLOGIC_T7 y --
CONFIG_DRM_GPUVM m --
CONFIG_DRM_AUX_BRIDGE y --
CONFIG_FB_SYSMEM_FOPS y --
CONFIG_FB_IOMEM_FOPS y --
CONFIG_USB_CHIPIDEA_NPCM y --
CONFIG_COMMON_CLK_MT7988 y --
CONFIG_COMMON_CLK_S4_PLL y --
CONFIG_COMMON_CLK_S4_PERIPHERALS y --
CONFIG_ARM_SCMI_PERF_DOMAIN y --
CONFIG_AD7091R m --
CONFIG_NVMEM_LAYOUTS y --
CONFIG_FS_STACK y --
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS 64 --
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE 32 --
CONFIG_CRYPTO_JITTERENTROPY_OSR 1 --
CONFIG_CLOSURES y --
CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC y --
CONFIG_STACKDEPOT_MAX_FRAMES 64 --
CONFIG_FIRMWARE_TABLE y --
CONFIG_AS_HAS_NON_CONST_ULEB128 y --
========= config-merged not config-alarm-linux-aarch64 =========
CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND -- y
CONFIG_GCC11_NO_ARRAY_BOUNDS -- y
CONFIG_ACPI_HOTPLUG_CPU -- y
CONFIG_HAVE_KVM_IRQFD -- y
CONFIG_HAVE_KVM_EVENTFD -- y
CONFIG_OF_CONFIGFS -- y
CONFIG_BCM2835_SMI -- m
CONFIG_BCM2835_SMI_DEV -- m
CONFIG_MEDIA_CONTROLLER_REQUEST_API -- y
CONFIG_DRM_PANEL_CWD686 -- m
CONFIG_DRM_PANEL_CWU50 -- m
CONFIG_FB_SYS_FOPS -- y
CONFIG_BACKLIGHT_OCP8178 -- m
CONFIG_BCM_VC_SM_CMA -- m
CONFIG_XZ_DEC_IA64 -- y
CONFIG_AS_HAS_NON_CONST_LEB128 -- y
Build errors: both cpi display panels (cwd686/cwu50) failed to compile, minor type signature issues. #fixed
Now that the kernel is built, need to plug it into the RootFS… It seems that ArchLinuxARM by default packs a few different images in /boot (Image, Image.gz, kernel8.img), and the layout is different from raspbian (alarm: /boot/dtbs vs. stock: /boot/ directly)
Analyzing the alarm packages uboot-raspberrypi
and raspberrypi-bootloader
- https://forums.raspberrypi.com/viewtopic.php?t=143765
- https://archlinuxarm.org/packages/any/raspberrypi-bootloader
- https://archlinuxarm.org/packages/any/uboot-raspberrypi
Also, (everyone) please educate me how cm4 boots…
I did my research, I thought I understand, but then I realize don’t…
- From the rpi official docs it reads like once I have the proper elf and boot code binaries, the VideoCore will load the kernel and hand over the boot sequence.
- But then, ArchLinuxARM-rpi is shipped with
uboot-raspberrypi
andraspberrypi-bootloader
– what are these, and why do we have uboot here?
[root@Yatao-GPD-Arch /]# pacman -Ql raspberrypi-bootloader
raspberrypi-bootloader /boot/
raspberrypi-bootloader /boot/bootcode.bin
raspberrypi-bootloader /boot/fixup.dat
raspberrypi-bootloader /boot/fixup4.dat
raspberrypi-bootloader /boot/fixup4cd.dat
raspberrypi-bootloader /boot/fixup4db.dat
raspberrypi-bootloader /boot/fixup4x.dat
raspberrypi-bootloader /boot/fixup_cd.dat
raspberrypi-bootloader /boot/fixup_db.dat
raspberrypi-bootloader /boot/fixup_x.dat
raspberrypi-bootloader /boot/start.elf
raspberrypi-bootloader /boot/start4.elf
raspberrypi-bootloader /boot/start4cd.elf
raspberrypi-bootloader /boot/start4db.elf
raspberrypi-bootloader /boot/start4x.elf
raspberrypi-bootloader /boot/start_cd.elf
raspberrypi-bootloader /boot/start_db.elf
raspberrypi-bootloader /boot/start_x.elf
[root@Yatao-GPD-Arch /]# pacman -Ql raspberrypi-bootloader
raspberrypi-bootloader /boot/
raspberrypi-bootloader /boot/bootcode.bin
raspberrypi-bootloader /boot/fixup.dat
raspberrypi-bootloader /boot/fixup4.dat
raspberrypi-bootloader /boot/fixup4cd.dat
raspberrypi-bootloader /boot/fixup4db.dat
raspberrypi-bootloader /boot/fixup4x.dat
raspberrypi-bootloader /boot/fixup_cd.dat
raspberrypi-bootloader /boot/fixup_db.dat
raspberrypi-bootloader /boot/fixup_x.dat
raspberrypi-bootloader /boot/start.elf
raspberrypi-bootloader /boot/start4.elf
raspberrypi-bootloader /boot/start4cd.elf
raspberrypi-bootloader /boot/start4db.elf
raspberrypi-bootloader /boot/start4x.elf
raspberrypi-bootloader /boot/start_cd.elf
raspberrypi-bootloader /boot/start_db.elf
raspberrypi-bootloader /boot/start_x.elf
hmm! So in ArchLinuxARM-rpi, kernel8.img
is actually a uboot
binary – it then chainloads the real kernel image – that’s why the alarm dtb can be placed freely instead of following the VideoCore boot protocol.
We don’t need that
[root@Yatao-GPD-Arch /]# pacman -R uboot-raspberrypi linux-aarch64
We will instead use the ones we built from the kernel.
Also, now that we get rid of all the stock ArchLinuxARM-rpi boot config, we can scrape those from the original CM4 firmware.
[root@Yatao-GPD-Arch boot]# ls
LICENCE.broadcom bcm2711-rpi-4-b.dtb bcm2712-rpi-cm5-cm5io.dtb bootcode.bin fixup4x.dat start4.elf
bcm2710-rpi-2-b.dtb bcm2711-rpi-400.dtb bcm2712d0-rpi-5-b.dtb cmdline.txt fixup_cd.dat start4cd.elf
bcm2710-rpi-3-b-plus.dtb bcm2711-rpi-cm4-io.dtb bcm2837-rpi-3-a-plus.dtb config.txt fixup_db.dat start4db.elf
bcm2710-rpi-3-b.dtb bcm2711-rpi-cm4.dtb bcm2837-rpi-3-b-plus.dtb fixup.dat fixup_x.dat start4x.elf
bcm2710-rpi-cm3.dtb bcm2711-rpi-cm4s.dtb bcm2837-rpi-3-b.dtb fixup4.dat kernel8.img start_cd.elf
bcm2710-rpi-zero-2-w.dtb bcm2712-rpi-5-b.dtb bcm2837-rpi-cm3-io3.dtb fixup4cd.dat overlays start_db.elf
bcm2710-rpi-zero-2.dtb bcm2712-rpi-cm5-cm4io.dtb bcm2837-rpi-zero-2-w.dtb fixup4db.dat start.elf start_x.elf
[root@Yatao-GPD-Arch boot]# cat config.txt
disable_overscan=1
dtparam=audio=on
[pi4]
max_framebuffers=2
[all]
ignore_lcd=1
dtoverlay=dwc2,dr_mode=host
dtoverlay=vc4-kms-v3d-pi4,cma-384
dtoverlay=devterm-pmu
dtoverlay=devterm-panel-uc
dtoverlay=devterm-misc
dtoverlay=audremap,pins_12_13
dtparam=spi=on
gpio=10=ip,np
[root@Yatao-GPD-Arch boot]# cat cmdline.txt
console=serial0,115200 console=tty1 root=LABEL=ROOT_ARCH rootfstype=f2fs rw audit=0 fsck.repair=yes rootwait
@guu is there a good way to debug uc-cm4? When it’s not booting, I figure the only thing I can do is to stick it to my ear and have some very very rough idea about what’s going on by listening to the coil whine
After a dozen of transfering the microsd back and forth between uc and computer, I managed to boot it: ArchLinux ARM for uConsole CM4 -- living documentation - #4 by yatli
Until that, here’s what I did:
- Erased the card, create new filesystems (BOOT_ARCH: 512MB, ROOT_ARCH: rest), install
- No
- Why my dtb files are all 0-sized?
- forgot to install
dtc
… did that, install, no.
- forgot to install
- Throw away 6.x kernel and copy over the kernel and modules from @guu 's original kernel
- No
- Realized that the stock image partition layout has a +4MB blank area in the front.
- Use
rpi-imager
to re-create that layout and resize root (bootfs: 512MB, rootfs: rest, ext4), update /boot/cmdline.txt and /etc/fstab, install- No
- Again, throw away 6.x kernel and copy over 5.x
- No
- … What else?
- … Stupid runs like removing all the *.dtb files other than cm4
- No no no no no.
- … Wait… The coils are so much quieter this time. It means the kernel is loaded, but the rootfs is not found, cores sleeping.
- use root=PARTUUID instead of root=LABEL??
- YES!
Main quest still continues. I want kernel 6.x, ideally 6.8 (on par with Arch – how did they achieve that? rpi HEAD is still at 6.6.y).
Side mission is activated because I accidentally destroyed the keyboard firmware – it’s stuck in DFU mode now
Side mission progressing to phase 2 because it’s not even in DFU mode now. Waiting for uart flashing kit.
20240405
The keyboard is rescued successfully. Pop stack and continue.
rpi source tree HEAD (6.6.y) did not work – so I’m thinking of two different routes here:
- Use an RPi release tag. The latest tag is
1.20230405
, which is based on the upstream release6.1.21
- Use ArchLinux source.
Currently, 1) got better result than 6.6.y
– the backlight came on and off a few times, meaning that not only the kernel boots up, it also loads the ocp8178 backlight driver and pulses the GPIOs to initiate the backlight control.
Still got a blank screen and unable to shutdown the device cleanly. Need a way to properly debug the device.
Due to the lack of debugging ports, I’m thinking of adding a usb-serial cable as the main console.
I also need some proper crosscompile toolchain. Building the kernel inside chroot is sooo slow.
0406
aarch64-linux-gnu-gcc package brought down build time from 4 hours to 20mins.
And I realized something’s not right – where is initrd???
How did I even boot the Arch with the Raspbian kernel, without an initrd??
Without that, a lot of hooks will be dismissed (esp. udevd), and that’s why I’m easily stuck during pacman operations, warning me that udevd did not complete the queue…
However, because the backlight is active, we know that 1) the kernel loads, 2) devterm dt overlays load, 3) rootfs is detected and mounted successfully because ocp8178 is a module, not built into the kernel.
TODO: better debug than watching backlight and listening to coil whine:
- ttyusb console – if the kernel boots, this is very promising.
(and in case this does not work…) - plug in a keyboard to see if capslock etc. are responsive (doubt it, because power key doesn’t shut it down)
- if so, great, plug in usb ethernet and wait at the router to ssh in
- chroot into it, write a systemd task to blink the lcd backlight to send out moorse code – don’t worry, I’ve done this before on devterm, only with the fan instead of screen.
Update: actually it boots just fine!
We’ve got a blank display, and wonky power key, but other than that, it boots just fine! This is verified by blind typing to log in and sudo reboot
.
edit: stupid error, axp228 not cutting down power.sudo systemctl poweroff
did not work, probably the same way the power key didn’t – the kernel is not compatible with my axp228 patches.
Now I can setup a router to have the same SSID and password as remembered by uC and ssh in.