Merge branches 'pci/host-designware', 'pci/host-imx6', 'pci/host-mvebu' and 'pci/host-tegra' into next
* pci/host-designware: PCI: designware: Remove unnecessary use of 'conf_lock' spinlock PCI: designware: Use new OF interrupt mapping when possible PCI: designware: Fix iATU programming for cfg1, io and mem viewport PCI: designware: Fix comment for setting number of lanes * pci/host-imx6: PCI: designware: Split Exynos and i.MX bindings * pci/host-mvebu: PCI: mvebu: Use '%pa' for printing 'phys_addr_t' type PCI: mvebu: Remove unnecessary use of 'conf_lock' spinlock PCI: mvebu: split PCIe BARs into multiple MBus windows when needed bus: mvebu-mbus: allow several windows with the same target/attribute bus: mvebu-mbus: Avoid setting an undefined window size PCI: mvebu: fix off-by-one in the computed size of the mbus windows * pci/host-tegra: PCI: tegra: Use new OF interrupt mapping when possible
This commit is contained in:
Коммит
843a85ced9
|
@ -1,15 +1,7 @@
|
|||
* Synopsys Designware PCIe interface
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain "snps,dw-pcie" to identify the
|
||||
core, plus an identifier for the specific instance, such
|
||||
as "samsung,exynos5440-pcie" or "fsl,imx6q-pcie".
|
||||
- reg: base addresses and lengths of the pcie controller,
|
||||
the phy controller, additional register for the phy controller.
|
||||
- interrupts: interrupt values for level interrupt,
|
||||
pulse interrupt, special interrupt.
|
||||
- clocks: from common clock binding: handle to pci clock.
|
||||
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
|
||||
- compatible: should contain "snps,dw-pcie" to identify the core.
|
||||
- #address-cells: set to <3>
|
||||
- #size-cells: set to <2>
|
||||
- device_type: set to "pci"
|
||||
|
@ -19,65 +11,11 @@ Required properties:
|
|||
to define the mapping of the PCIe interface to interrupt
|
||||
numbers.
|
||||
- num-lanes: number of lanes to use
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: Must include the following entries:
|
||||
- "pcie"
|
||||
- "pcie_bus"
|
||||
|
||||
Optional properties:
|
||||
- reset-gpio: gpio pin number of power good signal
|
||||
|
||||
Optional properties for fsl,imx6q-pcie
|
||||
- power-on-gpio: gpio pin number of power-enable signal
|
||||
- wake-up-gpio: gpio pin number of incoming wakeup signal
|
||||
- disable-gpio: gpio pin number of outgoing rfkill/endpoint disable signal
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
reg = <0x290000 0x1000
|
||||
0x270000 0x1000
|
||||
0x271000 0x40>;
|
||||
interrupts = <0 20 0>, <0 21 0>, <0 22 0>;
|
||||
clocks = <&clock 28>, <&clock 27>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */
|
||||
0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */
|
||||
0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0x0 0 &gic 53>;
|
||||
num-lanes = <4>;
|
||||
};
|
||||
|
||||
pcie@2a0000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
reg = <0x2a0000 0x1000
|
||||
0x272000 0x1000
|
||||
0x271040 0x40>;
|
||||
interrupts = <0 23 0>, <0 24 0>, <0 25 0>;
|
||||
clocks = <&clock 29>, <&clock 27>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */
|
||||
0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */
|
||||
0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0x0 0 &gic 56>;
|
||||
num-lanes = <4>;
|
||||
};
|
||||
|
||||
Board specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
reset-gpio = <&pin_ctrl 5 0>;
|
||||
};
|
||||
|
||||
pcie@2a0000 {
|
||||
reset-gpio = <&pin_ctrl 22 0>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
* Freescale i.MX6 PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||
and thus inherits all the common properties defined in designware-pcie.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fsl,imx6q-pcie"
|
||||
- reg: base addresse and length of the pcie controller
|
||||
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||
entry for each entry in the interrupt-names property.
|
||||
- interrupt-names: Must include the following entries:
|
||||
- "msi": The interrupt that is asserted when an MSI is received
|
||||
- clock-names: Must include the following additional entries:
|
||||
- "pcie_phy"
|
||||
|
||||
Example:
|
||||
|
||||
pcie@0x01000000 {
|
||||
compatible = "fsl,imx6q-pcie", "snps,dw-pcie";
|
||||
reg = <0x01ffc000 0x4000>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000
|
||||
0x81000000 0 0 0x01f80000 0 0x00010000
|
||||
0x82000000 0 0x01000000 0x01000000 0 0x00f00000>;
|
||||
num-lanes = <1>;
|
||||
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks 144>, <&clks 206>, <&clks 189>;
|
||||
clock-names = "pcie", "pcie_bus", "pcie_phy";
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
* Samsung Exynos 5440 PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||
and thus inherits all the common properties defined in designware-pcie.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible: "samsung,exynos5440-pcie"
|
||||
- reg: base addresses and lengths of the pcie controller,
|
||||
the phy controller, additional register for the phy controller.
|
||||
- interrupts: A list of interrupt outputs for level interrupt,
|
||||
pulse interrupt, special interrupt.
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
reg = <0x290000 0x1000
|
||||
0x270000 0x1000
|
||||
0x271000 0x40>;
|
||||
interrupts = <0 20 0>, <0 21 0>, <0 22 0>;
|
||||
clocks = <&clock 28>, <&clock 27>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */
|
||||
0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */
|
||||
0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
|
||||
num-lanes = <4>;
|
||||
};
|
||||
|
||||
pcie@2a0000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
reg = <0x2a0000 0x1000
|
||||
0x272000 0x1000
|
||||
0x271040 0x40>;
|
||||
interrupts = <0 23 0>, <0 24 0>, <0 25 0>;
|
||||
clocks = <&clock 29>, <&clock 27>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */
|
||||
0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */
|
||||
0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
|
||||
num-lanes = <4>;
|
||||
};
|
||||
|
||||
Board specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
reset-gpio = <&pin_ctrl 5 0>;
|
||||
};
|
||||
|
||||
pcie@2a0000 {
|
||||
reset-gpio = <&pin_ctrl 22 0>;
|
||||
};
|
|
@ -56,6 +56,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
/*
|
||||
* DDR target is the same on all platforms.
|
||||
|
@ -222,12 +223,6 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
|
|||
*/
|
||||
if ((u64)base < wend && end > wbase)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check if target/attribute conflicts
|
||||
*/
|
||||
if (target == wtarget && attr == wattr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -266,6 +261,17 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
|
|||
mbus->soc->win_cfg_offset(win);
|
||||
u32 ctrl, remap_addr;
|
||||
|
||||
if (!is_power_of_2(size)) {
|
||||
WARN(true, "Invalid MBus window size: 0x%zx\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((base & (phys_addr_t)(size - 1)) != 0) {
|
||||
WARN(true, "Invalid MBus base/size: %pa len 0x%zx\n", &base,
|
||||
size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
|
||||
(attr << WIN_CTRL_ATTR_SHIFT) |
|
||||
(target << WIN_CTRL_TGT_SHIFT) |
|
||||
|
@ -413,6 +419,10 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
|
|||
win, (unsigned long long)wbase,
|
||||
(unsigned long long)(wbase + wsize), wtarget, wattr);
|
||||
|
||||
if (!is_power_of_2(wsize) ||
|
||||
((wbase & (u64)(wsize - 1)) != 0))
|
||||
seq_puts(seq, " (Invalid base/size!!)");
|
||||
|
||||
if (win < mbus->soc->num_remappable_wins) {
|
||||
seq_printf(seq, " (remap %016llx)\n",
|
||||
(unsigned long long)wremap);
|
||||
|
|
|
@ -545,7 +545,6 @@ static int __init add_pcie_port(struct pcie_port *pp,
|
|||
pp->root_bus_nr = -1;
|
||||
pp->ops = &exynos_pcie_host_ops;
|
||||
|
||||
spin_lock_init(&pp->conf_lock);
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize host\n");
|
||||
|
|
|
@ -507,7 +507,6 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
|
|||
pp->root_bus_nr = -1;
|
||||
pp->ops = &imx6_pcie_host_ops;
|
||||
|
||||
spin_lock_init(&pp->conf_lock);
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize host\n");
|
||||
|
|
|
@ -113,7 +113,6 @@ struct mvebu_pcie {
|
|||
struct mvebu_pcie_port {
|
||||
char *name;
|
||||
void __iomem *base;
|
||||
spinlock_t conf_lock;
|
||||
u32 port;
|
||||
u32 lane;
|
||||
int devfn;
|
||||
|
@ -293,6 +292,60 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
|
|||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove windows, starting from the largest ones to the smallest
|
||||
* ones.
|
||||
*/
|
||||
static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port,
|
||||
phys_addr_t base, size_t size)
|
||||
{
|
||||
while (size) {
|
||||
size_t sz = 1 << (fls(size) - 1);
|
||||
|
||||
mvebu_mbus_del_window(base, sz);
|
||||
base += sz;
|
||||
size -= sz;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MBus windows can only have a power of two size, but PCI BARs do not
|
||||
* have this constraint. Therefore, we have to split the PCI BAR into
|
||||
* areas each having a power of two size. We start from the largest
|
||||
* one (i.e highest order bit set in the size).
|
||||
*/
|
||||
static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
|
||||
unsigned int target, unsigned int attribute,
|
||||
phys_addr_t base, size_t size,
|
||||
phys_addr_t remap)
|
||||
{
|
||||
size_t size_mapped = 0;
|
||||
|
||||
while (size) {
|
||||
size_t sz = 1 << (fls(size) - 1);
|
||||
int ret;
|
||||
|
||||
ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base,
|
||||
sz, remap);
|
||||
if (ret) {
|
||||
phys_addr_t end = base + sz - 1;
|
||||
|
||||
dev_err(&port->pcie->pdev->dev,
|
||||
"Could not create MBus window at [mem %pa-%pa]: %d\n",
|
||||
&base, &end, ret);
|
||||
mvebu_pcie_del_windows(port, base - size_mapped,
|
||||
size_mapped);
|
||||
return;
|
||||
}
|
||||
|
||||
size -= sz;
|
||||
size_mapped += sz;
|
||||
base += sz;
|
||||
if (remap != MVEBU_MBUS_NO_REMAP)
|
||||
remap += sz;
|
||||
}
|
||||
}
|
||||
|
||||
static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
|
||||
{
|
||||
phys_addr_t iobase;
|
||||
|
@ -304,8 +357,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
|
|||
|
||||
/* If a window was configured, remove it */
|
||||
if (port->iowin_base) {
|
||||
mvebu_mbus_del_window(port->iowin_base,
|
||||
port->iowin_size);
|
||||
mvebu_pcie_del_windows(port, port->iowin_base,
|
||||
port->iowin_size);
|
||||
port->iowin_base = 0;
|
||||
port->iowin_size = 0;
|
||||
}
|
||||
|
@ -331,11 +384,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
|
|||
port->iowin_base = port->pcie->io.start + iobase;
|
||||
port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
|
||||
(port->bridge.iolimitupper << 16)) -
|
||||
iobase);
|
||||
iobase) + 1;
|
||||
|
||||
mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr,
|
||||
port->iowin_base, port->iowin_size,
|
||||
iobase);
|
||||
mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
|
||||
port->iowin_base, port->iowin_size,
|
||||
iobase);
|
||||
}
|
||||
|
||||
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
|
||||
|
@ -346,8 +399,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
|
|||
|
||||
/* If a window was configured, remove it */
|
||||
if (port->memwin_base) {
|
||||
mvebu_mbus_del_window(port->memwin_base,
|
||||
port->memwin_size);
|
||||
mvebu_pcie_del_windows(port, port->memwin_base,
|
||||
port->memwin_size);
|
||||
port->memwin_base = 0;
|
||||
port->memwin_size = 0;
|
||||
}
|
||||
|
@ -364,10 +417,11 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
|
|||
port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
|
||||
port->memwin_size =
|
||||
(((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
|
||||
port->memwin_base;
|
||||
port->memwin_base + 1;
|
||||
|
||||
mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr,
|
||||
port->memwin_base, port->memwin_size);
|
||||
mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
|
||||
port->memwin_base, port->memwin_size,
|
||||
MVEBU_MBUS_NO_REMAP);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -585,7 +639,6 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
{
|
||||
struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
|
||||
struct mvebu_pcie_port *port;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
port = mvebu_pcie_find_port(pcie, bus, devfn);
|
||||
|
@ -611,10 +664,8 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
/* Access the real PCIe interface */
|
||||
spin_lock_irqsave(&port->conf_lock, flags);
|
||||
ret = mvebu_pcie_hw_wr_conf(port, bus, devfn,
|
||||
where, size, val);
|
||||
spin_unlock_irqrestore(&port->conf_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -625,7 +676,6 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
{
|
||||
struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
|
||||
struct mvebu_pcie_port *port;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
port = mvebu_pcie_find_port(pcie, bus, devfn);
|
||||
|
@ -657,10 +707,8 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
}
|
||||
|
||||
/* Access the real PCIe interface */
|
||||
spin_lock_irqsave(&port->conf_lock, flags);
|
||||
ret = mvebu_pcie_hw_rd_conf(port, bus, devfn,
|
||||
where, size, val);
|
||||
spin_unlock_irqrestore(&port->conf_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -743,14 +791,21 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
|
|||
|
||||
/*
|
||||
* On the PCI-to-PCI bridge side, the I/O windows must have at
|
||||
* least a 64 KB size and be aligned on their size, and the
|
||||
* memory windows must have at least a 1 MB size and be
|
||||
* aligned on their size
|
||||
* least a 64 KB size and the memory windows must have at
|
||||
* least a 1 MB size. Moreover, MBus windows need to have a
|
||||
* base address aligned on their size, and their size must be
|
||||
* a power of two. This means that if the BAR doesn't have a
|
||||
* power of two size, several MBus windows will actually be
|
||||
* created. We need to ensure that the biggest MBus window
|
||||
* (which will be the first one) is aligned on its size, which
|
||||
* explains the rounddown_pow_of_two() being done here.
|
||||
*/
|
||||
if (res->flags & IORESOURCE_IO)
|
||||
return round_up(start, max_t(resource_size_t, SZ_64K, size));
|
||||
return round_up(start, max_t(resource_size_t, SZ_64K,
|
||||
rounddown_pow_of_two(size)));
|
||||
else if (res->flags & IORESOURCE_MEM)
|
||||
return round_up(start, max_t(resource_size_t, SZ_1M, size));
|
||||
return round_up(start, max_t(resource_size_t, SZ_1M,
|
||||
rounddown_pow_of_two(size)));
|
||||
else
|
||||
return start;
|
||||
}
|
||||
|
@ -1000,7 +1055,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
|
|||
mvebu_pcie_set_local_dev_nr(port, 1);
|
||||
|
||||
port->dn = child;
|
||||
spin_lock_init(&port->conf_lock);
|
||||
mvebu_sw_pci_bridge_init(port);
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -639,10 +639,15 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
|
|||
static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata);
|
||||
int irq;
|
||||
|
||||
tegra_cpuidle_pcie_irqs_in_use();
|
||||
|
||||
return pcie->irq;
|
||||
irq = of_irq_parse_and_map_pci(pdev, slot, pin);
|
||||
if (!irq)
|
||||
irq = pcie->irq;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void tegra_pcie_add_bus(struct pci_bus *bus)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -494,7 +495,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
|
|||
dw_pci.nr_controllers = 1;
|
||||
dw_pci.private_data = (void **)&pp;
|
||||
|
||||
pci_common_init(&dw_pci);
|
||||
pci_common_init_dev(pp->dev, &dw_pci);
|
||||
pci_assign_unassigned_resources();
|
||||
#ifdef CONFIG_PCI_DOMAINS
|
||||
dw_pci.domain++;
|
||||
|
@ -524,13 +525,13 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
|
|||
dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_VIEWPORT);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE);
|
||||
dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE);
|
||||
dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
|
||||
PCIE_ATU_LIMIT);
|
||||
dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
|
||||
dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
}
|
||||
|
||||
static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
|
||||
|
@ -539,7 +540,6 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
|
|||
dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_VIEWPORT);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
|
||||
dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
|
||||
dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
|
||||
|
@ -547,6 +547,7 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
|
|||
dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
|
||||
dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
|
||||
PCIE_ATU_UPPER_TARGET);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
}
|
||||
|
||||
static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
|
||||
|
@ -555,7 +556,6 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
|
|||
dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_VIEWPORT);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
|
||||
dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
|
||||
dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
|
||||
|
@ -563,6 +563,7 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
|
|||
dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
|
||||
dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
|
||||
PCIE_ATU_UPPER_TARGET);
|
||||
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
|
@ -642,7 +643,6 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
int size, u32 *val)
|
||||
{
|
||||
struct pcie_port *pp = sys_to_pcie(bus->sysdata);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!pp) {
|
||||
|
@ -655,13 +655,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pp->conf_lock, flags);
|
||||
if (bus->number != pp->root_bus_nr)
|
||||
ret = dw_pcie_rd_other_conf(pp, bus, devfn,
|
||||
where, size, val);
|
||||
else
|
||||
ret = dw_pcie_rd_own_conf(pp, where, size, val);
|
||||
spin_unlock_irqrestore(&pp->conf_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -670,7 +668,6 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
int where, int size, u32 val)
|
||||
{
|
||||
struct pcie_port *pp = sys_to_pcie(bus->sysdata);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!pp) {
|
||||
|
@ -681,13 +678,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
spin_lock_irqsave(&pp->conf_lock, flags);
|
||||
if (bus->number != pp->root_bus_nr)
|
||||
ret = dw_pcie_wr_other_conf(pp, bus, devfn,
|
||||
where, size, val);
|
||||
else
|
||||
ret = dw_pcie_wr_own_conf(pp, where, size, val);
|
||||
spin_unlock_irqrestore(&pp->conf_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -727,7 +722,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
|||
|
||||
if (pp) {
|
||||
pp->root_bus_nr = sys->busnr;
|
||||
bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops,
|
||||
bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops,
|
||||
sys, &sys->resources);
|
||||
} else {
|
||||
bus = NULL;
|
||||
|
@ -740,8 +735,13 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
|||
static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
|
||||
int irq;
|
||||
|
||||
return pp->irq;
|
||||
irq = of_irq_parse_and_map_pci(dev, slot, pin);
|
||||
if (!irq)
|
||||
irq = pp->irq;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void dw_pcie_add_bus(struct pci_bus *bus)
|
||||
|
@ -768,7 +768,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
|||
u32 membase;
|
||||
u32 memlimit;
|
||||
|
||||
/* set the number of lines as 4 */
|
||||
/* set the number of lanes */
|
||||
dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
|
||||
val &= ~PORT_LINK_MODE_MASK;
|
||||
switch (pp->lanes) {
|
||||
|
|
|
@ -41,7 +41,6 @@ struct pcie_port {
|
|||
void __iomem *va_cfg1_base;
|
||||
u64 io_base;
|
||||
u64 mem_base;
|
||||
spinlock_t conf_lock;
|
||||
struct resource cfg;
|
||||
struct resource io;
|
||||
struct resource mem;
|
||||
|
|
Загрузка…
Ссылка в новой задаче