From: John Jacques <john.jacq...@intel.com>

If the link does not come up, reduce the width and
try again.

Signed-off-by: John Jacques <john.jacq...@intel.com>
---
 drivers/misc/axxia-pei.c      | 340 ++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/host/pcie-axxia.c | 161 ++++++++++++--------
 drivers/pci/host/pcie-axxia.h |   1 +
 include/linux/axxia-pei.h     |   1 +
 4 files changed, 441 insertions(+), 62 deletions(-)

diff --git a/drivers/misc/axxia-pei.c b/drivers/misc/axxia-pei.c
index 2c0fabd..e9baf8b 100644
--- a/drivers/misc/axxia-pei.c
+++ b/drivers/misc/axxia-pei.c
@@ -150,6 +150,17 @@ static int pei_trace;
 module_param(pei_trace, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
 MODULE_PARM_DESC(pei_trace, "enable pei_trace");
 
+/*
+  
------------------------------------------------------------------------------
+  get_config
+*/
+
+static inline unsigned
+get_config(unsigned control)
+{
+       return (0xf & (control >> 22));
+}
+
 static u32
 pei_readl(void *address)
 {
@@ -1777,6 +1788,335 @@ int axxia_pei_is_control_set(void)
 }
 EXPORT_SYMBOL(axxia_pei_is_control_set);
 
+/*
+  
------------------------------------------------------------------------------
+  pei_reset_56xx
+*/
+
+static int
+pei_reset_56xx(enum PCIMode mode, unsigned int control)
+{
+       unsigned int ctrl0;
+
+       ncr_read32(NCP_REGION_ID(0x115, 0), 0, &ctrl0);
+
+       switch (get_config(control)) {
+       case 1:
+               /*
+                 PEI0x4  (HSS10-ch0,1; HSS11-ch0,1)
+                 PEI1x4  (HSS12-ch0,1; HSS13-ch0,1)
+               */
+
+               switch (mode) {
+               case PEI0:
+                       enable_reset(0);
+                       enable_reset(1);
+                       ctrl0 &= ~(1 << 0);
+                       break;
+               case PEI1:
+                       enable_reset(2);
+                       enable_reset(3);
+                       ctrl0 &= ~(1 << 1);
+                       break;
+               default:
+                       pr_err("Invalid PEI for mode %d!\n",
+                              get_config(control));
+                       return -1;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+
+               switch (mode) {
+               case PEI0:
+                       release_reset(0);
+                       release_reset(1);
+                       ctrl0 |= (1 << 0);
+                       break;
+               case PEI1:
+                       release_reset(2);
+                       release_reset(3);
+                       ctrl0 |= (1 << 1);
+                       break;
+               default:
+                       break;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       case 2:
+               /*
+                 PEI0x2  (HSS10-ch0,1)
+                 PEI2x2  (HSS11-ch0,1)
+                 PEI1x2  (HSS12-ch0,1)
+                 UNUSED  (HSS13-ch0,1)
+               */
+
+               /* Disable srio0 and srio1. */
+               ctrl0 &= ~((1 << 10) | (1 << 3));
+
+               switch (mode) {
+               case PEI0:
+                       enable_reset(0);
+                       ctrl0 &= ~(1 << 0);
+                       break;
+               case PEI1:
+                       enable_reset(2);
+                       ctrl0 &= ~(1 << 1);
+                       break;
+               case PEI2:
+                       enable_reset(1);
+                       ctrl0 &= ~(1 << 2);
+                       break;
+               default:
+                       pr_err("Invalid PEI for mode %d!\n",
+                              get_config(control));
+                       return -1;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+
+               switch (mode) {
+               case PEI0:
+                       release_reset(0);
+                       ctrl0 |= (1 << 0);
+                       break;
+               case PEI1:
+                       release_reset(2);
+                       ctrl0 |= (1 << 1);
+                       break;
+               case PEI2:
+                       release_reset(1);
+                       ctrl0 |= (1 << 2);
+                       break;
+               default:
+                       break;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       case 3:
+               /*
+                 PEI0x2  (HSS10-ch0,1)
+                 SRIO0x2 (HSS11-ch0,1)
+                 UNUSED  (HSS12-ch0,1)
+                 PEI2x2  (HSS13-ch0,1)
+                 INFO: Formerly case 6...
+               */
+
+               switch (mode) {
+               case PEI0:
+                       enable_reset(0);
+                       ctrl0 &= ~(1 << 0);
+                       break;
+               case PEI2:
+                       enable_reset(3);
+                       ctrl0 &= ~(1 << 2);
+                       break;
+               default:
+                       pr_err("Invalid PEI for mode %d!\n",
+                              get_config(control));
+                       return -1;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+
+               switch (mode) {
+               case PEI0:
+                       release_reset(0);
+                       ctrl0 |= (1 << 0);
+                       break;
+               case PEI2:
+                       release_reset(3);
+                       ctrl0 |= (1 << 2);
+                       break;
+               default:
+                       break;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       case 4:
+               /*
+                 SRIO1x2 (HSS10-ch0,1)
+                 SRIO0x2 (HSS11-ch0,1)
+                 UNUSED  (HSS12-ch0,1)
+                 PEI2x2  (HSS13-ch0,1)
+               */
+
+               switch (mode) {
+               case PEI2:
+                       enable_reset(3);
+                       ctrl0 &= ~(1 << 2);
+                       break;
+               default:
+                       pr_err("Invalid PEI for mode %d!\n",
+                              get_config(control));
+                       return -1;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+
+               switch (mode) {
+               case PEI2:
+                       release_reset(3);
+                       ctrl0 |= (1 << 2);
+                       break;
+               default:
+                       break;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+
+               /* Undocumented Configurations */
+
+       case 15:
+               /*
+                 UNUSED  (HSS10-ch0,1)
+                 SRIO0x2 (HSS11-ch0,1)
+                 PEI1x4  (HSS12-ch0,1; HSS13-ch0,1)
+               */
+
+               switch (mode) {
+               case PEI1:
+                       enable_reset(2);
+                       enable_reset(3);
+                       ctrl0 &= ~(1 << 1);
+                       break;
+               default:
+                       pr_err("Invalid PEI for mode %d!\n",
+                              get_config(control));
+                       return -1;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+
+               switch (mode) {
+               case PEI1:
+                       release_reset(2);
+                       release_reset(3);
+                       ctrl0 |= (1 << 1);
+                       break;
+               default:
+                       break;
+               }
+
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       default:
+               pr_err("Invalid Configuration: 0x%x\n", get_config(control));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  
------------------------------------------------------------------------------
+  pei_reset_67xx
+*/
+
+static int
+pei_reset_67xx(unsigned int control)
+{
+       unsigned int ctrl0;
+
+       ncr_read32(NCP_REGION_ID(0x115, 0), 0, &ctrl0);
+
+       switch (get_config(control)) {
+       case 1:
+               /*
+                 PEI0x2  (HSS15-ch0,1)
+               */
+
+               enable_reset(0);
+               ctrl0 &= ~(1 << 0);
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               release_reset(0);
+               ctrl0 |= (1 << 0);
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       case 2:
+               /*
+                 PEI0x1  (HSS15-ch0)
+               */
+
+               enable_reset(0);
+               ctrl0 &= ~(1 << 0);
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               release_reset(0);
+               ctrl0 |= (1 << 0);
+               ncr_write32(NCP_REGION_ID(0x115, 0), 0, ctrl0);
+               break;
+       default:
+               pr_err("Invalid Configuration: 0x%x\n", get_config(control));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  
------------------------------------------------------------------------------
+  axxia_pei_reset
+
+  Assumes that pei_init() has been run.
+
+  Only resets PCI ports.
+*/
+
+int
+axxia_pei_reset(unsigned int pei)
+{
+       unsigned int control;
+       enum PCIMode mode;
+       unsigned int ctrl0;
+
+       if (0 == axxia_pei_is_control_set()) {
+               pr_err("Control is Not Set\n");
+               return -1;
+       }
+
+       control = axxia_pei_get_control();
+
+       if (is_5500) {
+               pr_err("Invalid Target\n");
+               return -1;
+       }
+
+       if (is_6700 && 0 != pei) {
+               pr_err("Invalid PEI: %d\n", pei);
+               return -1;
+       }
+
+       switch (pei) {
+       case 0:
+               mode = PEI0;
+               break;
+       case 1:
+               mode = PEI1;
+               break;
+       case 2:
+               mode = PEI2;
+               break;
+       default:
+               pr_err("Invalid PEI: %d\n", pei);
+               return -1;
+       }
+
+       disable_ltssm(mode);
+       ncr_read32(NCP_REGION_ID(0x115, 0), 0, &ctrl0);
+
+       if (is_5600)
+               return pei_reset_56xx(mode, control);
+       else if (is_6700)
+               return pei_reset_67xx(control);
+
+       pr_err("Invalid Target\n");
+
+       return -1;
+}
+EXPORT_SYMBOL(axxia_pei_reset);
 
 /*
   
------------------------------------------------------------------------------
diff --git a/drivers/pci/host/pcie-axxia.c b/drivers/pci/host/pcie-axxia.c
index 3b7bc19..e7394c4 100644
--- a/drivers/pci/host/pcie-axxia.c
+++ b/drivers/pci/host/pcie-axxia.c
@@ -609,79 +609,104 @@ void axxia_pcie_setup_rc(struct pcie_port *pp)
        u32 membase;
        u32 memlimit;
 
-       /*
-         To work around a hardware problem, set
-         PCIE_LINK_WIDTH_SPEED_CONTROL to 1 lane in all cases.
-       */
-
-       axxia_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
-       val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-       val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
-       axxia_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
-
-       /* Set the number of lanes based on the device tree. */
-       axxia_pcie_rd_own_conf(pp, PCIE_PORT_LINK_CONTROL, 4, &val);
-       val &= ~PORT_LINK_MODE_MASK;
-
-       switch (pp->lanes) {
-       case 1:
-               val |= PORT_LINK_MODE_1_LANES;
-               break;
-       case 2:
-               val |= PORT_LINK_MODE_2_LANES;
-               break;
-       case 4:
-               val |= PORT_LINK_MODE_4_LANES;
-               break;
-       case 8:
-               val |= PORT_LINK_MODE_8_LANES;
-               break;
-       default:
-               break;
+       if (1 > pp->lanes)
+               return;
+
+       if (-1 == pp->pei_nr)
+               return;
+
+       for (;;) {
+               /*
+                 To work around a hardware problem, set
+                 PCIE_LINK_WIDTH_SPEED_CONTROL to 1 lane in all cases.
+               */
+
+               axxia_pcie_rd_own_conf(pp,
+                                      PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
+               val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+               val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+               axxia_pcie_wr_own_conf(pp,
+                                      PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+
+               /* Set the number of lanes based on the device tree. */
+               axxia_pcie_rd_own_conf(pp, PCIE_PORT_LINK_CONTROL, 4, &val);
+               val &= ~PORT_LINK_MODE_MASK;
+
+               switch (pp->lanes) {
+               case 1:
+                       val |= PORT_LINK_MODE_1_LANES;
+                       break;
+               case 2:
+                       val |= PORT_LINK_MODE_2_LANES;
+                       break;
+               case 4:
+                       val |= PORT_LINK_MODE_4_LANES;
+                       break;
+               case 8:
+                       val |= PORT_LINK_MODE_8_LANES;
+                       break;
+               default:
+                       break;
+               }
+               axxia_pcie_wr_own_conf(pp, PCIE_PORT_LINK_CONTROL, 4, val);
+
+               /* Add Mikes tweak for GEN3_EQ_CONTROL */
+               axxia_pcie_writel_rc(pp, 0x1017201, PCIE_GEN3_EQ_CONTROL_OFF);
+
+               /* setup bus numbers */
+               axxia_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
+               val &= 0xff000000;
+               val |= 0x00010100;
+               axxia_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
+
+               /* setup memory base, memory limit */
+               membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
+               memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
+               val = memlimit | membase;
+               axxia_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
+
+               /* setup command register */
+               axxia_pcie_readl_rc(pp, PCI_COMMAND, &val);
+               val &= 0xffff0000;
+               val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+               axxia_pcie_writel_rc(pp, val, PCI_COMMAND);
+
+               /* LTSSM enable */
+               axxia_cc_gpreg_readl(pp, PEI_GENERAL_CORE_CTL_REG, &val);
+               msleep(100);
+               val |= 0x1;
+               axxia_cc_gpreg_writel(pp, val, PEI_GENERAL_CORE_CTL_REG);
+               msleep(100);
+
+               if (axxia_pcie_link_up(pp))
+                       break;
+
+               if (1 >= pp->lanes)
+                       break;
+
+               pp->lanes >>= 1;
+               axxia_pei_reset(pp->pei_nr);
+               mdelay(100);
        }
-       axxia_pcie_wr_own_conf(pp, PCIE_PORT_LINK_CONTROL, 4, val);
-
-       /* Add Mikes tweak for GEN3_EQ_CONTROL */
-       axxia_pcie_writel_rc(pp, 0x1017201, PCIE_GEN3_EQ_CONTROL_OFF);
-
-       /* setup bus numbers */
-       axxia_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
-       val &= 0xff000000;
-       val |= 0x00010100;
-       axxia_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
-
-       /* setup memory base, memory limit */
-       membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
-       memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
-       val = memlimit | membase;
-       axxia_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
-
-       /* setup command register */
-       axxia_pcie_readl_rc(pp, PCI_COMMAND, &val);
-       val &= 0xffff0000;
-       val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-               PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-       axxia_pcie_writel_rc(pp, val, PCI_COMMAND);
-
-       /* LTSSM enable */
-       axxia_cc_gpreg_readl(pp, PEI_GENERAL_CORE_CTL_REG, &val);
-       msleep(100);
-       val |= 0x1;
-       axxia_cc_gpreg_writel(pp, val, PEI_GENERAL_CORE_CTL_REG);
-       msleep(100);
 }
 
 
 static int axxia_pcie_establish_link(struct pcie_port *pp)
 {
+       u32 value;
+
        /* setup root complex */
        axxia_pcie_setup_rc(pp);
 
-       if (axxia_pcie_link_up(pp))
-               dev_info(pp->dev, "Link up\n");
-       else
+       if (!axxia_pcie_link_up(pp))
                return 1;
 
+       axxia_pcie_readl_rc(pp, 0x80, &value);
+       dev_info(pp->dev, "PEI%d Link Up: Gen%d x%d\n", pp->pei_nr,
+                (((value & 0xf0000) >> 16) & 0xff),
+                (((value & 0x3f00000) >> 20) & 0xff));
+
        return 0;
 }
 
@@ -1131,6 +1156,18 @@ static int axxia_pcie_probe(struct platform_device *pdev)
        pp->dev = &pdev->dev;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+
+       if (0xa002000000 == res->start) {
+               pp->pei_nr = 0;
+       } else if (0xa004000000 == res->start) {
+               pp->pei_nr = 1;
+       } else if (0xa006000000 == res->start) {
+               pp->pei_nr = 2;
+       } else {
+               pr_warn("Unknown PEI!\n");
+               pp->pei_nr = -1;
+       }
+
        pp->dbi_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(pp->dbi_base))
                return PTR_ERR(pp->dbi_base);
diff --git a/drivers/pci/host/pcie-axxia.h b/drivers/pci/host/pcie-axxia.h
index bf2d62f..2fa15f6 100644
--- a/drivers/pci/host/pcie-axxia.h
+++ b/drivers/pci/host/pcie-axxia.h
@@ -29,6 +29,7 @@
 struct pcie_port {
        struct device           *dev;
        u8                      root_bus_nr;
+       s8                      pei_nr;
        void __iomem            *dbi_base;
        void __iomem            *cc_gpreg_base;
        void __iomem            *axi_gpreg_base;
diff --git a/include/linux/axxia-pei.h b/include/linux/axxia-pei.h
index 9ef3426..6ead0d1 100644
--- a/include/linux/axxia-pei.h
+++ b/include/linux/axxia-pei.h
@@ -19,6 +19,7 @@
 #ifndef __AXXIA_PEI_H
 #define __AXXIA_PEI_H
 
+int axxia_pei_reset(unsigned int);
 int axxia_pei_setup(unsigned int, unsigned int);
 int axxia_pcie_reset(void);
 
-- 
2.7.4

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to