hw/arm/bcm2838: Route I2C interrupts to GIC

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>
Message-id: 20260609024027.22140-1-nicholasrighi@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Nicholas Righi
2026-06-08 19:40:27 -07:00
committed by Peter Maydell
parent 335870f28e
commit fb3e0557a4
4 changed files with 16 additions and 0 deletions

View File

@@ -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));

View File

@@ -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));

View File

@@ -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;

View File

@@ -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