Commit c2df02bd authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branches 'pci/host-altera', 'pci/host-designware', 'pci/host-generic',...

Merge branches 'pci/host-altera', 'pci/host-designware', 'pci/host-generic', 'pci/host-imx6', 'pci/host-iproc', 'pci/host-mvebu', 'pci/host-rcar', 'pci/host-tegra' and 'pci/host-xgene' into next

* pci/host-altera:
  PCI: altera: Add Altera PCIe MSI driver
  PCI: altera: Add Altera PCIe host controller driver
  ARM: Add msi.h to Kbuild

* pci/host-designware:
  PCI: designware: Make "clocks" and "clock-names" optional DT properties
  PCI: designware: Make driver arch-agnostic
  ARM/PCI: Replace pci_sys_data->align_resource with global function pointer
  PCI: designware: Use of_pci_get_host_bridge_resources() to parse DT
  Revert "PCI: designware: Program ATU with untranslated address"
  PCI: designware: Move calculation of bus addresses to DRA7xx
  PCI: designware: Make "num-lanes" an optional DT property
  PCI: designware: Require config accesses to be naturally aligned
  PCI: designware: Simplify dw_pcie_cfg_read/write() interfaces
  PCI: designware: Use exact access size in dw_pcie_cfg_read()
  PCI: spear: Fix dw_pcie_cfg_read/write() usage
  PCI: designware: Set up high part of MSI target address
  PCI: designware: Make get_msi_addr() return phys_addr_t, not u32
  PCI: designware: Implement multivector MSI IRQ setup
  PCI: designware: Factor out MSI msg setup
  PCI: Add msi_controller setup_irqs() method for special multivector setup
  PCI: designware: Fix PORT_LOGIC_LINK_WIDTH_MASK

* pci/host-generic:
  PCI: generic: Fix address window calculation for non-zero starting bus
  PCI: generic: Pass starting bus number to pci_scan_root_bus()
  PCI: generic: Allow multiple hosts with different map_bus() methods
  arm64: dts: Drop linux,pci-probe-only from the Seattle DTS
  powerpc/PCI: Fix lookup of linux,pci-probe-only property
  PCI: generic: Fix lookup of linux,pci-probe-only property
  of/pci: Add of_pci_check_probe_only to parse "linux,pci-probe-only"

* pci/host-imx6:
  PCI: imx6: Add PCIE_PHY_RX_ASIC_OUT_VALID definition
  PCI: imx6: Return real error code from imx6_add_pcie_port()

* pci/host-iproc:
  PCI: iproc: Fix header comment "Corporation" misspelling
  PCI: iproc: Add outbound mapping support
  PCI: iproc: Update PCIe device tree bindings
  PCI: iproc: Improve link detection logic
  PCI: iproc: Fix PCIe reset logic
  PCI: iproc: Call pci_fixup_irqs() for ARM64 as well as ARM
  PCI: iproc: Remove unused struct iproc_pcie.irqs[]
  PCI: iproc: Fix code comment to match code

* pci/host-mvebu:
  PCI: mvebu: Remove code restricting accesses to slot 0
  PCI: mvebu: Add PCI Express root complex capability block
  PCI: mvebu: Improve clock/reset handling
  PCI: mvebu: Use gpio_desc to carry around gpio
  PCI: mvebu: Use devm_kcalloc() to allocate an array
  PCI: mvebu: Use gpio_set_value_cansleep()
  PCI: mvebu: Split port parsing and resource claiming from  port setup
  PCI: mvebu: Fix memory leaks and refcount leaks
  PCI: mvebu: Move port parsing and resource claiming to  separate function
  PCI: mvebu: Use port->name rather than "PCIe%d.%d"
  PCI: mvebu: Report full node name when reporting a DT error
  PCI: mvebu: Use for_each_available_child_of_node() to walk child nodes
  PCI: mvebu: Use of_get_available_child_count()
  PCI: mvebu: Use exact config access size; don't read/modify/write
  PCI: mvebu: Return zero for reserved or unimplemented config space

* pci/host-rcar:
  PCI: rcar: Fix I/O offset for multiple host bridges
  PCI: rcar: Set root bus nr to that provided in DT
  PCI: rcar: Remove dependency on ARM-specific struct hw_pci
  PCI: rcar: Make PCI aware of the I/O resources
  PCI: rcar: Build pcie-rcar.c only on ARM
  PCI: rcar: Build pci-rcar-gen2.c only on ARM

* pci/host-tegra:
  PCI: tegra: Wrap static pgprot_t initializer with __pgprot()

* pci/host-xgene:
  PCI/MSI: xgene: Remove msi_controller assignment
* Altera PCIe MSI controller
Required properties:
- compatible: should contain "altr,msi-1.0"
- reg: specifies the physical base address of the controller and
the length of the memory mapped region.
- reg-names: must include the following entries:
"csr": CSR registers
"vector_slave": vectors slave port region
- interrupt-parent: interrupt source phandle.
- interrupts: specifies the interrupt source of the parent interrupt
controller. The format of the interrupt specifier depends on the
parent interrupt controller.
- num-vectors: number of vectors, range 1 to 32.
- msi-controller: indicates that this is MSI controller node
Example
msi0: msi@0xFF200000 {
compatible = "altr,msi-1.0";
reg = <0xFF200000 0x00000010
0xFF200010 0x00000080>;
reg-names = "csr", "vector_slave";
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 42 4>;
msi-controller;
num-vectors = <32>;
};
* Altera PCIe controller
Required properties:
- compatible : should contain "altr,pcie-root-port-1.0"
- reg: a list of physical base address and length for TXS and CRA.
- reg-names: must include the following entries:
"Txs": TX slave port region
"Cra": Control register access region
- interrupt-parent: interrupt source phandle.
- interrupts: specifies the interrupt source of the parent interrupt controller.
The format of the interrupt specifier depends on the parent interrupt
controller.
- device_type: must be "pci"
- #address-cells: set to <3>
- #size-cells: set to <2>
- #interrupt-cells: set to <1>
- ranges: describes the translation of addresses for root ports and standard
PCI regions.
- interrupt-map-mask and interrupt-map: standard PCI properties to define the
mapping of the PCIe interface to interrupt numbers.
Optional properties:
- msi-parent: Link to the hardware entity that serves as the MSI controller for this PCIe
controller.
- bus-range: PCI bus numbers covered
Example
pcie_0: pcie@0xc00000000 {
compatible = "altr,pcie-root-port-1.0";
reg = <0xc0000000 0x20000000>,
<0xff220000 0x00004000>;
reg-names = "Txs", "Cra";
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 40 4>;
interrupt-controller;
#interrupt-cells = <1>;
bus-range = <0x0 0xFF>;
device_type = "pci";
msi-parent = <&msi_to_gic_gen_0>;
#address-cells = <3>;
#size-cells = <2>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_0 1>,
<0 0 0 2 &pcie_0 2>,
<0 0 0 3 &pcie_0 3>,
<0 0 0 4 &pcie_0 4>;
ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
};
......@@ -17,6 +17,21 @@ Optional properties:
- phys: phandle of the PCIe PHY device
- phy-names: must be "pcie-phy"
- brcm,pcie-ob: Some iProc SoCs do not have the outbound address mapping done
by the ASIC after power on reset. In this case, SW needs to configure it
If the brcm,pcie-ob property is present, the following properties become
effective:
Required:
- brcm,pcie-ob-axi-offset: The offset from the AXI address to the internal
address used by the iProc PCIe core (not the PCIe address)
- brcm,pcie-ob-window-size: The outbound address mapping window size (in MB)
Optional:
- brcm,pcie-ob-oarr-size: Some iProc SoCs need the OARR size bit to be set to
increase the outbound window size
Example:
pcie0: pcie@18012000 {
compatible = "brcm,iproc-pcie";
......@@ -38,6 +53,11 @@ Example:
phys = <&phy 0 5>;
phy-names = "pcie-phy";
brcm,pcie-ob;
brcm,pcie-ob-oarr-size;
brcm,pcie-ob-axi-offset = <0x00000000>;
brcm,pcie-ob-window-size = <256>;
};
pcie1: pcie@18013000 {
......
......@@ -15,14 +15,16 @@ 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:
- num-lanes: number of lanes to use (this property should be specified unless
the link is brought already up in BIOS)
- reset-gpio: gpio pin number of power good signal
- bus-range: PCI bus numbers covered (it is recommended for new devicetrees to
specify this property, to keep backwards compatibility a range of 0x00-0xff
is assumed if not present)
- 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"
......@@ -34,8 +34,9 @@ Properties of the host controller node:
- #size-cells : Must be 2.
- reg : The Configuration Space base address and size, as accessed
from the parent bus.
from the parent bus. The base address corresponds to
the first bus in the "bus-range" property. If no
"bus-range" is specified, this will be bus 0 (the default).
Properties of the /chosen node:
......
......@@ -7938,6 +7938,14 @@ F: include/linux/pci*
F: arch/x86/pci/
F: arch/x86/kernel/quirks.c
PCI DRIVER FOR ALTERA PCIE IP
M: Ley Foon Tan <lftan@altera.com>
L: rfi@lists.rocketboards.org (moderated for non-subscribers)
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/pci/altera-pcie.txt
F: drivers/pci/host/pcie-altera.c
PCI DRIVER FOR ARM VERSATILE PLATFORM
M: Rob Herring <robh@kernel.org>
L: linux-pci@vger.kernel.org
......@@ -8039,6 +8047,14 @@ L: linux-pci@vger.kernel.org
S: Maintained
F: drivers/pci/host/*spear*
PCI MSI DRIVER FOR ALTERA MSI IP
M: Ley Foon Tan <lftan@altera.com>
L: rfi@lists.rocketboards.org (moderated for non-subscribers)
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
F: drivers/pci/host/pcie-altera-msi.c
PCI MSI DRIVER FOR APPLIEDMICRO XGENE
M: Duc Dang <dhdang@apm.com>
L: linux-pci@vger.kernel.org
......
......@@ -14,6 +14,7 @@ generic-y += local.h
generic-y += local64.h
generic-y += mm-arch-hooks.h
generic-y += msgbuf.h
generic-y += msi.h
generic-y += param.h
generic-y += parport.h
generic-y += poll.h
......
......@@ -52,12 +52,6 @@ struct pci_sys_data {
u8 (*swizzle)(struct pci_dev *, u8 *);
/* IRQ mapping */
int (*map_irq)(const struct pci_dev *, u8, u8);
/* Resource alignement requirements */
resource_size_t (*align_resource)(struct pci_dev *dev,
const struct resource *res,
resource_size_t start,
resource_size_t size,
resource_size_t align);
void *private_data; /* platform controller private data */
};
......
......@@ -17,6 +17,11 @@
#include <asm/mach/pci.h>
static int debug_pci;
static resource_size_t (*align_resource)(struct pci_dev *dev,
const struct resource *res,
resource_size_t start,
resource_size_t size,
resource_size_t align) = NULL;
/*
* We can't use pci_get_device() here since we are
......@@ -456,7 +461,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
sys->busnr = busnr;
sys->swizzle = hw->swizzle;
sys->map_irq = hw->map_irq;
sys->align_resource = hw->align_resource;
align_resource = hw->align_resource;
INIT_LIST_HEAD(&sys->resources);
if (hw->private_data)
......@@ -572,7 +577,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
struct pci_sys_data *sys = dev->sysdata;
resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO && start & 0x300)
......@@ -580,8 +584,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
start = (start + align - 1) & ~(align - 1);
if (sys->align_resource)
return sys->align_resource(dev, res, start, size, align);
if (align_resource)
return align_resource(dev, res, start, size, align);
return start;
}
......
......@@ -14,7 +14,6 @@ / {
chosen {
stdout-path = &serial0;
linux,pci-probe-only;
};
};
......
......@@ -40,6 +40,7 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/of.h>
#include <linux/of_pci.h>
#include <linux/kexec.h>
#include <asm/mmu.h>
......@@ -495,18 +496,7 @@ static void __init find_and_init_phbs(void)
* PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
* in chosen.
*/
if (of_chosen) {
const int *prop;
prop = of_get_property(of_chosen,
"linux,pci-probe-only", NULL);
if (prop) {
if (*prop)
pci_add_flags(PCI_PROBE_ONLY);
else
pci_clear_flags(PCI_PROBE_ONLY);
}
}
of_pci_check_probe_only();
}
static void __init pSeries_setup_arch(void)
......
......@@ -5,6 +5,7 @@
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
#include <asm-generic/pci-bridge.h>
static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int data)
......@@ -117,6 +118,31 @@ int of_get_pci_domain_nr(struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
/**
* of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
* is present and valid
*/
void of_pci_check_probe_only(void)
{
u32 val;
int ret;
ret = of_property_read_u32(of_chosen, "linux,pci-probe-only", &val);
if (ret) {
if (ret == -ENODATA || ret == -EOVERFLOW)
pr_warn("linux,pci-probe-only without valid value, ignoring\n");
return;
}
if (val)
pci_add_flags(PCI_PROBE_ONLY);
else
pci_clear_flags(PCI_PROBE_ONLY);
pr_info("PCI: PROBE_ONLY %sabled\n", val ? "en" : "dis");
}
EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
/**
* of_pci_dma_configure - Setup DMA configuration
* @dev: ptr to pci_dev struct of the PCI device
......
......@@ -39,7 +39,8 @@ config PCI_TEGRA
config PCI_RCAR_GEN2
bool "Renesas R-Car Gen2 Internal PCI controller"
depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
depends on ARM
depends on ARCH_SHMOBILE || COMPILE_TEST
help
Say Y here if you want internal PCI support on R-Car Gen2 SoC.
There are 3 internal PCI controllers available with a single
......@@ -47,7 +48,8 @@ config PCI_RCAR_GEN2
config PCI_RCAR_GEN2_PCIE
bool "Renesas R-Car PCIe controller"
depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
depends on ARM
depends on ARCH_SHMOBILE || COMPILE_TEST
help
Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
......@@ -145,4 +147,21 @@ config PCIE_IPROC_BCMA
Say Y here if you want to use the Broadcom iProc PCIe controller
through the BCMA bus interface
config PCIE_ALTERA
bool "Altera PCIe controller"
depends on ARM || NIOS2
depends on OF_PCI
select PCI_DOMAINS
help
Say Y here if you want to enable PCIe controller support on Altera
FPGA.
config PCIE_ALTERA_MSI
bool "Altera PCIe MSI feature"
depends on PCIE_ALTERA && PCI_MSI
select PCI_MSI_IRQ_DOMAIN
help
Say Y here if you want PCIe MSI support for the Altera FPGA.
This MSI driver supports Altera MSI to GIC controller IP.
endmenu
......@@ -17,3 +17,5 @@ obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
......@@ -62,6 +62,7 @@
#define PCIECTRL_DRA7XX_CONF_PHY_CS 0x010C
#define LINK_UP BIT(16)
#define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
struct dra7xx_pcie {
void __iomem *base;
......@@ -151,6 +152,12 @@ static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
static void dra7xx_pcie_host_init(struct pcie_port *pp)
{
dw_pcie_setup_rc(pp);
pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR;
pp->cfg1_base &= DRA7XX_CPU_TO_BUS_ADDR;
dra7xx_pcie_establish_link(pp);
if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
......
......@@ -454,7 +454,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
int ret;
exynos_pcie_sideband_dbi_r_mode(pp, true);
ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
exynos_pcie_sideband_dbi_r_mode(pp, false);
return ret;
}
......@@ -465,8 +465,7 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
int ret;
exynos_pcie_sideband_dbi_w_mode(pp, true);
ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
where, size, val);
ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
exynos_pcie_sideband_dbi_w_mode(pp, false);
return ret;
}
......
......@@ -27,7 +27,7 @@
struct gen_pci_cfg_bus_ops {
u32 bus_shift;
void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int);
struct pci_ops ops;
};
struct gen_pci_cfg_windows {
......@@ -35,7 +35,7 @@ struct gen_pci_cfg_windows {
struct resource *bus_range;
void __iomem **win;
const struct gen_pci_cfg_bus_ops *ops;
struct gen_pci_cfg_bus_ops *ops;
};
/*
......@@ -65,7 +65,11 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
.bus_shift = 16,
.map_bus = gen_pci_map_cfg_bus_cam,
.ops = {
.map_bus = gen_pci_map_cfg_bus_cam,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
}
};
static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
......@@ -80,12 +84,11 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
.bus_shift = 20,
.map_bus = gen_pci_map_cfg_bus_ecam,
};
static struct pci_ops gen_pci_ops = {
.read = pci_generic_config_read,
.write = pci_generic_config_write,
.ops = {
.map_bus = gen_pci_map_cfg_bus_ecam,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
}
};
static const struct of_device_id gen_pci_of_match[] = {
......@@ -166,6 +169,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
struct resource *bus_range;
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;
u32 sz = 1 << pci->cfg.ops->bus_shift;
err = of_address_to_resource(np, 0, &pci->cfg.res);
if (err) {
......@@ -193,10 +197,9 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
bus_range = pci->cfg.bus_range;
for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
u32 idx = busn - bus_range->start;
u32 sz = 1 << pci->cfg.ops->bus_shift;
pci->cfg.win[idx] = devm_ioremap(dev,
pci->cfg.res.start + busn * sz,
pci->cfg.res.start + idx * sz,
sz);
if (!pci->cfg.win[idx])
return -ENOMEM;
......@@ -210,7 +213,6 @@ static int gen_pci_probe(struct platform_device *pdev)
int err;
const char *type;
const struct of_device_id *of_id;
const int *prop;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
......@@ -225,17 +227,10 @@ static int gen_pci_probe(struct platform_device *pdev)
return -EINVAL;
}
prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
if (prop) {
if (*prop)
pci_add_flags(PCI_PROBE_ONLY);
else
pci_clear_flags(PCI_PROBE_ONLY);
}
of_pci_check_probe_only();
of_id = of_match_node(gen_pci_of_match, np);
pci->cfg.ops = of_id->data;
gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
pci->host.dev.parent = dev;
INIT_LIST_HEAD(&pci->host.windows);
INIT_LIST_HEAD(&pci->resources);
......@@ -256,7 +251,9 @@ static int gen_pci_probe(struct platform_device *pdev)
if (!pci_has_flag(PCI_PROBE_ONLY))
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources);
bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
&pci->cfg.ops->ops, pci, &pci->resources);
if (!bus) {
dev_err(dev, "Scanning rootbus failed");
return -ENODEV;
......
......@@ -74,6 +74,7 @@ struct imx6_pcie {
/* PHY registers (not memory-mapped) */
#define PCIE_PHY_RX_ASIC_OUT 0x100D
#define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0)
#define PHY_RX_OVRD_IN_LO 0x1005
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
......@@ -503,7 +504,7 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
if (rx_valid & 0x01)
if (rx_valid & PCIE_PHY_RX_ASIC_OUT_VALID)
return 0;
if ((debug_r0 & 0x3f) != 0x0d)
......@@ -539,7 +540,7 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
IRQF_SHARED, "mx6-pcie-msi", pp);
if (ret) {
dev_err(&pdev->dev, "failed to request MSI irq\n");
return -ENODEV;
return ret;
}
}
......
......@@ -70,7 +70,7 @@ static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
*bit_pos = offset >> 3;
}
u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
......@@ -322,7 +322,7 @@ static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
{
struct pcie_port *pp = &ks_pcie->pp;
u32 start = pp->mem.start, end = pp->mem.end;
u32 start = pp->mem->start, end = pp->mem->end;
int i, tr_size;
/* Disable BARs for inbound access */
......@@ -398,7 +398,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
return dw_pcie_cfg_read(addr + where, size, val);
}
int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
......@@ -410,7 +410,7 @@ int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
return dw_pcie_cfg_write(addr + where, size, val);
}
/**
......
......@@ -37,7 +37,7 @@ struct keystone_pcie {
/* Keystone DW specific MSI controller APIs/definitions */
void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
/* Keystone specific PCI controller APIs */
void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
......
This diff is collapsed.
......@@ -382,8 +382,8 @@ static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where)
static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
unsigned int busnr)
{
pgprot_t prot = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN |
L_PTE_MT_DEV_SHARED | L_PTE_SHARED;
pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
L_PTE_XN | L_PTE_MT_DEV_SHARED | L_PTE_SHARED);
phys_addr_t cs = pcie->cs->start;
struct tegra_pcie_bus *bus;
unsigned int i;
......
......@@ -509,24 +509,6 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
return 0;
}
static int xgene_pcie_msi_enable(struct pci_bus *bus)
{
struct device_node *msi_node;
msi_node = of_parse_phandle(bus->dev.of_node,
"msi-parent", 0);
if (!msi_node)
return -ENODEV;
bus->msi = of_pci_find_msi_chip_by_node(msi_node);
if (!bus->msi)
return -ENODEV;
of_node_put(msi_node);
bus->msi->dev = &bus->dev;
return 0;
}
static int xgene_pcie_probe_bridge(struct platform_device *pdev)
{
struct device_node *dn = pdev->dev.of_node;
......@@ -567,10 +549,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
if (!bus)
return -ENOMEM;
if (IS_ENABLED(CONFIG_PCI_MSI))
if (xgene_pcie_msi_enable(bus))
dev_info(port->dev, "failed to enable MSI\n");
pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
pci_bus_add_devices(bus);
......
/*
* Copyright Altera Corporation (C) 2013-2015. All rights reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define MSI_STATUS 0x0
#define MSI_ERROR 0x4
#define MSI_INTMASK 0x8
#define MAX_MSI_VECTORS 32
struct altera_msi {
DECLARE_BITMAP(used, MAX_MSI_VECTORS);
struct mutex lock; /* protect "used" bitmap */
struct platform_device *pdev;
struct irq_domain *msi_domain;
struct irq_domain *inner_domain;
void __iomem *csr_base;
void __iomem *vector_base;
phys_addr_t vector_phy;
u32 num_of_vectors;
int irq;
};
static inline void msi_writel(struct altera_msi *msi, const u32 value,
const u32 reg)
{
writel_relaxed(value, msi->csr_base + reg);
}
static inline u32 msi_readl(struct altera_msi *msi, const u32 reg)
{
return readl_relaxed(msi->csr_base + reg);
}
static void altera_msi_isr(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct altera_msi *msi;
unsigned long status;
u32 num_of_vectors;
u32 bit;
u32 virq;
chained_irq_enter(chip, desc);
msi = irq_desc_get_handler_data(desc);
num_of_vectors = msi->num_of_vectors;
while ((status = msi_readl(msi, MSI_STATUS)) != 0) {
for_each_set_bit(bit, &status, msi->num_of_vectors) {
/* Dummy read from vector to clear the interrupt */
readl_relaxed(msi->vector_base + (bit * sizeof(u32)));
virq = irq_find_mapping(msi->inner_domain, bit);
if (virq)
generic_handle_irq(virq);
else
dev_err(&msi->pdev->dev, "unexpected MSI\n");
}
}
chained_irq_exit(chip, desc);
}
static struct irq_chip altera_msi_irq_chip = {
.name = "Altera PCIe MSI",
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
};
static struct msi_domain_info altera_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_PCI_MSIX),
.chip = &altera_msi_irq_chip,
};
static void altera_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct altera_msi *msi = irq_data_get_irq_chip_data(data);
phys_addr_t addr = msi->vector_phy + (data->hwirq * sizeof(u32));
msg->address_lo = lower_32_bits(addr);
msg->address_hi = upper_32_bits(addr);
msg->data = data->hwirq;
dev_dbg(&msi->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n",
(int)data->hwirq, msg->address_hi, msg->address_lo);
}
static int altera_msi_set_affinity(struct irq_data *irq_data,
const struct cpumask *mask, bool force)
{
return -EINVAL;
}
static struct irq_chip altera_msi_bottom_irq_chip = {
.name = "Altera MSI",
.irq_compose_msi_msg = altera_compose_msi_msg,
.irq_set_affinity = altera_msi_set_affinity,
};
static int altera_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *args)
{
struct altera_msi *msi = domain->host_data;
unsigned long bit;
u32 mask;
WARN_ON(nr_irqs != 1);
mutex_lock(&msi->lock);
bit = find_first_zero_bit(msi->used, msi->num_of_vectors);
if (bit >= msi->num_of_vectors) {
mutex_unlock(&msi->lock);
return -ENOSPC;
}
set_bit(bit, msi->used);
mutex_unlock(&msi->lock);
irq_domain_set_info(domain, virq, bit, &altera_msi_bottom_irq_chip,
domain->host_data, handle_simple_irq,
NULL, NULL);
mask = msi_readl(msi, MSI_INTMASK);
mask |= 1 << bit;
msi_writel(msi, mask, MSI_INTMASK);
return 0;
}
static void altera_irq_domain_free(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs)
{
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct altera_msi *msi = irq_data_get_irq_chip_data(d);
u32 mask;
mutex_lock(&msi->lock);
if (!test_bit(d->hwirq, msi->used)) {
dev_err(&msi->pdev->dev, "trying to free unused MSI#%lu\n",
d->hwirq);
} else {
__clear_bit(d->hwirq, msi->used);
mask = msi_readl(msi, MSI_INTMASK);
mask &= ~(1 << d->hwirq);
msi_writel(msi, mask, MSI_INTMASK);
}
mutex_unlock(&msi->lock);
}
static const struct irq_domain_ops msi_domain_ops = {
.alloc = altera_irq_domain_alloc,
.free = altera_irq_domain_free,
};
static int altera_allocate_domains(struct altera_msi *msi)
{
msi->inner_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
&msi_domain_ops, msi);
if (!msi->inner_domain) {
dev_err(&msi->pdev->dev, "failed to create IRQ domain\n");
return -ENOMEM;
}
msi->msi_domain = pci_msi_create_irq_domain(msi->pdev->dev.of_node,
&altera_msi_domain_info, msi->inner_domain);
if (!msi->msi_domain) {
dev_err(&msi->pdev->dev, "failed to create MSI domain\n");
irq_domain_remove(msi->inner_domain);
return -ENOMEM;
}
return 0;
}
static void altera_free_domains(struct altera_msi *msi)
{
irq_domain_remove(msi->msi_domain);
irq_domain_remove(msi->inner_domain);
}
static int altera_msi_remove(struct platform_device *pdev)
{
struct altera_msi *msi = platform_get_drvdata(pdev);
msi_writel(msi, 0, MSI_INTMASK);
irq_set_chained_handler(msi->irq, NULL);
irq_set_handler_data(msi->irq, NULL);
altera_free_domains(msi);
platform_set_drvdata(pdev, NULL);
return 0;
}
static int altera_msi_probe(struct platform_device *pdev)
{
struct altera_msi *msi;
struct device_node *np = pdev->dev.of_node;
struct resource *res;
int ret;
msi = devm_kzalloc(&pdev->dev, sizeof(struct altera_msi),
GFP_KERNEL);
if (!msi)
return -ENOMEM;
mutex_init(&msi->lock);
msi->pdev = pdev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
if (!res) {
dev_err(&pdev->dev, "no csr memory resource defined\n");
return -ENODEV;
}
msi->csr_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi->csr_base)) {
dev_err(&pdev->dev, "failed to map csr memory\n");
return PTR_ERR(msi->csr_base);
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"vector_slave");
if (!res) {
dev_err(&pdev->dev, "no vector_slave memory resource defined\n");
return -ENODEV;
}
msi->vector_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi->vector_base)) {
dev_err(&pdev->dev, "failed to map vector_slave memory\n");
return PTR_ERR(msi->vector_base);
}
msi->vector_phy = res->start;
if (of_property_read_u32(np, "num-vectors", &msi->num_of_vectors)) {
dev_err(&pdev->dev, "failed to parse the number of vectors\n");
return -EINVAL;
}
ret = altera_allocate_domains(msi);
if (ret)
return ret;
msi->irq = platform_get_irq(pdev, 0);
if (msi->irq <= 0) {
dev_err(&pdev->dev, "failed to map IRQ: %d\n", msi->irq);
ret = -ENODEV;
goto err;
}
irq_set_chained_handler_and_data(msi->irq, altera_msi_isr, msi);
platform_set_drvdata(pdev, msi);
return 0;
err:
altera_msi_remove(pdev);
return ret;
}
static const struct of_device_id altera_msi_of_match[] = {
{ .compatible = "altr,msi-1.0", NULL },
{ },
};
static struct platform_driver altera_msi_driver = {
.driver = {
.name = "altera-msi",
.of_match_table = altera_msi_of_match,
},
.probe = altera_msi_probe,
.remove = altera_msi_remove,
};
static int __init altera_msi_init(void)
{
return platform_driver_register(&altera_msi_driver);
}
subsys_initcall(altera_msi_init);
MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
MODULE_DESCRIPTION("Altera PCIe MSI support");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
......@@ -27,25 +27,21 @@ struct pcie_port {
u8 root_bus_nr;
void __iomem *dbi_base;
u64 cfg0_base;
u64 cfg0_mod_base;
void __iomem *va_cfg0_base;
u32 cfg0_size;
u64 cfg1_base;
u64 cfg1_mod_base;
void __iomem *va_cfg1_base;
u32 cfg1_size;
u64 io_base;
u64 io_mod_base;
resource_size_t io_base;
phys_addr_t io_bus_addr;
u32 io_size;
u64 mem_base;
u64 mem_mod_base;
phys_addr_t mem_bus_addr;
u32 mem_size;
struct resource cfg;
struct resource io;
struct resource mem;
struct resource busn;
struct resource *cfg;
struct resource *io;
struct resource *mem;
struct resource *busn;
int irq;
u32 lanes;
struct pcie_host_ops *ops;
......@@ -70,14 +66,14 @@ struct pcie_host_ops {
void (*host_init)(struct pcie_port *pp);
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
u32 (*get_msi_addr)(struct pcie_port *pp);
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
};
int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val);
int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
int dw_pcie_link_up(struct pcie_port *pp);
......
......@@ -54,6 +54,33 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
return -ENOMEM;
}
if (of_property_read_bool(np, "brcm,pcie-ob")) {
u32 val;
ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset",
&val);
if (ret) {
dev_err(pcie->dev,
"missing brcm,pcie-ob-axi-offset property\n");
return ret;
}
pcie->ob.axi_offset = val;
ret = of_property_read_u32(np, "brcm,pcie-ob-window-size",
&val);
if (ret) {
dev_err(pcie->dev,
"missing brcm,pcie-ob-window-size property\n");
return ret;
}
pcie->ob.window_size = (resource_size_t)val * SZ_1M;
if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size"))
pcie->ob.set_oarr_size = true;
pcie->need_ob_cfg = true;
}
/* PHY use is optional */
pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy");
if (IS_ERR(pcie->phy)) {
......
/*
* Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
* Copyright (C) 2015 Broadcom Corporatcommon ion
* Copyright (C) 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -31,6 +31,8 @@
#include "pcie-iproc.h"
#define CLK_CONTROL_OFFSET 0x000
#define EP_PERST_SOURCE_SELECT_SHIFT 2
#define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
#define EP_MODE_SURVIVE_PERST_SHIFT 1
#define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
#define RC_PCIE_RST_OUTPUT_SHIFT 0
......@@ -58,6 +60,24 @@
#define SYS_RC_INTX_EN 0x330
#define SYS_RC_INTX_MASK 0xf
#define PCIE_LINK_STATUS_OFFSET 0xf0c
#define PCIE_PHYLINKUP_SHIFT 3
#define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
#define PCIE_DL_ACTIVE_SHIFT 2
#define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
#define OARR_VALID_SHIFT 0
#define OARR_VALID BIT(OARR_VALID_SHIFT)
#define OARR_SIZE_CFG_SHIFT 1
#define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT)
#define OARR_LO(window) (0xd20 + (window) * 8)
#define OARR_HI(window) (0xd24 + (window) * 8)
#define OMAP_LO(window) (0xd40 + (window) * 8)
#define OMAP_HI(window) (0xd44 + (window) * 8)
#define MAX_NUM_OB_WINDOWS 2
static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
{
struct iproc_pcie *pcie;
......@@ -119,23 +139,32 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie)
u32 val;
/*
* Configure the PCIe controller as root complex and send a downstream
* reset
* Select perst_b signal as reset source. Put the device into reset,
* and then bring it out of reset
*/
val = EP_MODE_SURVIVE_PERST | RC_PCIE_RST_OUTPUT;
val = readl(pcie->base + CLK_CONTROL_OFFSET);
val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
~RC_PCIE_RST_OUTPUT;
writel(val, pcie->base + CLK_CONTROL_OFFSET);
udelay(250);
val &= ~EP_MODE_SURVIVE_PERST;
val |= RC_PCIE_RST_OUTPUT;
writel(val, pcie->base + CLK_CONTROL_OFFSET);
msleep(250);
msleep(100);
}
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
{
u8 hdr_type;
u32 link_ctrl;
u32 link_ctrl, class, val;
u16 pos, link_status;
int link_is_active = 0;
bool link_is_active = false;
val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET);
if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
dev_err(pcie->dev, "PHY or data link is INACTIVE!\n");
return -ENODEV;
}
/* make sure we are not in EP mode */
pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
......@@ -145,14 +174,19 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
}
/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE,
PCI_CLASS_BRIDGE_PCI);
#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
#define PCI_CLASS_BRIDGE_MASK 0xffff00
#define PCI_CLASS_BRIDGE_SHIFT 8
pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class);
class &= ~PCI_CLASS_BRIDGE_MASK;
class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class);
/* check link status to see if link is active */
pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
if (link_status & PCI_EXP_LNKSTA_NLW)
link_is_active = 1;
link_is_active = true;
if (!link_is_active) {
/* try GEN 1 link speed */
......@@ -176,7 +210,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
&link_status);
if (link_status & PCI_EXP_LNKSTA_NLW)
link_is_active = 1;
link_is_active = true;
}
}
......@@ -190,6 +224,101 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie)
writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
}
/**
* Some iProc SoCs require the SW to configure the outbound address mapping
*
* Outbound address translation:
*
* iproc_pcie_address = axi_address - axi_offset
* OARR = iproc_pcie_address
* OMAP = pci_addr
*
* axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address
*/
static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
u64 pci_addr, resource_size_t size)
{
struct iproc_pcie_ob *ob = &pcie->ob;
unsigned i;
u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS;
u64 remainder;
if (size > max_size) {
dev_err(pcie->dev,
"res size 0x%pap exceeds max supported size 0x%llx\n",
&size, max_size);
return -EINVAL;
}
div64_u64_rem(size, ob->window_size, &remainder);
if (remainder) {
dev_err(pcie->dev,
"res size %pap needs to be multiple of window size %pap\n",
&size, &ob->window_size);
return -EINVAL;
}
if (axi_addr < ob->axi_offset) {
dev_err(pcie->dev,
"axi address %pap less than offset %pap\n",
&axi_addr, &ob->axi_offset);
return -EINVAL;
}
/*
* Translate the AXI address to the internal address used by the iProc
* PCIe core before programming the OARR
*/
axi_addr -= ob->axi_offset;
for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) {
writel(lower_32_bits(axi_addr) | OARR_VALID |
(ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i));
writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i));
writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i));
writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i));
size -= ob->window_size;
if (size == 0)
break;
axi_addr += ob->window_size;
pci_addr += ob->window_size;
}
return 0;
}
static int iproc_pcie_map_ranges(struct iproc_pcie *pcie,
struct list_head *resources)
{
struct resource_entry *window;
int ret;
resource_list_for_each_entry(window, resources) {
struct resource *res = window->res;
u64 res_type = resource_type(res);
switch (res_type) {
case IORESOURCE_IO:
case IORESOURCE_BUS:
break;
case IORESOURCE_MEM:
ret = iproc_pcie_setup_ob(pcie, res->start,
res->start - window->offset,
resource_size(res));
if (ret)
return ret;
break;
default:
dev_err(pcie->dev, "invalid resource %pR\n", res);
return -EINVAL;
}
}
return 0;
}
int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
{
int ret;
......@@ -213,6 +342,14 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
iproc_pcie_reset(pcie);
if (pcie->need_ob_cfg) {
ret = iproc_pcie_map_ranges(pcie, res);
if (ret) {
dev_err(pcie->dev, "map failed\n");
goto err_power_off_phy;
}
}
#ifdef CONFIG_ARM
pcie->sysdata.private_data = pcie;
sysdata = &pcie->sysdata;
......@@ -238,9 +375,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
#ifdef CONFIG_ARM
pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
#endif
pci_bus_add_devices(bus);
return 0;
......
......@@ -14,17 +14,30 @@
#ifndef _PCIE_IPROC_H
#define _PCIE_IPROC_H
#define IPROC_PCIE_MAX_NUM_IRQS 6
/**
* iProc PCIe outbound mapping
* @set_oarr_size: indicates the OARR size bit needs to be set
* @axi_offset: offset from the AXI address to the internal address used by
* the iProc PCIe core
* @window_size: outbound window size
*/
struct iproc_pcie_ob {
bool set_oarr_size;
resource_size_t axi_offset;
resource_size_t window_size;
};
/**
* iProc PCIe device
* @dev: pointer to device data structure
* @base: PCIe host controller I/O register base
* @resources: linked list of all PCI resources
* @sysdata: Per PCI controller data (ARM-specific)
* @root_bus: pointer to root bus
* @phy: optional PHY device that controls the Serdes
* @irqs: interrupt IDs
* @map_irq: function callback to map interrupts
* @need_ob_cfg: indidates SW needs to configure the outbound mapping window
* @ob: outbound mapping parameters
*/
struct iproc_pcie {
struct device *dev;
......@@ -34,8 +47,9 @@ struct iproc_pcie {
#endif
struct pci_bus *root_bus;
struct phy *phy;
int irqs[IPROC_PCIE_MAX_NUM_IRQS];
int (*map_irq)(const struct pci_dev *, u8, u8);
bool need_ob_cfg;
struct iproc_pcie_ob ob;
};
int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
......
......@@ -108,6 +108,8 @@
#define RCAR_PCI_MAX_RESOURCES 4
#define MAX_NR_INBOUND_MAPS 6
static unsigned long global_io_offset;
struct rcar_msi {
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
struct irq_domain *domain;
......@@ -124,7 +126,16 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
}
/* Structure representing the PCIe interface */
/*
* ARM pcibios functions expect the ARM struct pci_sys_data as the PCI
* sysdata. Add pci_sys_data as the first element in struct gen_pci so
* that when we use a gen_pci pointer as sysdata, it is also a pointer to
* a struct pci_sys_data.
*/
struct rcar_pcie {
#ifdef CONFIG_ARM
struct pci_sys_data sys;
#endif
struct device *dev;
void __iomem *base;
struct resource res[RCAR_PCI_MAX_RESOURCES];
......@@ -135,11 +146,6 @@ struct rcar_pcie {
struct rcar_msi msi;
};
static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
{
return sys->private_data;
}
static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
unsigned long reg)
{
......@@ -258,7 +264,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
struct rcar_pcie *pcie = bus->sysdata;
int ret;
ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ,
......@@ -283,7 +289,7 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
struct rcar_pcie *pcie = bus->sysdata;
int shift, ret;
u32 data;
......@@ -353,13 +359,12 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie)
rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win));
}
static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pcie)
{
struct rcar_pcie *pcie = sys_to_pcie(sys);
struct resource *res;
int i;
pcie->root_bus_nr = -1;
pcie->root_bus_nr = pcie->busn.start;
/* Setup PCI resources */
for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) {
......@@ -372,32 +377,53 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
if (res->flags & IORESOURCE_IO) {
phys_addr_t io_start = pci_pio_to_address(res->start);
pci_ioremap_io(nr * SZ_64K, io_start);
} else
pci_add_resource(&sys->resources, res);
pci_ioremap_io(global_io_offset, io_start);
global_io_offset += SZ_64K;
}
pci_add_resource(resource, res);
}
pci_add_resource(&sys->resources, &pcie->busn);
pci_add_resource(resource, &pcie->busn);
return 1;
}
static struct hw_pci rcar_pci = {
.setup = rcar_pcie_setup,
.map_irq = of_irq_parse_and_map_pci,
.ops = &rcar_pcie_ops,
};
static void rcar_pcie_enable(struct rcar_pcie *pcie)
static int rcar_pcie_enable(struct rcar_pcie *pcie)
{
struct platform_device *pdev = to_platform_device(pcie->dev);
struct pci_bus *bus, *child;
LIST_HEAD(res);
rcar_pci.nr_controllers = 1;
rcar_pci.private_data = (void **)&pcie;
#ifdef CONFIG_PCI_MSI
rcar_pci.msi_ctrl = &pcie->msi.chip;
#endif
rcar_pcie_setup(&res, pcie);
/* Do not reassign resources if probe only */
if (!pci_has_flag(PCI_PROBE_ONLY))
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
pci_common_init_dev(&pdev->dev, &rcar_pci);
if (IS_ENABLED(CONFIG_PCI_MSI))
bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr,
&rcar_pcie_ops, pcie, &res, &pcie->msi.chip);
else
bus = pci_scan_root_bus(pcie->dev, pcie->root_bus_nr,
&rcar_pcie_ops, pcie, &res);
if (!bus) {
dev_err(pcie->dev, "Scanning rootbus failed");
return -ENODEV;
}
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
if (!pci_has_flag(PCI_PROBE_ONLY)) {
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
}
pci_bus_add_devices(bus);
return 0;
}
static int phy_wait_for_ack(struct rcar_pcie *pcie)
......@@ -970,9 +996,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
data = rcar_pci_read_reg(pcie, MACSR);
dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
rcar_pcie_enable(pcie);
return 0;
return rcar_pcie_enable(pcie);
}
static struct platform_driver rcar_pcie_driver = {
......
......@@ -163,34 +163,34 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
val &= ~PCI_EXP_DEVCTL_READRQ;
dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
/*
* if is_gen1 is set then handle it, so that some buggy card
* also works
*/
if (spear13xx_pcie->is_gen1) {
dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
&val);
dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
4, &val);
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
PCI_EXP_LNKCAP, 4, val);
dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
PCI_EXP_LNKCAP, 4, val);
}
dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
&val);
dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
2, &val);
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
PCI_EXP_LNKCTL2, 4, val);
dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
PCI_EXP_LNKCTL2, 2, val);
}
}
......
......@@ -105,9 +105,12 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
struct msi_controller *chip = dev->bus->msi;
struct msi_desc *entry;
int ret;
if (chip && chip->setup_irqs)
return chip->setup_irqs(chip, dev, nvec, type);
/*
* If an architecture wants to support multiple MSI, it needs to
* override arch_setup_msi_irqs()
......
......@@ -163,6 +163,8 @@ struct msi_controller {
int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev,
struct msi_desc *desc);
int (*setup_irqs)(struct msi_controller *chip, struct pci_dev *dev,
int nvec, int type);
void (*teardown_irq)(struct msi_controller *chip, unsigned int irq);
};
......
......@@ -17,6 +17,7 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
int of_get_pci_domain_nr(struct device_node *node);
void of_pci_dma_configure(struct pci_dev *pci_dev);
void of_pci_check_probe_only(void);
#else
static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
{
......@@ -53,6 +54,8 @@ of_get_pci_domain_nr(struct device_node *node)
}
static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
static inline void of_pci_check_probe_only(void) { }
#endif
#if defined(CONFIG_OF_ADDRESS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment