[PATCH] hw/arm/bcm2838: Route I2C interrupts to GIC

Nicholas Righi posted 1 patch 5 days, 13 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260525032634.7754-1-nicholasrighi@gmail.com
Maintainers: Peter Maydell <peter.maydell@linaro.org>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
hw/arm/bcm2838.c                     | 3 +++
include/hw/arm/bcm2838_peripherals.h | 1 +
2 files changed, 4 insertions(+)
[PATCH] hw/arm/bcm2838: Route I2C interrupts to GIC
Posted by Nicholas Righi 5 days, 13 hours ago
The I2C interrupts are only routed to the legacy interrupt controller. This means
that for modern device trees that use the GIC, the interrupts don't work. This patch
re-routes the I2C OR'd interrupt from the legacy interrupt controller to the GIC so
I2C emulation works out of the box with current kernels.

Testing

Add these lines to QEMU invocation

-drive if=none,id=i2c_storage,format=raw,file=eeprom.bin \
-device at24c-eeprom,bus=i2c-bus.1,address=0x50,drive=i2c_storage,rom-size=4096 \

note: eeprom.bin is all zeros

Before this change, running i2c get to read from EEPROM would result in this

i2cget -y 1 0x50
Error: Read failed

After this change, running i2c to read from EEPROM results in this

i2cget -y 1 0x50
0x00

The eeprom can now also be enabled in the device tree. Before the
eeprom driver load would fail due to the read failing

ls -l /sys/bus/i2c/devices/i2c-1/1-0050/ | grep -i eeprom
-rw------- 1 root root 4096 May 17 16:57 eeprom

Signed-off-by: Nicholas Righi <nicholasrighi@gmail.com>
---
 hw/arm/bcm2838.c                     | 3 +++
 include/hw/arm/bcm2838_peripherals.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
index c14a854046..6895f70385 100644
--- a/hw/arm/bcm2838.c
+++ b/hw/arm/bcm2838.c
@@ -184,6 +184,9 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
     sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->aux), 0,
                        qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_AUX_UART1));
 
+    qdev_connect_gpio_out(DEVICE(&ps_base->orgated_i2c_irq), 0,
+                        qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_I2C));
+
     /* Connect VC mailbox to the interrupt controller */
     sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mboxes), 0,
                        qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MBOX));
diff --git a/include/hw/arm/bcm2838_peripherals.h b/include/hw/arm/bcm2838_peripherals.h
index 7ee1bd066f..0be97e67c7 100644
--- a/include/hw/arm/bcm2838_peripherals.h
+++ b/include/hw/arm/bcm2838_peripherals.h
@@ -22,6 +22,7 @@
 #define GIC_SPI_INTERRUPT_DMA_7_8      87
 #define GIC_SPI_INTERRUPT_DMA_9_10     88
 #define GIC_SPI_INTERRUPT_AUX_UART1    93
+#define GIC_SPI_INTERRUPT_I2C          117
 #define GIC_SPI_INTERRUPT_SDHOST       120
 #define GIC_SPI_INTERRUPT_UART0        121
 #define GIC_SPI_INTERRUPT_RNG200       125
-- 
2.51.2
Re: [PATCH] hw/arm/bcm2838: Route I2C interrupts to GIC
Posted by Peter Maydell 4 days, 8 hours ago
On Mon, 25 May 2026 at 04:26, Nicholas Righi <nicholasrighi@gmail.com> wrote:
>
> The I2C interrupts are only routed to the legacy interrupt controller. This means
> that for modern device trees that use the GIC, the interrupts don't work. This patch
> re-routes the I2C OR'd interrupt from the legacy interrupt controller to the GIC so
> I2C emulation works out of the box with current kernels.
>

> diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
> index c14a854046..6895f70385 100644
> --- a/hw/arm/bcm2838.c
> +++ b/hw/arm/bcm2838.c
> @@ -184,6 +184,9 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
>      sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->aux), 0,
>                         qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_AUX_UART1));
>
> +    qdev_connect_gpio_out(DEVICE(&ps_base->orgated_i2c_irq), 0,
> +                        qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_I2C));

We already connect this output from orgated_i2c_irq to
somewhere else, in hw/arm/bcm2835_peripherals.c:

    qdev_connect_gpio_out(DEVICE(&s->orgated_i2c_irq), 0,
                          qdev_get_gpio_in_named(DEVICE(&s->ic),
                                                 BCM2835_IC_GPU_IRQ,
                                                 INTERRUPT_I2C));

It is not possible to connect one GPIO output to two places
like this -- the second call will silently override the first one.
You need to create a TYPE_IRQ_SPLIT object, connect the
output from the device to the input of the splitter, and
connect the outputs of the splitter to the legacy interrupt
controller and the GIC.

thanks
-- PMM
Re: [PATCH] hw/arm/bcm2838: Route I2C interrupts to GIC
Posted by Philippe Mathieu-Daudé 4 days, 9 hours ago
On 25/5/26 05:26, Nicholas Righi wrote:
> The I2C interrupts are only routed to the legacy interrupt controller. This means
> that for modern device trees that use the GIC, the interrupts don't work. This patch
> re-routes the I2C OR'd interrupt from the legacy interrupt controller to the GIC so
> I2C emulation works out of the box with current kernels.
> 
> Testing
> 
> Add these lines to QEMU invocation
> 
> -drive if=none,id=i2c_storage,format=raw,file=eeprom.bin \
> -device at24c-eeprom,bus=i2c-bus.1,address=0x50,drive=i2c_storage,rom-size=4096 \
> 
> note: eeprom.bin is all zeros
> 
> Before this change, running i2c get to read from EEPROM would result in this
> 
> i2cget -y 1 0x50
> Error: Read failed
> 
> After this change, running i2c to read from EEPROM results in this
> 
> i2cget -y 1 0x50
> 0x00
> 
> The eeprom can now also be enabled in the device tree. Before the
> eeprom driver load would fail due to the read failing
> 
> ls -l /sys/bus/i2c/devices/i2c-1/1-0050/ | grep -i eeprom
> -rw------- 1 root root 4096 May 17 16:57 eeprom
> 
> Signed-off-by: Nicholas Righi <nicholasrighi@gmail.com>
> ---
>   hw/arm/bcm2838.c                     | 3 +++
>   include/hw/arm/bcm2838_peripherals.h | 1 +
>   2 files changed, 4 insertions(+)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>