diff options
author | Richard Zhu <hongxing.zhu@nxp.com> | 2016-12-27 10:15:50 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | 26b07a372178bd97026224338630080eb15efc8e (patch) | |
tree | 89f6f24d196803fa6c35cc341188a1831b9f9cd4 /drivers/pci/host/pci-imx6.c | |
parent | 6b8b92208f55d90572e87ebc2ca49ba28d2c8bef (diff) |
MLK-13679-2 PCI: imx: workaround of ERR010728 for pcie on imx7d
Description: Initial VCO oscillation may fail under
corner conditions such as cold temperature. It causes
PCIe PLL fail to lock in initialization phase.
Project Impact: iMX7 PCIe PLL fails to lock and iMX7D
PCIe doesn't work.
Workarounds: To toggle internal PLL_PD signal to make
VCO oscillate after G_RST signal is de-asserted by
following the sequences:
- De-asserted G_RST signal
- Toggle internal PLL_PD signal:
- Write "0x04" to the address "0x306D_0054"
- Write "0xA4" to the address "0x306D_0054"
- Write "0x04" to the address "0x306D_0054"
- De-asserted CMN_RST signal
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci/host/pci-imx6.c')
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 9cb7ba1f5407..8bb8bc24503e 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -76,6 +76,7 @@ struct imx6_pcie { u32 tx_swing_low; int link_gen; struct regmap *reg_src; + void __iomem *phy_base; struct regulator *pcie_phy_regulator; struct regulator *pcie_bus_regulator; }; @@ -138,6 +139,12 @@ struct imx6_pcie { * FIELD: ref_clkdiv2 [0:0] */ +/* iMX7 PCIe PHY registers */ +#define PCIE_PHY_CMN_REG15 0x54 +#define PCIE_PHY_CMN_REG15_DLY_4 (1 << 2) +#define PCIE_PHY_CMN_REG15_PLL_PD (1 << 5) +#define PCIE_PHY_CMN_REG15_OVRD_PLL_PD (1 << 7) + static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) { struct pcie_port *pp = &imx6_pcie->pp; @@ -509,6 +516,21 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) udelay(10); regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(6), 0); regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(1), 0); + + /* Add the workaround for ERR010728 */ + if (unlikely(imx6_pcie->phy_base == NULL)) { + pr_err("phy base shouldn't be null.\n"); + } else { + writel(PCIE_PHY_CMN_REG15_DLY_4, + imx6_pcie->phy_base + PCIE_PHY_CMN_REG15); + writel(PCIE_PHY_CMN_REG15_DLY_4 + | PCIE_PHY_CMN_REG15_PLL_PD + | PCIE_PHY_CMN_REG15_OVRD_PLL_PD, + imx6_pcie->phy_base + PCIE_PHY_CMN_REG15); + writel(PCIE_PHY_CMN_REG15_DLY_4, + imx6_pcie->phy_base + PCIE_PHY_CMN_REG15); + } + regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(2), 0); /* wait for phy pll lock firstly. */ @@ -1153,6 +1175,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct imx6_pcie *imx6_pcie; struct pcie_port *pp; + struct device_node *np; struct resource *dbi_base; struct device_node *node = dev->of_node; int ret; @@ -1178,6 +1201,15 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx-pcie-phy"); + if (np != NULL) { + imx6_pcie->phy_base = of_iomap(np, 0); + WARN_ON(!imx6_pcie->phy_base); + } else { + imx6_pcie->phy_base = NULL; + } + dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); pp->dbi_base = devm_ioremap_resource(dev, dbi_base); if (IS_ERR(pp->dbi_base)) |