Skip to content

rpi4_64: make the I2C/Sense HAT path work on 64-bit - #302

Merged
daniel-rossier merged 1 commit into
mainfrom
fix/rpi4-64-i2c-rpisense
Jul 17, 2026
Merged

rpi4_64: make the I2C/Sense HAT path work on 64-bit#302
daniel-rossier merged 1 commit into
mainfrom
fix/rpi4-64-i2c-rpisense

Conversation

@daniel-rossier

@daniel-rossier daniel-rossier commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Problem

The i2c_bsc and rpisense drivers come from the 32-bit rpi4 platform and had never actually run on rpi4_64. Enabling them there (CONFIG_I2C_BSC/CONFIG_RPI_SENSE + status = "ok" on the i2c1/rpisense DT nodes) boots to complete silence — no kernel output at all.

Three independent leftovers from the 32→64-bit move, each invisible until a 64-bit build exercised this code:

1. Kconfig hangs off a dead symbol

devices/i2c/Kconfig:5:       depends on RPI4
devices/rpisense/Kconfig:3:  depends on RPI4

RPI4 no longer exists — arch/arm32/Kconfig only carries VIRT32; the 64-bit board is RPI4_64. So I2C_BSC and RPI_SENSE are simply not selectable on rpi4_64.

devices/serial/Kconfig:12 already reads depends on RPI4 || RPI4_64 — it was updated when rpi4_64 landed and i2c/rpisense were missed. This PR uses the same form rather than RPI4_64 alone, so a returning 32-bit platform keeps working.

2. io_map() return value truncated to 32 bits

addr_t io_map(addr_t phys, size_t size);   /* 64-bit on arm64 */
uint32_t gpio_regs_addr;                   /* i2c_bsc.c:214, rpisense.c:38 */
gpio_regs_addr = io_map(GPIO_REGS_ADDR, 0xF0);
mask = ioread32(gpio_regs_addr + GPIO_FSEL0_OFF);

On arm64 the mapped virtual address sits at CONFIG_IO_MAPPING_BASE (0xffff9000_00000000), so a uint32_t drops the top half and the driver dereferences the truncated address. On ARM32 addr_t was 32-bit and the code was correct.

Why the total silence: both are REGISTER_DRIVER_CORE, so they probe before the POSTCORE serial console — the abort kills the kernel before there is anything to print with.

3. config.txt never got the 64-bit boot settings

The deploy installs the aarch64 U-Boot as kernel8.img, but this firmware (bcm2711, Aug 2021) defaults arm_64bit to 0 and looks for kernel7l.img — nothing is loaded, no output. Now sets arm_64bit=1 and names the kernel explicitly.

Bonus: the Sense HAT blocked U-Boot entirely

With a HAT fitted the firmware merges the HAT's EEPROM overlay into the DT it hands to U-Boot (Loaded HAT overlay in the firmware log). That DT has no /chosen/stdout-path, so U-Boot picks its console by DT node order — the merge perturbs it and U-Boot drives the wrong UART, booting in silence. Isolated to one variable: same board, same card, HAT removed → U-Boot starts.

force_eeprom_read=0 avoids it. SO3 talks to the HAT through its own rpisense driver and never needs the overlay.

Test

Real hardware, RPi 4 Model B (0xc03111, 1 GB), Sense HAT fitted:

U-Boot 2022.04 (Jul 17 2026 - 10:46:05 +0200)
DRAM:  948 MiB
RPI 4 Model B (0xc03111)
...
Starting kernel ...
********** Smart Object Oriented SO3 Operating System **********
Version 6.2.3
[SO3 USR] Starting the initial process

SO3 reaches userspace with i2c_bsc and rpisense probing at CORE, and the HAT's LED matrix and joystick respond.

Notes

  • config.txt is shared by every rpi4 BSP, so the 32/64-bit settings live in the appended config_rpi4_arm{32,64}.txt fragments rather than in the file itself. Only bsp_rpi4_64.inc consumes one today.
  • Enabling i2c1/rpisense in rpi4_64.dts is deliberately not part of this PR: they are CORE drivers, so turning them on by default would make every rpi4_64 probe a Sense HAT that may not be there.
  • Separate gap noticed while testing, addressed on its own in rpi4: restore the firmware device trees the *.dtb rule swallowed #305: build/meta-bsp/recipes-bsp/bsp/rpi4/ ships no .dtb, so the deploy relies on whatever DTB already sits on the card.

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.
@daniel-rossier
daniel-rossier force-pushed the fix/rpi4-64-i2c-rpisense branch from 9c85fa0 to 74f0d54 Compare July 17, 2026 10:07
@daniel-rossier
daniel-rossier merged commit e095725 into main Jul 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant