1dcf1d8cdSSergey Kambalin /* 2dcf1d8cdSSergey Kambalin * BCM2838 SoC emulation 3dcf1d8cdSSergey Kambalin * 4dcf1d8cdSSergey Kambalin * Copyright (C) 2022 Ovchinnikov Vitalii <vitalii.ovchinnikov@auriga.com> 5dcf1d8cdSSergey Kambalin * 6dcf1d8cdSSergey Kambalin * SPDX-License-Identifier: GPL-2.0-or-later 7dcf1d8cdSSergey Kambalin */ 8dcf1d8cdSSergey Kambalin 9dcf1d8cdSSergey Kambalin #include "qemu/osdep.h" 10dcf1d8cdSSergey Kambalin #include "qapi/error.h" 11dcf1d8cdSSergey Kambalin #include "qemu/module.h" 12dcf1d8cdSSergey Kambalin #include "hw/arm/raspi_platform.h" 13dcf1d8cdSSergey Kambalin #include "hw/sysbus.h" 14dcf1d8cdSSergey Kambalin #include "hw/arm/bcm2838.h" 15dcf1d8cdSSergey Kambalin #include "trace.h" 16dcf1d8cdSSergey Kambalin 17*96b22ee5SSergey Kambalin #define GIC400_MAINTENANCE_IRQ 9 18*96b22ee5SSergey Kambalin #define GIC400_TIMER_NS_EL2_IRQ 10 19*96b22ee5SSergey Kambalin #define GIC400_TIMER_VIRT_IRQ 11 20*96b22ee5SSergey Kambalin #define GIC400_LEGACY_FIQ 12 21*96b22ee5SSergey Kambalin #define GIC400_TIMER_S_EL1_IRQ 13 22*96b22ee5SSergey Kambalin #define GIC400_TIMER_NS_EL1_IRQ 14 23*96b22ee5SSergey Kambalin #define GIC400_LEGACY_IRQ 15 24*96b22ee5SSergey Kambalin 25*96b22ee5SSergey Kambalin /* Number of external interrupt lines to configure the GIC with */ 26*96b22ee5SSergey Kambalin #define GIC_NUM_IRQS 192 27*96b22ee5SSergey Kambalin 28*96b22ee5SSergey Kambalin #define PPI(cpu, irq) (GIC_NUM_IRQS + (cpu) * GIC_INTERNAL + GIC_NR_SGIS + irq) 29*96b22ee5SSergey Kambalin 30*96b22ee5SSergey Kambalin #define GIC_BASE_OFS 0x0000 31*96b22ee5SSergey Kambalin #define GIC_DIST_OFS 0x1000 32*96b22ee5SSergey Kambalin #define GIC_CPU_OFS 0x2000 33*96b22ee5SSergey Kambalin #define GIC_VIFACE_THIS_OFS 0x4000 34*96b22ee5SSergey Kambalin #define GIC_VIFACE_OTHER_OFS(cpu) (0x5000 + (cpu) * 0x200) 35*96b22ee5SSergey Kambalin #define GIC_VCPU_OFS 0x6000 36*96b22ee5SSergey Kambalin 37dcf1d8cdSSergey Kambalin #define VIRTUAL_PMU_IRQ 7 38dcf1d8cdSSergey Kambalin 39*96b22ee5SSergey Kambalin static void bcm2838_gic_set_irq(void *opaque, int irq, int level) 40*96b22ee5SSergey Kambalin { 41*96b22ee5SSergey Kambalin BCM2838State *s = (BCM2838State *)opaque; 42*96b22ee5SSergey Kambalin 43*96b22ee5SSergey Kambalin trace_bcm2838_gic_set_irq(irq, level); 44*96b22ee5SSergey Kambalin qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level); 45*96b22ee5SSergey Kambalin } 46*96b22ee5SSergey Kambalin 47dcf1d8cdSSergey Kambalin static void bcm2838_init(Object *obj) 48dcf1d8cdSSergey Kambalin { 49dcf1d8cdSSergey Kambalin BCM2838State *s = BCM2838(obj); 50dcf1d8cdSSergey Kambalin 51dcf1d8cdSSergey Kambalin object_initialize_child(obj, "peripherals", &s->peripherals, 52dcf1d8cdSSergey Kambalin TYPE_BCM2838_PERIPHERALS); 53dcf1d8cdSSergey Kambalin object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), 54dcf1d8cdSSergey Kambalin "board-rev"); 55dcf1d8cdSSergey Kambalin object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), 56dcf1d8cdSSergey Kambalin "vcram-size"); 57dcf1d8cdSSergey Kambalin object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals), 58dcf1d8cdSSergey Kambalin "command-line"); 59*96b22ee5SSergey Kambalin 60*96b22ee5SSergey Kambalin object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); 61dcf1d8cdSSergey Kambalin } 62dcf1d8cdSSergey Kambalin 63dcf1d8cdSSergey Kambalin static void bcm2838_realize(DeviceState *dev, Error **errp) 64dcf1d8cdSSergey Kambalin { 65dcf1d8cdSSergey Kambalin BCM2838State *s = BCM2838(dev); 66dcf1d8cdSSergey Kambalin BCM283XBaseState *s_base = BCM283X_BASE(dev); 67dcf1d8cdSSergey Kambalin BCM283XBaseClass *bc_base = BCM283X_BASE_GET_CLASS(dev); 68dcf1d8cdSSergey Kambalin BCM2838PeripheralState *ps = BCM2838_PERIPHERALS(&s->peripherals); 69dcf1d8cdSSergey Kambalin BCMSocPeripheralBaseState *ps_base = 70dcf1d8cdSSergey Kambalin BCM_SOC_PERIPHERALS_BASE(&s->peripherals); 71dcf1d8cdSSergey Kambalin 72*96b22ee5SSergey Kambalin DeviceState *gicdev = NULL; 73*96b22ee5SSergey Kambalin 74dcf1d8cdSSergey Kambalin if (!bcm283x_common_realize(dev, ps_base, errp)) { 75dcf1d8cdSSergey Kambalin return; 76dcf1d8cdSSergey Kambalin } 77dcf1d8cdSSergey Kambalin sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 1, BCM2838_PERI_LOW_BASE, 1); 78dcf1d8cdSSergey Kambalin 79dcf1d8cdSSergey Kambalin /* bcm2836 interrupt controller (and mailboxes, etc.) */ 80dcf1d8cdSSergey Kambalin if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) { 81dcf1d8cdSSergey Kambalin return; 82dcf1d8cdSSergey Kambalin } 83dcf1d8cdSSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc_base->ctrl_base); 84dcf1d8cdSSergey Kambalin 85dcf1d8cdSSergey Kambalin /* Create cores */ 86*96b22ee5SSergey Kambalin for (int n = 0; n < bc_base->core_count; n++) { 87dcf1d8cdSSergey Kambalin 88dcf1d8cdSSergey Kambalin object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity", 89dcf1d8cdSSergey Kambalin (bc_base->clusterid << 8) | n, &error_abort); 90dcf1d8cdSSergey Kambalin 91*96b22ee5SSergey Kambalin /* set periphbase/CBAR value for CPU-local registers */ 92*96b22ee5SSergey Kambalin object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar", 93*96b22ee5SSergey Kambalin bc_base->peri_base, &error_abort); 94*96b22ee5SSergey Kambalin 95dcf1d8cdSSergey Kambalin /* start powered off if not enabled */ 96dcf1d8cdSSergey Kambalin object_property_set_bool(OBJECT(&s_base->cpu[n].core), 97dcf1d8cdSSergey Kambalin "start-powered-off", 98dcf1d8cdSSergey Kambalin n >= s_base->enabled_cpus, &error_abort); 99dcf1d8cdSSergey Kambalin 100dcf1d8cdSSergey Kambalin if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) { 101dcf1d8cdSSergey Kambalin return; 102dcf1d8cdSSergey Kambalin } 103dcf1d8cdSSergey Kambalin } 104*96b22ee5SSergey Kambalin 105*96b22ee5SSergey Kambalin if (!object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp)) { 106*96b22ee5SSergey Kambalin return; 107*96b22ee5SSergey Kambalin } 108*96b22ee5SSergey Kambalin 109*96b22ee5SSergey Kambalin if (!object_property_set_uint(OBJECT(&s->gic), "num-cpu", BCM283X_NCPUS, 110*96b22ee5SSergey Kambalin errp)) { 111*96b22ee5SSergey Kambalin return; 112*96b22ee5SSergey Kambalin } 113*96b22ee5SSergey Kambalin 114*96b22ee5SSergey Kambalin if (!object_property_set_uint(OBJECT(&s->gic), "num-irq", 115*96b22ee5SSergey Kambalin GIC_NUM_IRQS + GIC_INTERNAL, errp)) { 116*96b22ee5SSergey Kambalin return; 117*96b22ee5SSergey Kambalin } 118*96b22ee5SSergey Kambalin 119*96b22ee5SSergey Kambalin if (!object_property_set_bool(OBJECT(&s->gic), 120*96b22ee5SSergey Kambalin "has-virtualization-extensions", true, 121*96b22ee5SSergey Kambalin errp)) { 122*96b22ee5SSergey Kambalin return; 123*96b22ee5SSergey Kambalin } 124*96b22ee5SSergey Kambalin 125*96b22ee5SSergey Kambalin if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { 126*96b22ee5SSergey Kambalin return; 127*96b22ee5SSergey Kambalin } 128*96b22ee5SSergey Kambalin 129*96b22ee5SSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, 130*96b22ee5SSergey Kambalin bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_DIST_OFS); 131*96b22ee5SSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, 132*96b22ee5SSergey Kambalin bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_CPU_OFS); 133*96b22ee5SSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2, 134*96b22ee5SSergey Kambalin bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VIFACE_THIS_OFS); 135*96b22ee5SSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3, 136*96b22ee5SSergey Kambalin bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VCPU_OFS); 137*96b22ee5SSergey Kambalin 138*96b22ee5SSergey Kambalin for (int n = 0; n < BCM283X_NCPUS; n++) { 139*96b22ee5SSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n, 140*96b22ee5SSergey Kambalin bc_base->ctrl_base + BCM2838_GIC_BASE 141*96b22ee5SSergey Kambalin + GIC_VIFACE_OTHER_OFS(n)); 142*96b22ee5SSergey Kambalin } 143*96b22ee5SSergey Kambalin 144*96b22ee5SSergey Kambalin gicdev = DEVICE(&s->gic); 145*96b22ee5SSergey Kambalin 146*96b22ee5SSergey Kambalin for (int n = 0; n < BCM283X_NCPUS; n++) { 147*96b22ee5SSergey Kambalin DeviceState *cpudev = DEVICE(&s_base->cpu[n]); 148*96b22ee5SSergey Kambalin 149*96b22ee5SSergey Kambalin /* Connect the GICv2 outputs to the CPU */ 150*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n, 151*96b22ee5SSergey Kambalin qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); 152*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + BCM283X_NCPUS, 153*96b22ee5SSergey Kambalin qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); 154*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 2 * BCM283X_NCPUS, 155*96b22ee5SSergey Kambalin qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); 156*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 3 * BCM283X_NCPUS, 157*96b22ee5SSergey Kambalin qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); 158*96b22ee5SSergey Kambalin 159*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 4 * BCM283X_NCPUS, 160*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, 161*96b22ee5SSergey Kambalin PPI(n, GIC400_MAINTENANCE_IRQ))); 162*96b22ee5SSergey Kambalin 163*96b22ee5SSergey Kambalin /* Connect timers from the CPU to the interrupt controller */ 164*96b22ee5SSergey Kambalin qdev_connect_gpio_out(cpudev, GTIMER_PHYS, 165*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_NS_EL1_IRQ))); 166*96b22ee5SSergey Kambalin qdev_connect_gpio_out(cpudev, GTIMER_VIRT, 167*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_VIRT_IRQ))); 168*96b22ee5SSergey Kambalin qdev_connect_gpio_out(cpudev, GTIMER_HYP, 169*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_NS_EL2_IRQ))); 170*96b22ee5SSergey Kambalin qdev_connect_gpio_out(cpudev, GTIMER_SEC, 171*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_S_EL1_IRQ))); 172*96b22ee5SSergey Kambalin /* PMU interrupt */ 173*96b22ee5SSergey Kambalin qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, 174*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, PPI(n, VIRTUAL_PMU_IRQ))); 175*96b22ee5SSergey Kambalin } 176*96b22ee5SSergey Kambalin 177*96b22ee5SSergey Kambalin /* Connect UART0 to the interrupt controller */ 178*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->uart0), 0, 179*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_UART0)); 180*96b22ee5SSergey Kambalin 181*96b22ee5SSergey Kambalin /* Connect AUX / UART1 to the interrupt controller */ 182*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->aux), 0, 183*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_AUX_UART1)); 184*96b22ee5SSergey Kambalin 185*96b22ee5SSergey Kambalin /* Connect VC mailbox to the interrupt controller */ 186*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mboxes), 0, 187*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MBOX)); 188*96b22ee5SSergey Kambalin 189*96b22ee5SSergey Kambalin /* Connect SD host to the interrupt controller */ 190*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->sdhost), 0, 191*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_SDHOST)); 192*96b22ee5SSergey Kambalin 193*96b22ee5SSergey Kambalin /* According to DTS, EMMC and EMMC2 share one irq */ 194*96b22ee5SSergey Kambalin DeviceState *mmc_irq_orgate = DEVICE(&ps->mmc_irq_orgate); 195*96b22ee5SSergey Kambalin 196*96b22ee5SSergey Kambalin /* Connect EMMC and EMMC2 to the interrupt controller */ 197*96b22ee5SSergey Kambalin qdev_connect_gpio_out(mmc_irq_orgate, 0, 198*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_EMMC_EMMC2)); 199*96b22ee5SSergey Kambalin 200*96b22ee5SSergey Kambalin /* Connect USB OTG and MPHI to the interrupt controller */ 201*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mphi), 0, 202*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MPHI)); 203*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dwc2), 0, 204*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DWC2)); 205*96b22ee5SSergey Kambalin 206*96b22ee5SSergey Kambalin /* Connect DMA 0-6 to the interrupt controller */ 207*96b22ee5SSergey Kambalin for (int n = GIC_SPI_INTERRUPT_DMA_0; n <= GIC_SPI_INTERRUPT_DMA_6; n++) { 208*96b22ee5SSergey Kambalin sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dma), 209*96b22ee5SSergey Kambalin n - GIC_SPI_INTERRUPT_DMA_0, 210*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, n)); 211*96b22ee5SSergey Kambalin } 212*96b22ee5SSergey Kambalin 213*96b22ee5SSergey Kambalin /* According to DTS, DMA 7 and 8 share one irq */ 214*96b22ee5SSergey Kambalin DeviceState *dma_7_8_irq_orgate = DEVICE(&ps->dma_7_8_irq_orgate); 215*96b22ee5SSergey Kambalin 216*96b22ee5SSergey Kambalin /* Connect DMA 7-8 to the interrupt controller */ 217*96b22ee5SSergey Kambalin qdev_connect_gpio_out(dma_7_8_irq_orgate, 0, 218*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DMA_7_8)); 219*96b22ee5SSergey Kambalin 220*96b22ee5SSergey Kambalin /* According to DTS, DMA 9 and 10 share one irq */ 221*96b22ee5SSergey Kambalin DeviceState *dma_9_10_irq_orgate = DEVICE(&ps->dma_9_10_irq_orgate); 222*96b22ee5SSergey Kambalin 223*96b22ee5SSergey Kambalin /* Connect DMA 9-10 to the interrupt controller */ 224*96b22ee5SSergey Kambalin qdev_connect_gpio_out(dma_9_10_irq_orgate, 0, 225*96b22ee5SSergey Kambalin qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DMA_9_10)); 226*96b22ee5SSergey Kambalin 227*96b22ee5SSergey Kambalin /* Pass through inbound GPIO lines to the GIC */ 228*96b22ee5SSergey Kambalin qdev_init_gpio_in(dev, bcm2838_gic_set_irq, GIC_NUM_IRQS); 229*96b22ee5SSergey Kambalin 230*96b22ee5SSergey Kambalin /* Pass through outbound IRQ lines from the GIC */ 231*96b22ee5SSergey Kambalin qdev_pass_gpios(DEVICE(&s->gic), DEVICE(&s->peripherals), NULL); 232dcf1d8cdSSergey Kambalin } 233dcf1d8cdSSergey Kambalin 234dcf1d8cdSSergey Kambalin static void bcm2838_class_init(ObjectClass *oc, void *data) 235dcf1d8cdSSergey Kambalin { 236dcf1d8cdSSergey Kambalin DeviceClass *dc = DEVICE_CLASS(oc); 237dcf1d8cdSSergey Kambalin BCM283XBaseClass *bc_base = BCM283X_BASE_CLASS(oc); 238dcf1d8cdSSergey Kambalin 239dcf1d8cdSSergey Kambalin bc_base->cpu_type = ARM_CPU_TYPE_NAME("cortex-a72"); 240dcf1d8cdSSergey Kambalin bc_base->core_count = BCM283X_NCPUS; 241dcf1d8cdSSergey Kambalin bc_base->peri_base = 0xfe000000; 242dcf1d8cdSSergey Kambalin bc_base->ctrl_base = 0xff800000; 243dcf1d8cdSSergey Kambalin bc_base->clusterid = 0x0; 244dcf1d8cdSSergey Kambalin dc->realize = bcm2838_realize; 245dcf1d8cdSSergey Kambalin } 246dcf1d8cdSSergey Kambalin 247dcf1d8cdSSergey Kambalin static const TypeInfo bcm2838_type = { 248dcf1d8cdSSergey Kambalin .name = TYPE_BCM2838, 249dcf1d8cdSSergey Kambalin .parent = TYPE_BCM283X_BASE, 250dcf1d8cdSSergey Kambalin .instance_size = sizeof(BCM2838State), 251dcf1d8cdSSergey Kambalin .instance_init = bcm2838_init, 252dcf1d8cdSSergey Kambalin .class_size = sizeof(BCM283XBaseClass), 253dcf1d8cdSSergey Kambalin .class_init = bcm2838_class_init, 254dcf1d8cdSSergey Kambalin }; 255dcf1d8cdSSergey Kambalin 256dcf1d8cdSSergey Kambalin static void bcm2838_register_types(void) 257dcf1d8cdSSergey Kambalin { 258dcf1d8cdSSergey Kambalin type_register_static(&bcm2838_type); 259dcf1d8cdSSergey Kambalin } 260dcf1d8cdSSergey Kambalin 261dcf1d8cdSSergey Kambalin type_init(bcm2838_register_types); 262