MLK-13679-2 PCI: imx: workaround of ERR010728 for pcie on imx7d
authorRichard Zhu <hongxing.zhu@nxp.com>
Tue, 27 Dec 2016 02:15:50 +0000 (10:15 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:58:20 +0000 (14:58 -0500)
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>
drivers/pci/host/pci-imx6.c

index 9cb7ba1..8bb8bc2 100644 (file)
@@ -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))