PCI: dra7xx: Add support to force RC to work in GEN1 mode
authorKishon Vijay Abraham I <kishon@ti.com>
Wed, 11 Jan 2017 12:06:53 +0000 (17:36 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 21 Feb 2017 21:00:11 +0000 (15:00 -0600)
PCIe in AM57x/DRA7x devices is by default configured to work in GEN2 mode.
However there may be situations when working in GEN1 mode is desired.  One
example is limitation i925 (PCIe GEN2 mode not supported at junction
temperatures < 0C).

Add support to force Root Complex to work in GEN1 mode if so desired, but
don't force GEN1 mode on any board just yet.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/dwc/pci-dra7xx.c

index f6d0c630f7d6bcb05039ffe7d719046a1fce5f42..587b18c38bccb6abba4e02c8ad1caa976258fa0a 100644 (file)
@@ -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>
 #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;
        void __iomem            *base;          /* DT ti_conf */
        int                     phy_count;      /* DT phy-names count */
        struct phy              **phy;
+       int                     link_gen;
 };
 
 #define to_dra7xx_pcie(x)      container_of((x), struct dra7xx_pcie, pp)
@@ -96,12 +100,33 @@ static int dra7xx_pcie_establish_link(struct dra7xx_pcie *dra7xx)
        struct pcie_port *pp = &dra7xx->pp;
        struct device *dev = pp->dev;
        u32 reg;
+       u32 exp_cap_off = EXP_CAP_ID_OFFSET;
 
        if (dw_pcie_link_up(pp)) {
                dev_err(dev, "link is already up\n");
                return 0;
        }
 
+       if (dra7xx->link_gen == 1) {
+               dw_pcie_cfg_read(pp->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_cfg_write(pp->dbi_base + exp_cap_off +
+                                         PCI_EXP_LNKCAP, 4, reg);
+               }
+
+               dw_pcie_cfg_read(pp->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_cfg_write(pp->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);
@@ -397,6 +422,10 @@ 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;