From: Chao-ying Fu <[email protected]> This patch adds a `.probe` implementation to the Xilinx PCIe driver to initializ bridge registers and determine the ECAM region size at runtime.
Additionally, writing the PCI memory base and limit registers is skipped for the root bridge (bus 0, device 0). On platforms such as the MIPS Boston board, writing these fields results in incorrect values being reported (e.g. base = 0x0, limit = 0x1600), causing Linux to fail memory space assignment for the bridge. This workaround allows a MIPS Boston board to boot Linux & let Linux successfully probe the PCIe bus & all devices connected to it. Signed-off-by: Chao-ying Fu <[email protected]> Signed-off-by: Uros Stajic <[email protected]> --- drivers/pci/pcie_xilinx.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c index 63058e8e7c5..3b6a8ced848 100644 --- a/drivers/pci/pcie_xilinx.c +++ b/drivers/pci/pcie_xilinx.c @@ -132,6 +132,15 @@ static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value, enum pci_size_t size) { + if (bdf == PCI_BDF(bus->seq_, 0, 0)) { + switch (offset) { + case PCI_MEMORY_BASE: + case PCI_MEMORY_LIMIT: + /* Writing the memory base or limit causes problems */ + return 0; + } + } + return pci_generic_mmap_write_config(bus, pcie_xilinx_config_address, bdf, offset, value, size); } @@ -186,6 +195,31 @@ static int pci_xilinx_probe(struct udevice *dev) return 0; } +static int pcie_xilinx_probe(struct udevice *dev) +{ + struct xilinx_pcie *pcie = dev_get_priv(dev); + u32 bridge_info, ecam_sz, rpsc; + + /* Disable all interrupts */ + writel(0, pcie->cfg_base + XILINX_PCIE_REG_INT_MASK); + + /* Enable the bridge */ + rpsc = readl(pcie->cfg_base + XILINX_PCIE_REG_RPSC); + rpsc |= XILINX_PCIE_REG_RPSC_BEN; + writel(rpsc, pcie->cfg_base + XILINX_PCIE_REG_RPSC); + + /* Discover the size of the ECAM region */ + bridge_info = readl(pcie->cfg_base + XILINX_PCIE_REG_BRIDGE_INFO); + ecam_sz = bridge_info & XILINX_PCIE_REG_BRIDGE_INFO_ECAMSZ_MASK; + ecam_sz >>= XILINX_PCIE_REG_BRIDGE_INFO_ECAMSZ_SHIFT; + + /* Enable access to all possible subordinate buses */ + writel((0 << 0) | (1 << 8) | (GENMASK(ecam_sz - 1, 0) << 16), + pcie->cfg_base + PCI_PRIMARY_BUS); + + return 0; +} + static const struct dm_pci_ops pcie_xilinx_ops = { .read_config = pcie_xilinx_read_config, .write_config = pcie_xilinx_write_config, @@ -204,4 +238,5 @@ U_BOOT_DRIVER(pcie_xilinx) = { .of_to_plat = pcie_xilinx_of_to_plat, .probe = pci_xilinx_probe, .priv_auto = sizeof(struct xilinx_pcie), + .probe = pcie_xilinx_probe, }; -- 2.34.1

