summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2017-02-21 15:12:18 -0600
committerBjorn Helgaas <bhelgaas@google.com>2017-02-21 15:12:18 -0600
commit3bb0356bb1b5a2c4434b4a3267df6dd9927ca5bf (patch)
treea601387ad9c6a3fd66125e4506b560530280ccbd /drivers
parent4c2ae32d4c6ccd63819f36702f8455a5b08eaca8 (diff)
parent7a2b3f024b8b724257d82f76690e68c69d797efd (diff)
Merge branch 'pci/host-designware' into next
* pci/host-designware: PCI: dwc: Remove dependency of designware on CONFIG_PCI PCI: dwc: Add CONFIG_PCIE_DW_HOST to enable PCI dwc host PCI: dwc: Split pcie-designware.c into host and core files PCI: dwc: designware: Fix style errors in pcie-designware.c PCI: dwc: designware: Parse "num-lanes" property in dw_pcie_setup_rc() PCI: dwc: all: Split struct pcie_port into host-only and core structures PCI: dwc: designware: Get device pointer at the start of dw_pcie_host_init() PCI: dwc: all: Rename cfg_read/cfg_write to read/write PCI: dwc: all: Use platform_set_drvdata() to save private data PCI: dwc: designware: Move register defines to designware header file PCI: dwc: Use PTR_ERR_OR_ZERO to simplify code PCI: dra7xx: Group PHY API invocations PCI: dra7xx: Enable MSI and legacy interrupts simultaneously PCI: dra7xx: Add support to force RC to work in GEN1 mode PCI: dra7xx: Simplify probe code with devm_gpiod_get_optional() PCI: Move DesignWare IP support to new drivers/pci/dwc/ directory PCI: designware: Check for iATU unroll only on platforms that use ATU
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/pci/Kconfig1
-rw-r--r--drivers/pci/dwc/Kconfig132
-rw-r--r--drivers/pci/dwc/Makefile24
-rw-r--r--drivers/pci/dwc/pci-dra7xx.c (renamed from drivers/pci/host/pci-dra7xx.c)247
-rw-r--r--drivers/pci/dwc/pci-exynos.c (renamed from drivers/pci/host/pci-exynos.c)81
-rw-r--r--drivers/pci/dwc/pci-imx6.c (renamed from drivers/pci/host/pci-imx6.c)131
-rw-r--r--drivers/pci/dwc/pci-keystone-dw.c (renamed from drivers/pci/host/pci-keystone-dw.c)87
-rw-r--r--drivers/pci/dwc/pci-keystone.c (renamed from drivers/pci/host/pci-keystone.c)56
-rw-r--r--drivers/pci/dwc/pci-keystone.h (renamed from drivers/pci/host/pci-keystone.h)4
-rw-r--r--drivers/pci/dwc/pci-layerscape.c (renamed from drivers/pci/host/pci-layerscape.c)93
-rw-r--r--drivers/pci/dwc/pcie-armada8k.c (renamed from drivers/pci/host/pcie-armada8k.c)87
-rw-r--r--drivers/pci/dwc/pcie-artpec6.c (renamed from drivers/pci/host/pcie-artpec6.c)50
-rw-r--r--drivers/pci/dwc/pcie-designware-host.c (renamed from drivers/pci/host/pcie-designware.c)445
-rw-r--r--drivers/pci/dwc/pcie-designware-plat.c (renamed from drivers/pci/host/pcie-designware-plat.c)29
-rw-r--r--drivers/pci/dwc/pcie-designware.c233
-rw-r--r--drivers/pci/dwc/pcie-designware.h198
-rw-r--r--drivers/pci/dwc/pcie-hisi.c (renamed from drivers/pci/host/pcie-hisi.c)57
-rw-r--r--drivers/pci/dwc/pcie-qcom.c (renamed from drivers/pci/host/pcie-qcom.c)87
-rw-r--r--drivers/pci/dwc/pcie-spear13xx.c (renamed from drivers/pci/host/pcie-spear13xx.c)85
-rw-r--r--drivers/pci/host/Kconfig113
-rw-r--r--drivers/pci/host/Makefile12
-rw-r--r--drivers/pci/host/pcie-designware.h86
23 files changed, 1322 insertions, 1019 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 060026a02f59..f521cb0e58d6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,9 @@ obj-$(CONFIG_PINCTRL) += pinctrl/
obj-$(CONFIG_GPIOLIB) += gpio/
obj-y += pwm/
obj-$(CONFIG_PCI) += pci/
+# PCI dwc controller drivers
+obj-y += pci/dwc/
+
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 6555eb78d91c..df141420c902 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -132,4 +132,5 @@ config PCI_HYPERV
PCI devices from a PCI backend to support PCI driver domains.
source "drivers/pci/hotplug/Kconfig"
+source "drivers/pci/dwc/Kconfig"
source "drivers/pci/host/Kconfig"
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig
new file mode 100644
index 000000000000..dfb8a69afc28
--- /dev/null
+++ b/drivers/pci/dwc/Kconfig
@@ -0,0 +1,132 @@
+menu "DesignWare PCI Core Support"
+
+config PCIE_DW
+ bool
+
+config PCIE_DW_HOST
+ bool
+ depends on PCI
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW
+
+config PCI_DRA7XX
+ bool "TI DRA7xx PCIe controller"
+ depends on PCI
+ depends on OF && HAS_IOMEM && TI_PIPE3
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW_HOST
+ help
+ Enables support for the PCIe controller in the DRA7xx SoC. There
+ are two instances of PCIe controller in DRA7xx. This controller can
+ act both as EP and RC. This reuses the Designware core.
+
+config PCIE_DW_PLAT
+ bool "Platform bus based DesignWare PCIe Controller"
+ depends on PCI
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW_HOST
+ ---help---
+ This selects the DesignWare PCIe controller support. Select this if
+ you have a PCIe controller on Platform bus.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
+config PCI_EXYNOS
+ bool "Samsung Exynos PCIe controller"
+ depends on PCI
+ depends on SOC_EXYNOS5440
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+
+config PCI_IMX6
+ bool "Freescale i.MX6 PCIe controller"
+ depends on PCI
+ depends on SOC_IMX6Q
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+
+config PCIE_SPEAR13XX
+ bool "STMicroelectronics SPEAr PCIe controller"
+ depends on PCI
+ depends on ARCH_SPEAR13XX
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want PCIe support on SPEAr13XX SoCs.
+
+config PCI_KEYSTONE
+ bool "TI Keystone PCIe controller"
+ depends on PCI
+ depends on ARCH_KEYSTONE
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want to enable PCI controller support on Keystone
+ SoCs. The PCI controller on Keystone is based on Designware hardware
+ and therefore the driver re-uses the Designware core functions to
+ implement the driver.
+
+config PCI_LAYERSCAPE
+ bool "Freescale Layerscape PCIe controller"
+ depends on PCI
+ depends on OF && (ARM || ARCH_LAYERSCAPE)
+ depends on PCI_MSI_IRQ_DOMAIN
+ select MFD_SYSCON
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want PCIe controller support on Layerscape SoCs.
+
+config PCI_HISI
+ depends on OF && ARM64
+ bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers"
+ depends on PCI
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want PCIe controller support on HiSilicon
+ Hip05 and Hip06 SoCs
+
+config PCIE_QCOM
+ bool "Qualcomm PCIe controller"
+ depends on PCI
+ depends on ARCH_QCOM && OF
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here to enable PCIe controller support on Qualcomm SoCs. The
+ PCIe controller uses the Designware core plus Qualcomm-specific
+ hardware wrappers.
+
+config PCIE_ARMADA_8K
+ bool "Marvell Armada-8K PCIe controller"
+ depends on PCI
+ depends on ARCH_MVEBU
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Armada-8K SoCs. The PCIe controller on Armada-8K is based on
+ Designware hardware and therefore the driver re-uses the
+ Designware core functions to implement the driver.
+
+config PCIE_ARTPEC6
+ bool "Axis ARTPEC-6 PCIe controller"
+ depends on PCI
+ depends on MACH_ARTPEC6
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIEPORTBUS
+ select PCIE_DW_HOST
+ help
+ Say Y here to enable PCIe controller support on Axis ARTPEC-6
+ SoCs. This PCIe controller uses the DesignWare core.
+
+endmenu
diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile
new file mode 100644
index 000000000000..a2df13c28798
--- /dev/null
+++ b/drivers/pci/dwc/Makefile
@@ -0,0 +1,24 @@
+obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
+obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
+obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
+obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
+obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
+obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
+obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
+obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
+obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
+
+# The following drivers are for devices that use the generic ACPI
+# pci_root.c driver but don't support standard ECAM config access.
+# They contain MCFG quirks to replace the generic ECAM accessors with
+# device-specific ones that are shared with the DT driver.
+
+# The ACPI driver is generic and should not require driver-specific
+# config options to be enabled, so we always build these drivers on
+# ARM64 and use internal ifdefs to only build the pieces we need
+# depending on whether ACPI, the DT driver, or both are enabled.
+
+obj-$(CONFIG_ARM64) += pcie-hisi.o
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c
index 9595fad63f6f..0984baff07e3 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/dwc/pci-dra7xx.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_gpio.h>
+#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@@ -63,14 +64,18 @@
#define LINK_UP BIT(16)
#define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
+#define EXP_CAP_ID_OFFSET 0x70
+
struct dra7xx_pcie {
- struct pcie_port pp;
+ struct dw_pcie *pci;
void __iomem *base; /* DT ti_conf */
int phy_count; /* DT phy-names count */
struct phy **phy;
+ int link_gen;
+ struct irq_domain *irq_domain;
};
-#define to_dra7xx_pcie(x) container_of((x), struct dra7xx_pcie, pp)
+#define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev)
static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset)
{
@@ -83,9 +88,9 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
writel(value, pcie->base + offset);
}
-static int dra7xx_pcie_link_up(struct pcie_port *pp)
+static int dra7xx_pcie_link_up(struct dw_pcie *pci)
{
- struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+ struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
return !!(reg & LINK_UP);
@@ -93,20 +98,41 @@ static int dra7xx_pcie_link_up(struct pcie_port *pp)
static int dra7xx_pcie_establish_link(struct dra7xx_pcie *dra7xx)
{
- struct pcie_port *pp = &dra7xx->pp;
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = dra7xx->pci;
+ struct device *dev = pci->dev;
u32 reg;
+ u32 exp_cap_off = EXP_CAP_ID_OFFSET;
- if (dw_pcie_link_up(pp)) {
+ if (dw_pcie_link_up(pci)) {
dev_err(dev, "link is already up\n");
return 0;
}
+ if (dra7xx->link_gen == 1) {
+ dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
+ 4, &reg);
+ if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
+ reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
+ reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
+ dw_pcie_write(pci->dbi_base + exp_cap_off +
+ PCI_EXP_LNKCAP, 4, reg);
+ }
+
+ dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
+ 2, &reg);
+ if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
+ reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
+ reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
+ dw_pcie_write(pci->dbi_base + exp_cap_off +
+ PCI_EXP_LNKCTL2, 2, reg);
+ }
+ }
+
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
reg |= LTSSM_EN;
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
- return dw_pcie_wait_for_link(pp);
+ return dw_pcie_wait_for_link(pci);
}
static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
@@ -117,19 +143,14 @@ static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS);
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI,
~LEG_EP_INTERRUPTS & ~MSI);
-
- if (IS_ENABLED(CONFIG_PCI_MSI))
- dra7xx_pcie_writel(dra7xx,
- PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI);
- else
- dra7xx_pcie_writel(dra7xx,
- PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI,
- LEG_EP_INTERRUPTS);
+ dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI,
+ MSI | LEG_EP_INTERRUPTS);
}
static void dra7xx_pcie_host_init(struct pcie_port *pp)
{
- struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
@@ -139,13 +160,11 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp)
dw_pcie_setup_rc(pp);
dra7xx_pcie_establish_link(dra7xx);
- if (IS_ENABLED(CONFIG_PCI_MSI))
- dw_pcie_msi_init(pp);
+ dw_pcie_msi_init(pp);
dra7xx_pcie_enable_interrupts(dra7xx);
}
-static struct pcie_host_ops dra7xx_pcie_host_ops = {
- .link_up = dra7xx_pcie_link_up,
+static struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
.host_init = dra7xx_pcie_host_init,
};
@@ -164,7 +183,9 @@ static const struct irq_domain_ops intx_domain_ops = {
static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
{
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
+ struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
struct device_node *node = dev->of_node;
struct device_node *pcie_intc_node = of_get_next_child(node, NULL);
@@ -173,9 +194,9 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
return -ENODEV;
}
- pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
- &intx_domain_ops, pp);
- if (!pp->irq_domain) {
+ dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+ &intx_domain_ops, pp);
+ if (!dra7xx->irq_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n");
return -ENODEV;
}
@@ -186,7 +207,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
{
struct dra7xx_pcie *dra7xx = arg;
- struct pcie_port *pp = &dra7xx->pp;
+ struct dw_pcie *pci = dra7xx->pci;
+ struct pcie_port *pp = &pci->pp;
u32 reg;
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
@@ -199,7 +221,8 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
case INTB:
case INTC:
case INTD:
- generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
+ generic_handle_irq(irq_find_mapping(dra7xx->irq_domain,
+ ffs(reg)));
break;
}
@@ -212,7 +235,8 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
{
struct dra7xx_pcie *dra7xx = arg;
- struct device *dev = dra7xx->pp.dev;
+ struct dw_pcie *pci = dra7xx->pci;
+ struct device *dev = pci->dev;
u32 reg;
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN);
@@ -267,8 +291,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
struct platform_device *pdev)
{
int ret;
- struct pcie_port *pp = &dra7xx->pp;
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = dra7xx->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = pci->dev;
struct resource *res;
pp->irq = platform_get_irq(pdev, 1);
@@ -285,15 +310,13 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
return ret;
}
- if (!IS_ENABLED(CONFIG_PCI_MSI)) {
- ret = dra7xx_pcie_init_irq_domain(pp);
- if (ret < 0)
- return ret;
- }
+ ret = dra7xx_pcie_init_irq_domain(pp);
+ if (ret < 0)
+ return ret;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics");
- pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
- if (!pp->dbi_base)
+ pci->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pci->dbi_base)
return -ENOMEM;
ret = dw_pcie_host_init(pp);
@@ -305,6 +328,49 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
return 0;
}
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = dra7xx_pcie_link_up,
+};
+
+static void dra7xx_pcie_disable_phy(struct dra7xx_pcie *dra7xx)
+{
+ int phy_count = dra7xx->phy_count;
+
+ while (phy_count--) {
+ phy_power_off(dra7xx->phy[phy_count]);
+ phy_exit(dra7xx->phy[phy_count]);
+ }
+}
+
+static int dra7xx_pcie_enable_phy(struct dra7xx_pcie *dra7xx)
+{
+ int phy_count = dra7xx->phy_count;
+ int ret;
+ int i;
+
+ for (i = 0; i < phy_count; i++) {
+ ret = phy_init(dra7xx->phy[i]);
+ if (ret < 0)
+ goto err_phy;
+
+ ret = phy_power_on(dra7xx->phy[i]);
+ if (ret < 0) {
+ phy_exit(dra7xx->phy[i]);
+ goto err_phy;
+ }
+ }
+
+ return 0;
+
+err_phy:
+ while (--i >= 0) {
+ phy_power_off(dra7xx->phy[i]);
+ phy_exit(dra7xx->phy[i]);
+ }
+
+ return ret;
+}
+
static int __init dra7xx_pcie_probe(struct platform_device *pdev)
{
u32 reg;
@@ -315,21 +381,26 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
struct phy **phy;
void __iomem *base;
struct resource *res;
- struct dra7xx_pcie *dra7xx;
+ struct dw_pcie *pci;
struct pcie_port *pp;
+ struct dra7xx_pcie *dra7xx;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
char name[10];
- int gpio_sel;
- enum of_gpio_flags flags;
- unsigned long gpio_flags;
+ struct gpio_desc *reset;
dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
if (!dra7xx)
return -ENOMEM;
- pp = &dra7xx->pp;
- pp->dev = dev;
+ pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+ if (!pci)
+ return -ENOMEM;
+
+ pci->dev = dev;
+ pci->ops = &dw_pcie_ops;
+
+ pp = &pci->pp;
pp->ops = &dra7xx_pcie_host_ops;
irq = platform_get_irq(pdev, 0);
@@ -365,22 +436,21 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
phy[i] = devm_phy_get(dev, name);
if (IS_ERR(phy[i]))
return PTR_ERR(phy[i]);
-
- ret = phy_init(phy[i]);
- if (ret < 0)
- goto err_phy;
-
- ret = phy_power_on(phy[i]);
- if (ret < 0) {
- phy_exit(phy[i]);
- goto err_phy;
- }
}
dra7xx->base = base;
dra7xx->phy = phy;
+ dra7xx->pci = pci;
dra7xx->phy_count = phy_count;
+ ret = dra7xx_pcie_enable_phy(dra7xx);
+ if (ret) {
+ dev_err(dev, "failed to enable phy\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, dra7xx);
+
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
@@ -388,19 +458,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
goto err_get_sync;
}
- gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags);
- if (gpio_is_valid(gpio_sel)) {
- gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
- ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags,
- "pcie_reset");
- if (ret) {
- dev_err(dev, "gpio%d request failed, ret %d\n",
- gpio_sel, ret);
- goto err_gpio;
- }
- } else if (gpio_sel == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ reset = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(reset)) {
+ ret = PTR_ERR(reset);
+ dev_err(&pdev->dev, "gpio request failed, ret %d\n", ret);
goto err_gpio;
}
@@ -408,11 +469,14 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
reg &= ~LTSSM_EN;
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+ dra7xx->link_gen = of_pci_get_max_link_speed(np);
+ if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2)
+ dra7xx->link_gen = 2;
+
ret = dra7xx_add_pcie_port(dra7xx, pdev);
if (ret < 0)
goto err_gpio;
- platform_set_drvdata(pdev, dra7xx);
return 0;
err_gpio:
@@ -420,12 +484,7 @@ err_gpio:
err_get_sync:
pm_runtime_disable(dev);
-
-err_phy:
- while (--i >= 0) {
- phy_power_off(phy[i]);
- phy_exit(phy[i]);
- }
+ dra7xx_pcie_disable_phy(dra7xx);
return ret;
}
@@ -434,13 +493,13 @@ err_phy:
static int dra7xx_pcie_suspend(struct device *dev)
{
struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
- struct pcie_port *pp = &dra7xx->pp;
+ struct dw_pcie *pci = dra7xx->pci;
u32 val;
/* clear MSE */
- val = dw_pcie_readl_rc(pp, PCI_COMMAND);
+ val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
val &= ~PCI_COMMAND_MEMORY;
- dw_pcie_writel_rc(pp, PCI_COMMAND, val);
+ dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
return 0;
}
@@ -448,13 +507,13 @@ static int dra7xx_pcie_suspend(struct device *dev)
static int dra7xx_pcie_resume(struct device *dev)
{
struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
- struct pcie_port *pp = &dra7xx->pp;
+ struct dw_pcie *pci = dra7xx->pci;
u32 val;
/* set MSE */
- val = dw_pcie_readl_rc(pp, PCI_COMMAND);
+ val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
val |= PCI_COMMAND_MEMORY;
- dw_pcie_writel_rc(pp, PCI_COMMAND, val);
+ dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
return 0;
}
@@ -462,12 +521,8 @@ static int dra7xx_pcie_resume(struct device *dev)
static int dra7xx_pcie_suspend_noirq(struct device *dev)
{
struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
- int count = dra7xx->phy_count;
- while (count--) {
- phy_power_off(dra7xx->phy[count]);
- phy_exit(dra7xx->phy[count]);
- }
+ dra7xx_pcie_disable_phy(dra7xx);
return 0;
}
@@ -475,31 +530,15 @@ static int dra7xx_pcie_suspend_noirq(struct device *dev)
static int dra7xx_pcie_resume_noirq(struct device *dev)
{
struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
- int phy_count = dra7xx->phy_count;
int ret;
- int i;
-
- for (i = 0; i < phy_count; i++) {
- ret = phy_init(dra7xx->phy[i]);
- if (ret < 0)
- goto err_phy;
- ret = phy_power_on(dra7xx->phy[i]);
- if (ret < 0) {
- phy_exit(dra7xx->phy[i]);
- goto err_phy;
- }
+ ret = dra7xx_pcie_enable_phy(dra7xx);
+ if (ret) {
+ dev_err(dev, "failed to enable phy\n");
+ return ret;
}
return 0;
-
-err_phy:
- while (--i >= 0) {
- phy_power_off(dra7xx->phy[i]);
- phy_exit(dra7xx->phy[i]);
- }
-
- return ret;
}
#endif
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c
index f1c544bb8b68..0295ec96f3d0 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/dwc/pci-exynos.c
@@ -26,10 +26,10 @@
#include "pcie-designware.h"
-#define to_exynos_pcie(x) container_of(x, struct exynos_pcie, pp)
+#define to_exynos_pcie(x) dev_get_drvdata((x)->dev)
struct exynos_pcie {
- struct pcie_port pp;
+ struct dw_pcie *pci;
void __iomem *elbi_base; /* DT 0th resource */
void __iomem *phy_base; /* DT 1st resource */
void __iomem *block_base; /* DT 2nd resource */
@@ -297,8 +297,8 @@ static void exynos_pcie_init_phy(struct exynos_pcie *exynos_pcie)
static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
{
- struct pcie_port *pp = &exynos_pcie->pp;
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = exynos_pcie->pci;
+ struct device *dev = pci->dev;
if (exynos_pcie->reset_gpio >= 0)
devm_gpio_request_one(dev, exynos_pcie->reset_gpio,
@@ -307,11 +307,12 @@ static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
{
- struct pcie_port *pp = &exynos_pcie->pp;
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = exynos_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = pci->dev;
u32 val;
- if (dw_pcie_link_up(pp)) {
+ if (dw_pcie_link_up(pci)) {
dev_err(dev, "Link already up\n");
return 0;
}
@@ -336,7 +337,7 @@ static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */
- if (!dw_pcie_wait_for_link(pp))
+ if (!dw_pcie_wait_for_link(pci))
return 0;
while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) {
@@ -376,14 +377,16 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
{
struct exynos_pcie *exynos_pcie = arg;
- struct pcie_port *pp = &exynos_pcie->pp;
+ struct dw_pcie *pci = exynos_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
return dw_handle_msi_irq(pp);
}
static void exynos_pcie_msi_init(struct exynos_pcie *exynos_pcie)
{
- struct pcie_port *pp = &exynos_pcie->pp;
+ struct dw_pcie *pci = exynos_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
u32 val;
dw_pcie_msi_init(pp);
@@ -402,34 +405,35 @@ static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie)
exynos_pcie_msi_init(exynos_pcie);
}
-static u32 exynos_pcie_readl_rc(struct pcie_port *pp, u32 reg)
+static u32 exynos_pcie_readl_dbi(struct dw_pcie *pci, u32 reg)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
u32 val;
exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true);
- val = readl(pp->dbi_base + reg);
+ val = readl(pci->dbi_base + reg);
exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false);
return val;
}
-static void exynos_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val)
+static void exynos_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true);
- writel(val, pp->dbi_base + reg);
+ writel(val, pci->dbi_base + reg);
exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false);
}
static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
u32 *val)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
int ret;
exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true);
- ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
+ ret = dw_pcie_read(pci->dbi_base + where, size, val);
exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false);
return ret;
}
@@ -437,18 +441,19 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
u32 val)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
int ret;
exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true);
- ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
+ ret = dw_pcie_write(pci->dbi_base + where, size, val);
exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false);
return ret;
}
-static int exynos_pcie_link_up(struct pcie_port *pp)
+static int exynos_pcie_link_up(struct dw_pcie *pci)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
u32 val;
val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_RDLH_LINKUP);
@@ -460,26 +465,25 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
static void exynos_pcie_host_init(struct pcie_port *pp)
{
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci);
exynos_pcie_establish_link(exynos_pcie);
exynos_pcie_enable_interrupts(exynos_pcie);
}
-static struct pcie_host_ops exynos_pcie_host_ops = {
- .readl_rc = exynos_pcie_readl_rc,
- .writel_rc = exynos_pcie_writel_rc,
+static struct dw_pcie_host_ops exynos_pcie_host_ops = {
.rd_own_conf = exynos_pcie_rd_own_conf,
.wr_own_conf = exynos_pcie_wr_own_conf,
- .link_up = exynos_pcie_link_up,
.host_init = exynos_pcie_host_init,
};
static int __init exynos_add_pcie_port(struct exynos_pcie *exynos_pcie,
struct platform_device *pdev)
{
- struct pcie_port *pp = &exynos_pcie->pp;
- struct device *dev = pp->dev;
+ struct dw_pcie *pci = exynos_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = &pdev->dev;
int ret;
pp->irq = platform_get_irq(pdev, 1);
@@ -523,11 +527,17 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *exynos_pcie,
return 0;
}
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .readl_dbi = exynos_pcie_readl_dbi,
+ .writel_dbi = exynos_pcie_writel_dbi,
+ .link_up = exynos_pcie_link_up,
+};
+
static int __init exynos_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct dw_pcie *pci;
struct exynos_pcie *exynos_pcie;
- struct pcie_port *pp;
struct device_node *np = dev->of_node;
struct resource *elbi_base;
struct resource *phy_base;
@@ -538,8 +548,12 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
if (!exynos_pcie)
return -ENOMEM;
- pp = &exynos_pcie->pp;
- pp->dev = dev;
+ pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+ if (!pci)
+ return -ENOMEM;
+
+ pci->dev = dev;
+ pci->ops = &dw_pcie_ops;
exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
@@ -583,11 +597,12 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
goto fail_bus_clk;
}
+ platform_set_drvdata(pdev, exynos_pcie);
+
ret = exynos_add_pcie_port(exynos_pcie, pdev);
if (ret < 0)
goto fail_bus_clk;
- platform_set_drvdata(pdev, exynos_pcie);
return 0;
fail_bus_clk:
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index c8cefb078218..70fa380ea077 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -30,7 +30,7 @@
#include "pcie-designware.h"
-#define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
+#define to_imx6_pcie(x) dev_get_drvdata((x)->dev)
enum imx6_pcie_variants {
IMX6Q,
@@ -39,7 +39,7 @@ enum imx6_pcie_variants {
};
struct imx6_pcie {
- struct pcie_port pp; /* pp.dbi_base is DT 0th resource */
+ struct dw_pcie *pci;
int reset_gpio;
bool gpio_active_high;
struct clk *pcie_bus;