]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branches 'pci/host-dra7xx' and 'pci/host-iproc' into next
authorBjorn Helgaas <bhelgaas@google.com>
Fri, 14 Aug 2015 13:21:16 +0000 (08:21 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 14 Aug 2015 13:21:16 +0000 (08:21 -0500)
* pci/host-dra7xx:
  ARM: dts: am57xx-evm: Add 'gpios' property with gpio2_8
  PCI: dra7xx: Add support to make GPIO drive PERST# line
  PCI: dra7xx: Clear MSE bit during suspend so clocks will idle
  PCI: dra7xx: Add PM support
  PCI: dra7xx: Disable pm_runtime on get_sync failure

* pci/host-iproc:
  PCI: iproc: Allow BCMA bus driver to be built as module
  PCI: iproc: Add arm64 support
  PCI: iproc: Delete unnecessary checks before phy calls

Documentation/devicetree/bindings/pci/ti-pci.txt
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/dra7.dtsi
drivers/pci/host/Kconfig
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-iproc.h

index 3d217911b3133ef35e762e6abc45e1180b7656e0..60e25161f35181bfd026b48519f43666d33f091e 100644 (file)
@@ -23,6 +23,9 @@ PCIe Designware Controller
    interrupt-map-mask,
    interrupt-map : as specified in ../designware-pcie.txt
 
+Optional Property:
+ - gpios : Should be added if a gpio line is required to drive PERST# line
+
 Example:
 axi {
        compatible = "simple-bus";
index a63bf78191ea5a57093e97f1d1fc95d904695816..f9a4b317ed2fc4d6c40fcd13d6422ecb6787fb74 100644 (file)
                };
        };
 };
+
+&pcie1 {
+       gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+};
index 8f1e25bcecbd76273f62671e8b9afa8f193ea261..37202b41351b3bb930ba167eef259b7e51989233 100644 (file)
                        #address-cells = <1>;
                        ranges = <0x51000000 0x51000000 0x3000
                                  0x0        0x20000000 0x10000000>;
-                       pcie@51000000 {
+                       pcie1: pcie@51000000 {
                                compatible = "ti,dra7-pcie";
                                reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>;
                                reg-names = "rc_dbics", "ti_conf", "config";
index c132bddc03f380a96a3c0acb5691a44df8fd2fa7..e339a8c42f7694692d7c1c0e3cab7dcbab0e799b 100644 (file)
@@ -135,7 +135,7 @@ config PCIE_IPROC_PLATFORM
          through the generic platform bus interface
 
 config PCIE_IPROC_BCMA
-       bool "Broadcom iProc PCIe BCMA bus driver"
+       tristate "Broadcom iProc PCIe BCMA bus driver"
        depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST)
        select PCIE_IPROC
        select BCMA
index 1a0d124b199aa3f8198f19a0408cbe0438a2dd21..52e2da7b3cd7b6dd09e98710a9794938bd5a1751 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_gpio.h>
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
@@ -83,6 +84,17 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
        writel(value, pcie->base + offset);
 }
 
+static inline u32 dra7xx_pcie_readl_rc(struct pcie_port *pp, u32 offset)
+{
+       return readl(pp->dbi_base + offset);
+}
+
+static inline void dra7xx_pcie_writel_rc(struct pcie_port *pp, u32 offset,
+                                        u32 value)
+{
+       writel(value, pp->dbi_base + offset);
+}
+
 static int dra7xx_pcie_link_up(struct pcie_port *pp)
 {
        struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
@@ -324,6 +336,9 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
        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;
 
        dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
        if (!dra7xx)
@@ -383,7 +398,23 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
        ret = pm_runtime_get_sync(dev);
        if (IS_ERR_VALUE(ret)) {
                dev_err(dev, "pm_runtime_get_sync failed\n");
-               goto err_phy;
+               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(&pdev->dev, "gpio%d request failed, ret %d\n",
+                               gpio_sel, ret);
+                       goto err_gpio;
+               }
+       } else if (gpio_sel == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto err_gpio;
        }
 
        reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
@@ -394,12 +425,14 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 
        ret = dra7xx_add_pcie_port(dra7xx, pdev);
        if (ret < 0)
-               goto err_add_port;
+               goto err_gpio;
 
        return 0;
 
-err_add_port:
+err_gpio:
        pm_runtime_put(dev);
+
+err_get_sync:
        pm_runtime_disable(dev);
 
 err_phy:
@@ -430,6 +463,85 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int dra7xx_pcie_suspend(struct device *dev)
+{
+       struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
+       struct pcie_port *pp = &dra7xx->pp;
+       u32 val;
+
+       /* clear MSE */
+       val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND);
+       val &= ~PCI_COMMAND_MEMORY;
+       dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val);
+
+       return 0;
+}
+
+static int dra7xx_pcie_resume(struct device *dev)
+{
+       struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
+       struct pcie_port *pp = &dra7xx->pp;
+       u32 val;
+
+       /* set MSE */
+       val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND);
+       val |= PCI_COMMAND_MEMORY;
+       dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val);
+
+       return 0;
+}
+
+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]);
+       }
+
+       return 0;
+}
+
+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;
+               }
+       }
+
+       return 0;
+
+err_phy:
+       while (--i >= 0) {
+               phy_power_off(dra7xx->phy[i]);
+               phy_exit(dra7xx->phy[i]);
+       }
+
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops dra7xx_pcie_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend, dra7xx_pcie_resume)
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend_noirq,
+                                     dra7xx_pcie_resume_noirq)
+};
+
 static const struct of_device_id of_dra7xx_pcie_match[] = {
        { .compatible = "ti,dra7-pcie", },
        {},
@@ -441,6 +553,7 @@ static struct platform_driver dra7xx_pcie_driver = {
        .driver = {
                .name   = "dra7-pcie",
                .of_match_table = of_dra7xx_pcie_match,
+               .pm     = &dra7xx_pcie_pm_ops,
        },
 };
 
index d77481ea553e08de04527f885df842e3dc2f8d84..fe2efb141a9bd3b74c22af5764ead81dcfc2ce6d 100644 (file)
 #define SYS_RC_INTX_EN               0x330
 #define SYS_RC_INTX_MASK             0xf
 
-static inline struct iproc_pcie *sys_to_pcie(struct pci_sys_data *sys)
+static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
 {
-       return sys->private_data;
+       struct iproc_pcie *pcie;
+#ifdef CONFIG_ARM
+       struct pci_sys_data *sys = bus->sysdata;
+
+       pcie = sys->private_data;
+#else
+       pcie = bus->sysdata;
+#endif
+       return pcie;
 }
 
 /**
@@ -71,8 +79,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus,
                                            unsigned int devfn,
                                            int where)
 {
-       struct pci_sys_data *sys = bus->sysdata;
-       struct iproc_pcie *pcie = sys_to_pcie(sys);
+       struct iproc_pcie *pcie = iproc_data(bus);
        unsigned slot = PCI_SLOT(devfn);
        unsigned fn = PCI_FUNC(devfn);
        unsigned busno = bus->number;
@@ -186,32 +193,34 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie)
 int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 {
        int ret;
+       void *sysdata;
        struct pci_bus *bus;
 
        if (!pcie || !pcie->dev || !pcie->base)
                return -EINVAL;
 
-       if (pcie->phy) {
-               ret = phy_init(pcie->phy);
-               if (ret) {
-                       dev_err(pcie->dev, "unable to initialize PCIe PHY\n");
-                       return ret;
-               }
-
-               ret = phy_power_on(pcie->phy);
-               if (ret) {
-                       dev_err(pcie->dev, "unable to power on PCIe PHY\n");
-                       goto err_exit_phy;
-               }
+       ret = phy_init(pcie->phy);
+       if (ret) {
+               dev_err(pcie->dev, "unable to initialize PCIe PHY\n");
+               return ret;
+       }
 
+       ret = phy_power_on(pcie->phy);
+       if (ret) {
+               dev_err(pcie->dev, "unable to power on PCIe PHY\n");
+               goto err_exit_phy;
        }
 
        iproc_pcie_reset(pcie);
 
+#ifdef CONFIG_ARM
        pcie->sysdata.private_data = pcie;
+       sysdata = &pcie->sysdata;
+#else
+       sysdata = pcie;
+#endif
 
-       bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops,
-                                 &pcie->sysdata, res);
+       bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, sysdata, res);
        if (!bus) {
                dev_err(pcie->dev, "unable to create PCI root bus\n");
                ret = -ENOMEM;
@@ -229,7 +238,9 @@ 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;
@@ -239,12 +250,9 @@ err_rm_root_bus:
        pci_remove_root_bus(bus);
 
 err_power_off_phy:
-       if (pcie->phy)
-               phy_power_off(pcie->phy);
+       phy_power_off(pcie->phy);
 err_exit_phy:
-       if (pcie->phy)
-               phy_exit(pcie->phy);
-
+       phy_exit(pcie->phy);
        return ret;
 }
 EXPORT_SYMBOL(iproc_pcie_setup);
@@ -254,10 +262,8 @@ int iproc_pcie_remove(struct iproc_pcie *pcie)
        pci_stop_root_bus(pcie->root_bus);
        pci_remove_root_bus(pcie->root_bus);
 
-       if (pcie->phy) {
-               phy_power_off(pcie->phy);
-               phy_exit(pcie->phy);
-       }
+       phy_power_off(pcie->phy);
+       phy_exit(pcie->phy);
 
        return 0;
 }
index ba0a108309ccf584446947120be074fed83883ba..c9e4c10a462e80897eafec3fbbf3ba119c2307e3 100644 (file)
@@ -21,7 +21,7 @@
  * @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
+ * @sysdata: Per PCI controller data (ARM-specific)
  * @root_bus: pointer to root bus
  * @phy: optional PHY device that controls the Serdes
  * @irqs: interrupt IDs
@@ -29,7 +29,9 @@
 struct iproc_pcie {
        struct device *dev;
        void __iomem *base;
+#ifdef CONFIG_ARM
        struct pci_sys_data sysdata;
+#endif
        struct pci_bus *root_bus;
        struct phy *phy;
        int irqs[IPROC_PCIE_MAX_NUM_IRQS];