summaryrefslogtreecommitdiff
path: root/drivers/pci/host/pci-imx6.c
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2016-12-27 10:15:50 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit26b07a372178bd97026224338630080eb15efc8e (patch)
tree89f6f24d196803fa6c35cc341188a1831b9f9cd4 /drivers/pci/host/pci-imx6.c
parent6b8b92208f55d90572e87ebc2ca49ba28d2c8bef (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.c32
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))