From 11be65472a427dcf7a11ab6e3e3628f1c6768b5b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 26 Jul 2013 10:17:48 -0300 Subject: [PATCH] PCI: mvebu: Adapt to the new device tree layout The new device tree layout encodes the window's target ID and attribute in the PCIe controller node's ranges property. This allows to parse such entries to obtain such information and use the recently introduced MBus API to create the windows, instead of using the current name based scheme. Acked-by: Bjorn Helgaas Signed-off-by: Thomas Petazzoni Tested-by: Andrew Lunn Tested-by: Sebastian Hesselbarth Signed-off-by: Jason Cooper --- drivers/pci/host/pci-mvebu.c | 113 ++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 29 deletions(-) diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 13a633b1612e..424a7b8e040f 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -123,6 +123,10 @@ struct mvebu_pcie_port { u32 port; u32 lane; int devfn; + unsigned int mem_target; + unsigned int mem_attr; + unsigned int io_target; + unsigned int io_attr; struct clk *clk; struct mvebu_sw_pci_bridge bridge; struct device_node *dn; @@ -307,10 +311,9 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) (port->bridge.iolimitupper << 16)) - iobase); - mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base, - port->iowin_size, - iobase, - MVEBU_MBUS_PCI_IO); + mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, + port->iowin_base, port->iowin_size, + iobase); pci_ioremap_io(iobase, port->iowin_base); } @@ -342,10 +345,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - port->memwin_base; - mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base, - port->memwin_size, - MVEBU_MBUS_NO_REMAP, - MVEBU_MBUS_PCI_MEM); + mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, + port->memwin_base, port->memwin_size); } /* @@ -755,12 +756,54 @@ mvebu_pcie_map_registers(struct platform_device *pdev, return devm_request_and_ioremap(&pdev->dev, ®s); } +#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) +#define DT_TYPE_IO 0x1 +#define DT_TYPE_MEM32 0x2 +#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF) +#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) + +static int mvebu_get_tgt_attr(struct device_node *np, int devfn, + unsigned long type, int *tgt, int *attr) +{ + const int na = 3, ns = 2; + const __be32 *range; + int rlen, nranges, rangesz, pna, i; + + range = of_get_property(np, "ranges", &rlen); + if (!range) + return -EINVAL; + + pna = of_n_addr_cells(np); + rangesz = pna + na + ns; + nranges = rlen / sizeof(__be32) / rangesz; + + for (i = 0; i < nranges; i++) { + u32 flags = of_read_number(range, 1); + u32 slot = of_read_number(range, 2); + u64 cpuaddr = of_read_number(range + na, pna); + unsigned long rtype; + + if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO) + rtype = IORESOURCE_IO; + else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32) + rtype = IORESOURCE_MEM; + + if (slot == PCI_SLOT(devfn) && type == rtype) { + *tgt = DT_CPUADDR_TO_TARGET(cpuaddr); + *attr = DT_CPUADDR_TO_ATTR(cpuaddr); + return 0; + } + + range += rangesz; + } + + return -ENOENT; +} + static int __init mvebu_pcie_probe(struct platform_device *pdev) { struct mvebu_pcie *pcie; struct device_node *np = pdev->dev.of_node; - struct of_pci_range range; - struct of_pci_range_parser parser; struct device_node *child; int i, ret; @@ -771,29 +814,25 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev) pcie->pdev = pdev; - if (of_pci_range_parser_init(&parser, np)) + /* Get the PCIe memory and I/O aperture */ + mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); + if (resource_size(&pcie->mem) == 0) { + dev_err(&pdev->dev, "invalid memory aperture size\n"); return -EINVAL; + } - /* Get the I/O and memory ranges from DT */ - for_each_of_pci_range(&parser, &range) { - unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; - if (restype == IORESOURCE_IO) { - of_pci_range_to_resource(&range, np, &pcie->io); - of_pci_range_to_resource(&range, np, &pcie->realio); - pcie->io.name = "I/O"; - pcie->realio.start = max_t(resource_size_t, - PCIBIOS_MIN_IO, - range.pci_addr); - pcie->realio.end = min_t(resource_size_t, - IO_SPACE_LIMIT, - range.pci_addr + range.size); - } - if (restype == IORESOURCE_MEM) { - of_pci_range_to_resource(&range, np, &pcie->mem); - pcie->mem.name = "MEM"; - } + mvebu_mbus_get_pcie_io_aperture(&pcie->io); + if (resource_size(&pcie->io) == 0) { + dev_err(&pdev->dev, "invalid I/O aperture size\n"); + return -EINVAL; } + pcie->realio.flags = pcie->io.flags; + pcie->realio.start = PCIBIOS_MIN_IO; + pcie->realio.end = min_t(resource_size_t, + IO_SPACE_LIMIT, + resource_size(&pcie->io)); + /* Get the bus range */ ret = of_pci_parse_bus_range(np, &pcie->busn); if (ret) { @@ -841,6 +880,22 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev) if (port->devfn < 0) continue; + ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_MEM, + &port->mem_target, &port->mem_attr); + if (ret < 0) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for mem window\n", + port->port, port->lane); + continue; + } + + ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, + &port->io_target, &port->io_attr); + if (ret < 0) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", + port->port, port->lane); + continue; + } + port->base = mvebu_pcie_map_registers(pdev, child, port); if (!port->base) { dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n", -- 2.20.1