[PATCH v2 03/19] hw/arm/bcm2838: enable BCM2838 PCIe host bridge
Marcelo Manzo <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Wire the BCM2838 PCIe host bridge into the SoC's peripheral block: instantiate it, map its RC registers and MMIO window. Per Peter Maydell's review of a later follow-up series, fold in the remaining defect from what was originally a separate bugfix here, since this device isn't in upstream git yet: the PCI MMIO window was mapped at the ARM base address with no address translation, even though PCIE_MMIO_OFFSET was defined for exactly that purpose (and otherwise unused). The DTB declares CPU 0x600000000 as mapping to PCI 0xc0000000, so a guest would read PCI address 0 where it expected a device BAR. Map an alias at the correct PCI offset instead. Signed-off-by: Marcelo Manzo <[email protected]> --- hw/arm/bcm2838.c | 9 +++++++ hw/arm/bcm2838_peripherals.c | 35 ++++++++++++++++++++++++++++ hw/arm/raspi4b.c | 1 - include/hw/arm/bcm2838_peripherals.h | 3 +++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c index 089af412a3..fc56f87934 100644 --- a/hw/arm/bcm2838.c +++ b/hw/arm/bcm2838.c @@ -230,6 +230,15 @@ static void bcm2838_realize(DeviceState *dev, Error **errp) qdev_connect_gpio_out(dma_9_10_irq_orgate, 0, qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DMA_9_10)); + /* Connect PCIe host bridge to the interrupt controller */ + for (int n = 0; n < BCM2838_PCIE_NUM_IRQS; n++) { + int int_n = GIC_SPI_INTERRUPT_PCI_INT_A + n; + sysbus_connect_irq(SYS_BUS_DEVICE(&ps->pcie_host), n, + qdev_get_gpio_in(gicdev, int_n)); + bcm2838_pcie_host_set_irq_num(BCM2838_PCIE_HOST(&ps->pcie_host), n, + int_n); + } + /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(dev, bcm2838_gic_set_irq, GIC_NUM_IRQS); diff --git a/hw/arm/bcm2838_peripherals.c b/hw/arm/bcm2838_peripherals.c index 812b5b8480..d923ba968a 100644 --- a/hw/arm/bcm2838_peripherals.c +++ b/hw/arm/bcm2838_peripherals.c @@ -15,6 +15,11 @@ #define CLOCK_ISP_OFFSET 0xc11000 #define CLOCK_ISP_SIZE 0x100 +#define PCIE_RC_OFFSET 0x1500000 +#define PCIE_MMIO_OFFSET 0xc0000000 +#define PCIE_MMIO_ARM_OFFSET 0x600000000 +#define PCIE_MMIO_SIZE 0x40000000 + /* Lower peripheral base address on the VC (GPU) system bus */ #define BCM2838_VC_PERI_LOW_BASE 0x7c000000 @@ -35,6 +40,10 @@ static void bcm2838_peripherals_init(Object *obj) /* Extended Mass Media Controller 2 */ object_initialize_child(obj, "emmc2", &s->emmc2, TYPE_SYSBUS_SDHCI); + /* PCIe Host Bridge */ + object_initialize_child(obj, "pcie-host", &s->pcie_host, + TYPE_BCM2838_PCIE_HOST); + /* GPIO */ object_initialize_child(obj, "gpio", &s->gpio, TYPE_BCM2838_GPIO); @@ -67,6 +76,8 @@ static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp) MemoryRegion *mphi_mr; BCM2838PeripheralState *s = BCM2838_PERIPHERALS(dev); BCMSocPeripheralBaseState *s_base = BCM_SOC_PERIPHERALS_BASE(dev); + MemoryRegion *regs_mr; + MemoryRegion *mmio_mr; int n; bcm_soc_peripherals_common_realize(dev, errp); @@ -182,6 +193,30 @@ static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp) create_unimp(s_base, &s->clkisp, "bcm2835-clkisp", CLOCK_ISP_OFFSET, CLOCK_ISP_SIZE); + /* PCIe Root Complex */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_host), errp)) { + return; + } + /* RC registers region */ + regs_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pcie_host), 0); + memory_region_add_subregion(&s->peri_low_mr, PCIE_RC_OFFSET, regs_mr); + /* + * MMIO region. + * + * The BCM2711 PCIe controller translates addresses between the ARM and + * PCI address spaces: the DTB declares CPU 0x600000000 as mapping to PCI + * 0xc0000000. Map an alias of the PCI window starting at that PCI offset + * so accesses land on the right addresses; mapping the window directly + * would expose PCI address 0 at the ARM base instead, and every BAR + * behind the root port would be read at the wrong address. + */ + mmio_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pcie_host), 1); + memory_region_init_alias(&s->pcie_mmio_alias, OBJECT(s), + "bcm2838_pcie_mmio_alias", mmio_mr, + PCIE_MMIO_OFFSET, PCIE_MMIO_SIZE); + memory_region_add_subregion(get_system_memory(), PCIE_MMIO_ARM_OFFSET, + &s->pcie_mmio_alias); + /* GPIO */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c index 06aeb8db01..038eefb234 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -64,7 +64,6 @@ static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt) /* Temporarily disable following devices until they are implemented */ const char *nodes_to_remove[] = { - "brcm,bcm2711-pcie", "brcm,bcm2711-rng200", "brcm,bcm2711-thermal", "brcm,bcm2711-genet-v5", diff --git a/include/hw/arm/bcm2838_peripherals.h b/include/hw/arm/bcm2838_peripherals.h index 0be97e67c7..7fe92789e8 100644 --- a/include/hw/arm/bcm2838_peripherals.h +++ b/include/hw/arm/bcm2838_peripherals.h @@ -10,6 +10,7 @@ #define BCM2838_PERIPHERALS_H #include "hw/arm/bcm2835_peripherals.h" +#include "hw/arm/bcm2838_pcie.h" #include "hw/sd/sdhci.h" #include "hw/gpio/bcm2838_gpio.h" @@ -65,6 +66,8 @@ struct BCM2838PeripheralState { MemoryRegion mphi_mr_alias; SDHCIState emmc2; + MemoryRegion pcie_mmio_alias; + BCM2838PcieHostState pcie_host; BCM2838GpioState gpio; OrIRQState mmc_irq_orgate; -- 2.47.1