diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-02-21 15:12:18 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-02-21 15:12:18 -0600 |
commit | 3bb0356bb1b5a2c4434b4a3267df6dd9927ca5bf (patch) | |
tree | a601387ad9c6a3fd66125e4506b560530280ccbd /drivers | |
parent | 4c2ae32d4c6ccd63819f36702f8455a5b08eaca8 (diff) | |
parent | 7a2b3f024b8b724257d82f76690e68c69d797efd (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/Makefile | 3 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/dwc/Kconfig | 132 | ||||
-rw-r--r-- | drivers/pci/dwc/Makefile | 24 | ||||
-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.c | 233 | ||||
-rw-r--r-- | drivers/pci/dwc/pcie-designware.h | 198 | ||||
-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/Kconfig | 113 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 12 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.h | 86 |
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, ®); + 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, ®); + 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; |