staticbool mobiveil_pcie_valid_device(struct pci_bus *bus, unsignedint devfn)
{ /* Only one device down on each root port */ if (pci_is_root_bus(bus) && (devfn > 0)) returnfalse;
/* * Do not read more than one device on the bus directly * attached to RC
*/ if ((bus->primary == to_pci_host_bridge(bus->bridge)->busnr) && (PCI_SLOT(devfn) > 0)) returnfalse;
returntrue;
}
/* * mobiveil_pcie_map_bus - routine to get the configuration base of either * root port or endpoint
*/ staticvoid __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus, unsignedint devfn, int where)
{ struct mobiveil_pcie *pcie = bus->sysdata; struct mobiveil_root_port *rp = &pcie->rp;
u32 value;
if (!mobiveil_pcie_valid_device(bus, devfn)) return NULL;
/* * EP config access (in Config/APIO space) * Program PEX Address base (31..16 bits) with appropriate value * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register. * Relies on pci_lock serialization
*/
value = bus->number << PAB_BUS_SHIFT |
PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
/* * MSI_STATUS_OFFSET register gets updated to zero * once we pop not only the MSI data but also address * from MSI hardware FIFO. So keeping these following * two dummy reads.
*/
msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
MSI_ADDR_L_OFFSET);
msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
MSI_ADDR_H_OFFSET);
dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
msi_data, msi_addr_hi, msi_addr_lo);
if (!reinit) { /* setup bus numbers */
value = mobiveil_csr_readl(pcie, PCI_PRIMARY_BUS);
value &= 0xff000000;
value |= 0x00ff0100;
mobiveil_csr_writel(pcie, value, PCI_PRIMARY_BUS);
}
/* * program Bus Master Enable Bit in Command Register in PAB Config * Space
*/
value = mobiveil_csr_readl(pcie, PCI_COMMAND);
value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
mobiveil_csr_writel(pcie, value, PCI_COMMAND);
/* * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL * register
*/
pab_ctrl = mobiveil_csr_readl(pcie, PAB_CTRL);
pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
mobiveil_csr_writel(pcie, pab_ctrl, PAB_CTRL);
/* * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in * PAB_AXI_PIO_CTRL Register
*/
value = mobiveil_csr_readl(pcie, PAB_AXI_PIO_CTRL);
value |= APIO_EN_MASK;
mobiveil_csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
/* Enable PCIe PIO master */
value = mobiveil_csr_readl(pcie, PAB_PEX_PIO_CTRL);
value |= 1 << PIO_ENABLE_SHIFT;
mobiveil_csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
/* * we'll program one outbound window for config reads and * another default inbound window for all the upstream traffic * rest of the outbound windows will be configured according to * the "ranges" field defined in device tree
*/
/* Get the I/O and memory ranges from DT */
resource_list_for_each_entry(win, &bridge->windows) { if (resource_type(win->res) == IORESOURCE_MEM)
type = MEM_WINDOW_TYPE; elseif (resource_type(win->res) == IORESOURCE_IO)
type = IO_WINDOW_TYPE; else continue;
/* fixup for PCIe class register */
value = mobiveil_csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
value &= 0xff;
value |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
ret = mobiveil_pcie_parse_dt(pcie); if (ret) {
dev_err(dev, "Parsing DT failed, ret: %x\n", ret); return ret;
}
if (!mobiveil_pcie_is_bridge(pcie)) return -ENODEV;
/* * configure all inbound and outbound windows and prepare the RC for * config access
*/
ret = mobiveil_host_init(pcie, false); if (ret) {
dev_err(dev, "Failed to initialize host\n"); return ret;
}
ret = mobiveil_pcie_interrupt_init(pcie); if (ret) {
dev_err(dev, "Interrupt init failed\n"); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.