From: Marcelo Manzo <[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]> Reviewed-by: Peter Maydell <[email protected]> Message-id: [email protected] Signed-off-by: Peter Maydell <[email protected]> --- include/hw/arm/bcm2838_peripherals.h | 3 +++ hw/arm/bcm2838.c | 7 ++++++ hw/arm/bcm2838_peripherals.c | 35 ++++++++++++++++++++++++++++ hw/arm/raspi4b.c | 1 - 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/hw/arm/bcm2838_peripherals.h b/include/hw/arm/bcm2838_peripherals.h index a720eea8216..0afc2c7bd2e 100644 --- a/include/hw/arm/bcm2838_peripherals.h +++ b/include/hw/arm/bcm2838_peripherals.h @@ -12,6 +12,7 @@ #include "hw/arm/bcm2835_peripherals.h" #include "hw/misc/bcm2838_rng200.h" #include "hw/misc/bcm2838_thermal.h" +#include "hw/arm/bcm2838_pcie.h" #include "hw/sd/sdhci.h" #include "hw/gpio/bcm2838_gpio.h" @@ -69,6 +70,8 @@ struct BCM2838PeripheralState { BCM2838Rng200State rng200; Bcm2838ThermalState thermal; SDHCIState emmc2; + MemoryRegion pcie_mmio_alias; + BCM2838PcieHostState pcie_host; BCM2838GpioState gpio; OrIRQState mmc_irq_orgate; diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c index 218bebc0e85..cb52f0bd1a9 100644 --- a/hw/arm/bcm2838.c +++ b/hw/arm/bcm2838.c @@ -234,6 +234,13 @@ 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)); + } + /* 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 f4e9cb88f1f..e7d2e3155aa 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 @@ -41,6 +46,10 @@ static void bcm2838_peripherals_init(Object *obj) /* Thermal */ object_initialize_child(obj, "thermal", &s->thermal, TYPE_BCM2838_THERMAL); + /* 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); @@ -76,6 +85,8 @@ static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp) MemoryRegion *rng200_mr; qemu_irq rng_200_irq; MemoryRegion *thermal_mr; + MemoryRegion *regs_mr; + MemoryRegion *mmio_mr; int n; bcm_soc_peripherals_common_realize(dev, errp); @@ -210,6 +221,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 61adccded97..3613b8b0db1 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -63,7 +63,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-genet-v5", }; -- 2.43.0
