hw/arm/bcm2835_peripherals.c | 9 +++++++++ hw/arm/bcm2838.c | 4 ++++ include/hw/arm/bcm2835_peripherals.h | 2 ++ include/hw/arm/bcm2838_peripherals.h | 1 + 4 files changed, 16 insertions(+)
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
adds a splitter to route the I2C interrupt to both the legacy interrupt controller and the GIC.
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>
---
Changes v1 -> v2:
- Use a splitter to route the OR gated i2c interrupt to both the
legacy interrupt controller and the GIC, instead of just replacing
the legacy routing with the GIC routing
---
hw/arm/bcm2835_peripherals.c | 9 +++++++++
hw/arm/bcm2838.c | 4 ++++
include/hw/arm/bcm2835_peripherals.h | 2 ++
include/hw/arm/bcm2838_peripherals.h | 1 +
4 files changed, 16 insertions(+)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 8a1e72dfab..558c180df9 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -179,6 +179,8 @@ static void raspi_peripherals_base_init(Object *obj)
&s->orgated_i2c_irq, TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->orgated_i2c_irq), "num-lines",
ORGATED_I2C_IRQ_COUNT, &error_abort);
+ object_initialize_child(obj, "orgated-i2c-irq-splitter",
+ &s->orgated_i2c_irq_splitter, TYPE_SPLIT_IRQ);
}
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
@@ -504,7 +506,14 @@ void bcm_soc_peripherals_common_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[n]), 0,
qdev_get_gpio_in(DEVICE(&s->orgated_i2c_irq), n));
}
+
+ qdev_prop_set_uint32(DEVICE(&s->orgated_i2c_irq_splitter), "num-lines", 2);
+ if (!qdev_realize(DEVICE(&s->orgated_i2c_irq_splitter), NULL, errp)) {
+ return;
+ }
qdev_connect_gpio_out(DEVICE(&s->orgated_i2c_irq), 0,
+ qdev_get_gpio_in(DEVICE(&s->orgated_i2c_irq_splitter), 0));
+ qdev_connect_gpio_out(DEVICE(&s->orgated_i2c_irq_splitter), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_I2C));
diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
index c14a854046..089af412a3 100644
--- a/hw/arm/bcm2838.c
+++ b/hw/arm/bcm2838.c
@@ -184,6 +184,10 @@ 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));
+ /* Connect the I2C interrupt to the interrupt controller */
+ qdev_connect_gpio_out(DEVICE(&ps_base->orgated_i2c_irq_splitter), 1,
+ 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/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index bf35bb18e5..4f356f4643 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -33,6 +33,7 @@
#include "hw/usb/hcd-dwc2.h"
#include "hw/ssi/bcm2835_spi.h"
#include "hw/i2c/bcm2835_i2c.h"
+#include "hw/core/split-irq.h"
#include "hw/nvram/bcm2835_otp.h"
#include "hw/misc/unimp.h"
#include "qom/object.h"
@@ -72,6 +73,7 @@ struct BCMSocPeripheralBaseState {
BCM2835SPIState spi[1];
BCM2835I2CState i2c[3];
OrIRQState orgated_i2c_irq;
+ SplitIRQ orgated_i2c_irq_splitter;
BCM2835OTPState otp;
UnimplementedDeviceState dbus;
UnimplementedDeviceState ave0;
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.54.0
On Tue, 9 Jun 2026 at 03:40, 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 > adds a splitter to route the I2C interrupt to both the legacy interrupt controller and the GIC. > > 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> > --- > Changes v1 -> v2: > - Use a splitter to route the OR gated i2c interrupt to both the > legacy interrupt controller and the GIC, instead of just replacing > the legacy routing with the GIC routing > --- > hw/arm/bcm2835_peripherals.c | 9 +++++++++ > hw/arm/bcm2838.c | 4 ++++ > include/hw/arm/bcm2835_peripherals.h | 2 ++ > include/hw/arm/bcm2838_peripherals.h | 1 + > 4 files changed, 16 insertions(+) Applied to target-arm.next, thanks. -- PMM
On 16/6/26 13:10, Peter Maydell wrote: > On Tue, 9 Jun 2026 at 03:40, 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 >> adds a splitter to route the I2C interrupt to both the legacy interrupt controller and the GIC. >> >> 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> >> --- >> Changes v1 -> v2: >> - Use a splitter to route the OR gated i2c interrupt to both the >> legacy interrupt controller and the GIC, instead of just replacing >> the legacy routing with the GIC routing >> --- >> hw/arm/bcm2835_peripherals.c | 9 +++++++++ >> hw/arm/bcm2838.c | 4 ++++ >> include/hw/arm/bcm2835_peripherals.h | 2 ++ >> include/hw/arm/bcm2838_peripherals.h | 1 + >> 4 files changed, 16 insertions(+) > > > > Applied to target-arm.next, thanks. Too late but still it was in my review queue: Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
On Tue, 16 Jun 2026 at 15:59, Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> wrote: > > On 16/6/26 13:10, Peter Maydell wrote: > > On Tue, 9 Jun 2026 at 03:40, 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 > >> adds a splitter to route the I2C interrupt to both the legacy interrupt controller and the G > > Applied to target-arm.next, thanks. > > Too late but still it was in my review queue: > Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> I haven't done anything with my queue yet, so I've added your R-by tag; thanks! -- PMM
© 2016 - 2026 Red Hat, Inc.