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 | 348 ++++++++++++++++++++++++++++++++++++++++++ drivers/pci/host/pcie-axxia.c | 159 +++++++++++-------- drivers/pci/host/pcie-axxia.h | 1 + include/linux/axxia-pei.h | 1 + 4 files changed, 448 insertions(+), 61 deletions(-) diff --git a/drivers/misc/axxia-pei.c b/drivers/misc/axxia-pei.c index daf0381..bd0565f 100644 --- a/drivers/misc/axxia-pei.c +++ b/drivers/misc/axxia-pei.c @@ -148,6 +148,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 int control) +{ + return (0xf & (control >> 22)); +} + static u32 pei_readl(void *address) { @@ -1772,6 +1783,343 @@ 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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; + break; + } + + 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 7f8f355..10e4769 100644 --- a/drivers/pci/host/pcie-axxia.c +++ b/drivers/pci/host/pcie-axxia.c @@ -587,79 +587,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. - */ + 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); - 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; + /* 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; } @@ -1030,6 +1055,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 5a965d7..4ea4105 100644 --- a/drivers/pci/host/pcie-axxia.h +++ b/drivers/pci/host/pcie-axxia.h @@ -26,6 +26,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 9744945..e1f40a2 100644 --- a/include/linux/axxia-pei.h +++ b/include/linux/axxia-pei.h @@ -18,6 +18,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