From 74f0d54dc320b29e4dd3cc427d49e9e4c0454be2 Mon Sep 17 00:00:00 2001 From: Daniel Rossier Date: Fri, 17 Jul 2026 12:07:48 +0200 Subject: [PATCH] rpi4_64: make the I2C/Sense HAT path work on 64-bit The i2c_bsc and rpisense drivers date from the 32-bit rpi4 platform and had never actually run on rpi4_64. Enabling them there boots to complete silence. Three leftovers from the 32->64-bit move, each invisible until a 64-bit build exercised this code: 1. Kconfig depended on RPI4, a symbol that no longer exists (arm32 only carries VIRT32 now), so I2C_BSC and RPI_SENSE were not selectable on rpi4_64. devices/serial/Kconfig was already updated to "RPI4 || RPI4_64" when rpi4_64 landed; i2c and rpisense were missed. Use the same form rather than RPI4_64 alone, so a returning 32-bit platform keeps working. 2. Both drivers stored the io_map() return value in a uint32_t. io_map() returns addr_t, and on arm64 the virtual address sits at CONFIG_IO_MAPPING_BASE (0xffff9000_00000000), so the top half was cut off and the driver dereferenced the truncated address. Both are REGISTER_DRIVER_CORE, i.e. they probe *before* the POSTCORE serial console: the resulting abort killed the kernel with no output at all. On arm32 IO_MAPPING_BASE is 0xe0000000, which is why the bug slept there. 3. bsp/rpi4/config.txt never got the 64-bit boot settings. The deploy installs the aarch64 U-Boot as kernel8.img, but the firmware defaults arm_64bit to 0 and looks for kernel7l.img, so nothing is loaded and there is no output at all. config.txt is shared by every rpi4 BSP, and a 32- and a 64-bit chain need opposite values there. Rather than hardcode the 64-bit ones, keep the file as the common part and let each BSP append a config_rpi4_arm{32,64}.txt fragment after copying the directory. Only bsp_rpi4_64.inc consumes one today; the arm32 fragment is in place for the 32-bit platform. Also disable the HAT EEPROM read. With a Sense HAT fitted, the firmware merges the HAT's overlay into the DT it passes to U-Boot; that DT has no /chosen/stdout-path, so U-Boot picks its console by node order, and the merge made it drive the wrong UART and boot silently. Isolated to a single variable: same board, same card, HAT removed -> U-Boot starts. SO3 drives the HAT through rpisense and does not need the overlay. Validated on real hardware (RPi 4 Model B, 1 GB, Sense HAT fitted): U-Boot starts, boots the FIT image, SO3 6.2.3 reaches userspace, and the HAT's LEDs and joystick respond. --- .../recipes-bsp/bsp/files/bsp_rpi4_64.inc | 7 +++++++ .../bsp/files/config_rpi4_arm32.txt | 7 +++++++ .../bsp/files/config_rpi4_arm64.txt | 9 ++++++++ .../meta-bsp/recipes-bsp/bsp/rpi4/config.txt | 21 +++++++++++++++++++ so3/so3/devices/i2c/Kconfig | 2 +- so3/so3/devices/i2c/i2c_bsc.c | 7 ++++++- so3/so3/devices/rpisense/Kconfig | 2 +- so3/so3/devices/rpisense/rpisense.c | 6 +++++- 8 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm32.txt create mode 100644 build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm64.txt diff --git a/build/meta-bsp/recipes-bsp/bsp/files/bsp_rpi4_64.inc b/build/meta-bsp/recipes-bsp/bsp/files/bsp_rpi4_64.inc index 48d3a408e2..b0b55d0e5e 100644 --- a/build/meta-bsp/recipes-bsp/bsp/files/bsp_rpi4_64.inc +++ b/build/meta-bsp/recipes-bsp/bsp/files/bsp_rpi4_64.inc @@ -16,6 +16,13 @@ def __do_platform_deploy(d): uboot_path = d.getVar('IB_UBOOT_PATH') run(f"cp -r {filedirname}/../bsp/rpi4/* {dst}/p1") + + # bsp/rpi4/config.txt is shared with the 32-bit BSP and deliberately holds + # no arm_64bit/kernel setting; append the 64-bit half of the chain. + # FILE_DIRNAME is the *recipe's* directory (recipes-bsp/so3), not this + # include's — hence the ../bsp hop, as in the copy above. + run(f"cat {filedirname}/../bsp/files/config_rpi4_arm64.txt >> {dst}/p1/config.txt") + run(f"cp {uboot_path}/u-boot.bin {dst}/p1/kernel8.img") __deploy_arm_common(d) diff --git a/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm32.txt b/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm32.txt new file mode 100644 index 0000000000..3526a07fc7 --- /dev/null +++ b/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm32.txt @@ -0,0 +1,7 @@ + +# --- 32-bit boot chain (appended by bsp_rpi4.inc) --- +# The deploy installs the arm32 U-Boot as kernel7l.img. arm_64bit=0 is the +# firmware default, but state both explicitly so the loaded file never depends +# on the firmware's 32/64-bit filename default. +arm_64bit=0 +kernel=kernel7l.img diff --git a/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm64.txt b/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm64.txt new file mode 100644 index 0000000000..11a03f05b3 --- /dev/null +++ b/build/meta-bsp/recipes-bsp/bsp/files/config_rpi4_arm64.txt @@ -0,0 +1,9 @@ + +# --- 64-bit boot chain (appended by bsp_rpi4_64.inc) --- +# The deploy installs the aarch64 U-Boot as kernel8.img. This firmware +# (bcm2711, Aug 2021) defaults arm_64bit to 0, so without this it starts the +# cores in 32-bit mode and looks for kernel7l.img, never finds it, and boots +# nothing at all — no serial output whatsoever. kernel= is stated explicitly so +# the loaded file never depends on the firmware's filename default. +arm_64bit=1 +kernel=kernel8.img diff --git a/build/meta-bsp/recipes-bsp/bsp/rpi4/config.txt b/build/meta-bsp/recipes-bsp/bsp/rpi4/config.txt index c69ea6e544..002f7c7c45 100644 --- a/build/meta-bsp/recipes-bsp/bsp/rpi4/config.txt +++ b/build/meta-bsp/recipes-bsp/bsp/rpi4/config.txt @@ -65,3 +65,24 @@ max_framebuffers=2 #dtoverlay=vc4-fkms-v3d enable_uart=1 + +# Don't read an attached HAT's EEPROM. The firmware would merge the HAT's own +# overlay into the device tree it hands to U-Boot, and that DT carries no +# /chosen/stdout-path — so U-Boot picks its console by DT node order, which the +# merge perturbs: with a Sense HAT fitted, U-Boot drives the wrong UART and +# boots in complete silence. SO3 talks to the HAT through its own rpisense +# driver and never needs the overlay. Applies to both 32- and 64-bit. +force_eeprom_read=0 + +# The 32/64-bit boot settings are NOT here: this file is shared by every rpi4 +# BSP, and the two chains need opposite values (kernel7l.img vs kernel8.img). +# bsp_rpi4.inc / bsp_rpi4_64.inc append the right config_rpi4_arm{32,64}.txt +# fragment after copying this directory. + +# Diagnostic only — echoes the firmware's own boot stage on the UART, which is +# how you tell a failure *before* U-Boot from a dead board. Leave it OFF for +# normal boots: to print, the firmware muxes GPIO14/15 to the PL011 and resets +# its baud, while the DT gives serial0 = the mini-UART (7e215040, the one SO3 +# drives). The pins then stay on the wrong peripheral and U-Boot's output never +# reaches the wire. +#uart_2ndstage=1 diff --git a/so3/so3/devices/i2c/Kconfig b/so3/so3/devices/i2c/Kconfig index 8446f260c0..9fa4cf7506 100644 --- a/so3/so3/devices/i2c/Kconfig +++ b/so3/so3/devices/i2c/Kconfig @@ -2,4 +2,4 @@ config I2C_BSC default y depends on I2C bool "I2C Broadcom Serial Controller (BSC) interface" - depends on RPI4 + depends on RPI4 || RPI4_64 diff --git a/so3/so3/devices/i2c/i2c_bsc.c b/so3/so3/devices/i2c/i2c_bsc.c index 63605fe9ca..5865f897e5 100644 --- a/so3/so3/devices/i2c/i2c_bsc.c +++ b/so3/so3/devices/i2c/i2c_bsc.c @@ -211,7 +211,12 @@ static int i2c_bsc_init(dev_t *dev, int fdt_offset) const struct fdt_property *prop; int prop_len; uint32_t mask; - uint32_t gpio_regs_addr; + + /* addr_t, not uint32_t: io_map() hands back a virtual address, which on + * arm64 sits at CONFIG_IO_MAPPING_BASE (0xffff9000_00000000) and would + * lose its top half in a 32-bit variable. + */ + addr_t gpio_regs_addr; LOG_DEBUG("I2C broadcom - Initialization\n"); diff --git a/so3/so3/devices/rpisense/Kconfig b/so3/so3/devices/rpisense/Kconfig index fe4f874183..bec14548a8 100644 --- a/so3/so3/devices/rpisense/Kconfig +++ b/so3/so3/devices/rpisense/Kconfig @@ -1,5 +1,5 @@ config RPI_SENSE bool "Driver for the Sense Hat extension board" - depends on RPI4 + depends on RPI4 || RPI4_64 \ No newline at end of file diff --git a/so3/so3/devices/rpisense/rpisense.c b/so3/so3/devices/rpisense/rpisense.c index 706c6b016a..bea5cb411f 100644 --- a/so3/so3/devices/rpisense/rpisense.c +++ b/so3/so3/devices/rpisense/rpisense.c @@ -35,7 +35,11 @@ #include -static uint32_t gpio_regs_addr; +/* addr_t, not uint32_t: io_map() hands back a virtual address, which on arm64 + * sits at CONFIG_IO_MAPPING_BASE (0xffff9000_00000000) and would lose its top + * half in a 32-bit variable. + */ +static addr_t gpio_regs_addr; uint8_t leds_array[SIZE_FB];