[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v4 05/45] Add GIC-400 to BCM2838 SoC
From: |
Peter Maydell |
Subject: |
Re: [PATCH v4 05/45] Add GIC-400 to BCM2838 SoC |
Date: |
Mon, 18 Dec 2023 16:23:24 +0000 |
On Fri, 8 Dec 2023 at 02:32, Sergey Kambalin <serg.oker@gmail.com> wrote:
>
> Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
> ---
> hw/arm/bcm2838.c | 167 +++++++++++++++++++++++++++
> hw/arm/trace-events | 2 +
> include/hw/arm/bcm2838.h | 2 +
> include/hw/arm/bcm2838_peripherals.h | 39 +++++++
> 4 files changed, 210 insertions(+)
>
> diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
> index c61c59661b..042e543006 100644
> --- a/hw/arm/bcm2838.c
> +++ b/hw/arm/bcm2838.c
> @@ -14,8 +14,36 @@
> #include "hw/arm/bcm2838.h"
> #include "trace.h"
>
> +#define GIC400_MAINTAINANCE_IRQ 9
"MAINTENANCE"
> +#define GIC400_TIMER_NS_EL2_IRQ 10
> +#define GIC400_TIMER_VIRT_IRQ 11
> +#define GIC400_LEGACY_FIQ 12
> +#define GIC400_TIMER_S_EL1_IRQ 13
> +#define GIC400_TIMER_NS_EL1_IRQ 14
> +#define GIC400_LEGACY_IRQ 15
For the virt and sbsa-ref boards we found that having interrupt
#defines use the PPI number was on net a bit confusing, so we
standardized on having the defines be the architectural INTID
(which is the PPI number + 16). See commit 9036e917f8357f4.
But I mention this more as an FYI kind of thing because changing
the numbering base at this point is probably more likely to
introduce bugs than remove them...
> +/* Number of external interrupt lines to configure the GIC with */
> +#define GIC_NUM_IRQS 192
> +
> +#define PPI(cpu, irq) (GIC_NUM_IRQS + (cpu) * GIC_INTERNAL + GIC_NR_SGIS +
> irq)
> +
> +#define GIC_BASE_OFS 0x0000
> +#define GIC_DIST_OFS 0x1000
> +#define GIC_CPU_OFS 0x2000
> +#define GIC_VIFACE_THIS_OFS 0x4000
> +#define GIC_VIFACE_OTHER_OFS(cpu) (0x5000 + (cpu) * 0x200)
> +#define GIC_VCPU_OFS 0x6000
> +
> #define VIRTUAL_PMU_IRQ 7
>
> +static void bcm2838_gic_set_irq(void *opaque, int irq, int level)
> +{
> + BCM2838State *s = (BCM2838State *)opaque;
> +
> + trace_bcm2838_gic_set_irq(irq, level);
> + qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
> +}
> +
> static void bcm2838_init(Object *obj)
> {
> BCM2838State *s = BCM2838(obj);
> @@ -28,11 +56,14 @@ static void bcm2838_init(Object *obj)
> "vcram-size");
> object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
> "command-line");
> +
> + object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
> }
>
> static void bcm2838_realize(DeviceState *dev, Error **errp)
> {
> int n;
> + int int_n;
This is not a good name for a variable, especially in a
function that already has an "n" variable. As far as I can see
the use added here doesn't overlap with the existing "n" so
you could just reuse that.
Note that our coding style these days permits declaration of
loop variables inside the for():
for (int i = 0; i < ARRAY_SIZE(thing); i++) {
/* do something loopy */
}
so if you prefer you can have all the loops in the function do that
and not have any local n declared at the top of the function.
> BCM2838State *s = BCM2838(dev);
> BCM283XBaseState *s_base = BCM283X_BASE(dev);
> BCM283XBaseClass *bc_base = BCM283X_BASE_GET_CLASS(dev);
> @@ -56,6 +87,13 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
> /* TODO: this should be converted to a property of ARM_CPU */
> s_base->cpu[n].core.mp_affinity = (bc_base->clusterid << 8) | n;
>
> + /* set periphbase/CBAR value for CPU-local registers */
> + if (!object_property_set_int(OBJECT(&s_base->cpu[n].core),
> "reset-cbar",
> + bc_base->ctrl_base + BCM2838_GIC_BASE,
> + errp)) {
> + return;
> + }
This one doesn't need an error check either; compare
https://lore.kernel.org/qemu-devel/20231123143813.42632-3-philmd@linaro.org/
> +
> /* start powered off if not enabled */
> if (!object_property_set_bool(OBJECT(&s_base->cpu[n].core),
> "start-powered-off",
> @@ -68,6 +106,135 @@ static void bcm2838_realize(DeviceState *dev, Error
> **errp)
> return;
> }
> }
> +
> + if (!object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp)) {
> + return;
> + }
> +
> + if (!object_property_set_uint(OBJECT(&s->gic), "num-cpu", BCM283X_NCPUS,
> + errp)) {
> + return;
> + }
> +
> + if (!object_property_set_uint(OBJECT(&s->gic), "num-irq",
> + GIC_NUM_IRQS + GIC_INTERNAL, errp)) {
> + return;
> + }
> +
> + if (!object_property_set_bool(OBJECT(&s->gic),
> + "has-virtualization-extensions", true,
> + errp)) {
> + return;
> + }
> +
> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
> + return;
> + }
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
> + bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_DIST_OFS);
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
> + bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_CPU_OFS);
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
> + bc_base->ctrl_base + BCM2838_GIC_BASE +
> GIC_VIFACE_THIS_OFS);
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
> + bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VCPU_OFS);
> +
> + for (n = 0; n < BCM283X_NCPUS; n++) {
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
> + bc_base->ctrl_base + BCM2838_GIC_BASE
> + + GIC_VIFACE_OTHER_OFS(n));
> + }
> +
> + DeviceState *gicdev = DEVICE(&s->gic);
Our coding style says don't put declarations in the middle
of a code block. They should go at the start of blocks.
> +
> + for (n = 0; n < BCM283X_NCPUS; n++) {
> + DeviceState *cpudev = DEVICE(&s_base->cpu[n]);
> +
> + /* Connect the GICv2 outputs to the CPU */
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n,
> + qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + BCM283X_NCPUS,
> + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 2 * BCM283X_NCPUS,
> + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 3 * BCM283X_NCPUS,
> + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
> +
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 4 * BCM283X_NCPUS,
> + qdev_get_gpio_in(gicdev,
> + PPI(n,
> GIC400_MAINTAINANCE_IRQ)));
> +
> + /* Connect timers from the CPU to the interrupt controller */
> + qdev_connect_gpio_out(cpudev, GTIMER_PHYS,
> + qdev_get_gpio_in(gicdev, PPI(n,
> GIC400_TIMER_NS_EL1_IRQ)));
> + qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
> + qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_VIRT_IRQ)));
> + qdev_connect_gpio_out(cpudev, GTIMER_HYP,
> + qdev_get_gpio_in(gicdev, PPI(n,
> GIC400_TIMER_NS_EL2_IRQ)));
> + qdev_connect_gpio_out(cpudev, GTIMER_SEC,
> + qdev_get_gpio_in(gicdev, PPI(n,
> GIC400_TIMER_S_EL1_IRQ)));
> + /* PMU interrupt */
> + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
> + qdev_get_gpio_in(gicdev, PPI(n, VIRTUAL_PMU_IRQ)));
> + }
> +
> + /* Connect UART0 to the interrupt controller */
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->uart0), 0,
> + qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_UART0));
> +
> + /* Connect AUX / UART1 to the interrupt controller */
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->aux), 0,
> + qdev_get_gpio_in(gicdev,
> GIC_SPI_INTERRUPT_AUX_UART1));
> +
> + /* 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));
> +
> + /* Connect SD host to the interrupt controller */
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->sdhost), 0,
> + qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_SDHOST));
> +
> + /* According to DTS, EMMC and EMMC2 share one irq */
> + DeviceState *mmc_irq_orgate = DEVICE(&ps->mmc_irq_orgate);
> +
> + /* Connect EMMC and EMMC2 to the interrupt controller */
> + qdev_connect_gpio_out(mmc_irq_orgate, 0,
> + qdev_get_gpio_in(gicdev,
> GIC_SPI_INTERRUPT_EMMC_EMMC2));
> +
> + /* Connect USB OTG and MPHI to the interrupt controller */
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mphi), 0,
> + qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MPHI));
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dwc2), 0,
> + qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DWC2));
> +
> + /* Connect DMA 0-6 to the interrupt controller */
> + for (int_n = GIC_SPI_INTERRUPT_DMA_0; int_n <= GIC_SPI_INTERRUPT_DMA_6;
> + int_n++) {
> + sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dma),
> + int_n - GIC_SPI_INTERRUPT_DMA_0,
> + qdev_get_gpio_in(gicdev, int_n));
> + }
> +
> + /* According to DTS, DMA 7 and 8 share one irq */
> + DeviceState *dma_7_8_irq_orgate = DEVICE(&ps->dma_7_8_irq_orgate);
> +
> + /* Connect DMA 7-8 to the interrupt controller */
> + qdev_connect_gpio_out(dma_7_8_irq_orgate, 0,
> + qdev_get_gpio_in(gicdev,
> GIC_SPI_INTERRUPT_DMA_7_8));
> +
> + /* According to DTS, DMA 9 and 10 share one irq */
> + DeviceState *dma_9_10_irq_orgate = DEVICE(&ps->dma_9_10_irq_orgate);
> +
> + /* Connect DMA 9-10 to the interrupt controller */
> + qdev_connect_gpio_out(dma_9_10_irq_orgate, 0,
> + qdev_get_gpio_in(gicdev,
> GIC_SPI_INTERRUPT_DMA_9_10));
> +
> + /* Pass through inbound GPIO lines to the GIC */
> + qdev_init_gpio_in(dev, bcm2838_gic_set_irq, GIC_NUM_IRQS);
> +
> + /* Pass through outbound IRQ lines from the GIC */
> + qdev_pass_gpios(DEVICE(&s->gic), DEVICE(&s->peripherals), NULL);
> }
Otherwise looks OK.
thanks
-- PMM
- [PATCH v4 00/45] Raspberry Pi 4B machine, Sergey Kambalin, 2023/12/07
- [PATCH v4 01/45] Split out common part of BCM283X classes, Sergey Kambalin, 2023/12/07
- [PATCH v4 02/45] Split out common part of peripherals, Sergey Kambalin, 2023/12/07
- [PATCH v4 03/45] Split out raspi machine common part, Sergey Kambalin, 2023/12/07
- [PATCH v4 04/45] Introduce BCM2838 SoC, Sergey Kambalin, 2023/12/07
- [PATCH v4 05/45] Add GIC-400 to BCM2838 SoC, Sergey Kambalin, 2023/12/07
- Re: [PATCH v4 05/45] Add GIC-400 to BCM2838 SoC,
Peter Maydell <=
- [PATCH v4 06/45] Add BCM2838 GPIO stub, Sergey Kambalin, 2023/12/07
- [PATCH v4 08/45] Connect SD controller to BCM2838 GPIO, Sergey Kambalin, 2023/12/07
- [PATCH v4 09/45] Add GPIO and SD to BCM2838 periph, Sergey Kambalin, 2023/12/07
- [PATCH v4 10/45] Add BCM2838 checkpoint support, Sergey Kambalin, 2023/12/07
- [PATCH v4 07/45] Implement BCM2838 GPIO functionality, Sergey Kambalin, 2023/12/07