ENGR00325255 pcie:enable pcie support on imx6sx sd
authorYe Li <ye.li@nxp.com>
Fri, 11 Mar 2016 09:28:00 +0000 (17:28 +0800)
committerYe Li <ye.li@nxp.com>
Wed, 28 Apr 2021 20:49:34 +0000 (13:49 -0700)
Enable pcie support in uboot on imx6sx sd boards
- enable_pcie_clock should be call before ssp_en is set,
  since that ssp_en control the phy_ref clk gate, turn on
  it after the source of the pcie clks are stable.
- add debug info
- add rx_eq of gpr12 on imx6sx
- there are random link down issue on imx6sx. It's
  pcie ep reset issue.
  solution:reset ep, then retry link can fix it.

(cherry picked from commit ec78595a24b5ff1020baa97b6d6e79a3a3326307)
Signed-off-by: Richard Zhu <r65037@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 81fd30250110d72992758f08b66c07306126892b)
(cherry picked from commit 4226ce46f24e176dcfc20aea1af0713b4b425655)
(cherry picked from commit 3e1a0a7f37d749d5e36e27ad46e8c8db12a865be)
(cherry picked from commit fa4b46f0f55a19c3cab762e2fdbb01e359c9040b)

arch/arm/include/asm/mach-imx/sys_proto.h
arch/arm/mach-imx/mx6/clock.c
arch/arm/mach-imx/mx6/soc.c
drivers/pci/pcie_imx.c

index 43eae6d..2e1b191 100644 (file)
@@ -209,6 +209,9 @@ int mxs_reset_block(struct mxs_register_32 *reg);
 int mxs_wait_mask_set(struct mxs_register_32 *reg, u32 mask, u32 timeout);
 int mxs_wait_mask_clr(struct mxs_register_32 *reg, u32 mask, u32 timeout);
 
+void pcie_power_up(void);
+void pcie_power_off(void);
+
 unsigned long call_imx_sip(unsigned long id, unsigned long reg0,
                           unsigned long reg1, unsigned long reg2,
                           unsigned long reg3);
index cb9d629..5735afd 100644 (file)
@@ -1096,6 +1096,15 @@ void disable_sata_clock(void)
 #endif
 
 #ifdef CONFIG_PCIE_IMX
+static void ungate_disp_axi_clock(void)
+{
+       struct mxc_ccm_reg *const imx_ccm =
+               (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
+       /* Enable display axi clock. */
+       setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_DISP_AXI_MASK);
+}
+
 static void ungate_pcie_clock(void)
 {
        struct mxc_ccm_reg *const imx_ccm =
@@ -1143,14 +1152,22 @@ int enable_pcie_clock(void)
        /* PCIe reference clock sourced from AXI. */
        clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL);
 
+       if (!is_mx6sx()) {
        /* Party time! Ungate the clock to the PCIe. */
 #ifdef CONFIG_SATA
-       ungate_sata_clock();
+               ungate_sata_clock();
 #endif
-       ungate_pcie_clock();
+               ungate_pcie_clock();
 
-       return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA |
-                              BM_ANADIG_PLL_ENET_ENABLE_PCIE);
+               return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA |
+                                      BM_ANADIG_PLL_ENET_ENABLE_PCIE);
+       } else {
+               /* Party time! Ungate the clock to the PCIe. */
+               ungate_disp_axi_clock();
+               ungate_pcie_clock();
+
+               return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_PCIE);
+       }
 }
 #endif
 
index ce4f4a3..47f75ad 100644 (file)
@@ -409,6 +409,19 @@ static void noc_setup(void)
 }
 #endif
 
+#ifdef CONFIG_MX6SX
+
+void pcie_power_up(void)
+{
+       set_ldo_voltage(LDO_PU, 1100);  /* Set VDDPU to 1.1V */
+}
+
+void pcie_power_off(void)
+{
+       set_ldo_voltage(LDO_PU, 0);     /* Set VDDPU to 1.1V */
+}
+#endif
+
 static void imx_set_vddpu_power_down(void)
 {
        struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
index d9c2325..edd3dcb 100644 (file)
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2013 Marek Vasut <marex@denx.de>
  *
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ *
  * Based on upstream Linux kernel driver:
  * pci-imx6.c:         Sean Cross <xobs@kosagi.com>
  * pcie-designware.c:  Jingoo Han <jg1.han@samsung.com>
@@ -102,6 +104,43 @@ struct imx_pcie_priv {
        void __iomem            *cfg_base;
 };
 
+#ifdef DEBUG
+
+#ifdef DEBUG_STRESS_WR /* warm-reset stress tests */
+#define SNVS_LPGRP 0x020cc068
+#endif
+
+#define DBGF(x...) printf(x)
+
+static void print_regs(int contain_pcie_reg)
+{
+       u32 val;
+       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+       struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+       val = readl(&iomuxc_regs->gpr[1]);
+       DBGF("GPR01 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[1], val);
+       val = readl(&iomuxc_regs->gpr[5]);
+       DBGF("GPR05 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[5], val);
+       val = readl(&iomuxc_regs->gpr[8]);
+       DBGF("GPR08 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[8], val);
+       val = readl(&iomuxc_regs->gpr[12]);
+       DBGF("GPR12 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[12], val);
+       val = readl(&ccm_regs->analog_pll_enet);
+       DBGF("PLL06 a:0x%08x v:0x%08x\n", (u32)&ccm_regs->analog_pll_enet, val);
+       val = readl(&ccm_regs->ana_misc1);
+       DBGF("MISC1 a:0x%08x v:0x%08x\n", (u32)&ccm_regs->ana_misc1, val);
+       if (contain_pcie_reg) {
+               val = readl(MX6_DBI_ADDR + 0x728);
+               DBGF("dbr0 offset 0x728 %08x\n", val);
+               val = readl(MX6_DBI_ADDR + 0x72c);
+               DBGF("dbr1 offset 0x72c %08x\n", val);
+       }
+}
+#else
+#define DBGF(x...)
+static void print_regs(int contain_pcie_reg) {}
+#endif
+
 /*
  * PHY access functions
  */
@@ -397,7 +436,7 @@ static int imx_pcie_read_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
        ret = imx_pcie_addr_valid(d);
        if (ret) {
                *val = 0xffffffff;
-               return 0;
+               return ret;
        }
 
        va_address = get_bus_address(priv, d, where);
@@ -461,6 +500,7 @@ static int imx6_pcie_assert_core_reset(struct imx_pcie_priv *priv,
        setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
        /* Power up PCIe PHY */
        setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
+       pcie_power_up();
 #else
        /*
         * If the bootloader already enabled the link we need some special
@@ -503,7 +543,9 @@ static int imx6_pcie_init_phy(void)
 {
        struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
 
+#ifndef DEBUG
        clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+#endif
 
        clrsetbits_le32(&iomuxc_regs->gpr[12],
                        IOMUXC_GPR12_DEVICE_TYPE_MASK,
@@ -657,6 +699,22 @@ static int imx_pcie_link_up(struct imx_pcie_priv *priv)
        while (!imx6_pcie_link_up(priv)) {
                udelay(10);
                count++;
+               if (count == 1000) {
+                       print_regs(1);
+                       /* link down, try reset ep, and re-try link here */
+                       DBGF("pcie link is down, reset ep, then retry!\n");
+                       imx6_pcie_toggle_reset();
+                       continue;
+               }
+#ifdef DEBUG
+               else if (count >= 2000) {
+                       print_regs(1);
+                       /* link is down, stop here */
+                       setenv("bootcmd", "sleep 2;");
+                       DBGF("pcie link is down, stop here!\n");
+                       return -EINVAL;
+               }
+#endif
                if (count >= 4000) {
 #ifdef CONFIG_PCI_SCAN_SHOW
                        puts("PCI:   pcie phy link never came up\n");
@@ -701,6 +759,10 @@ void imx_pcie_init(void)
        static struct pci_controller    pcc;
        struct pci_controller           *hose = &pcc;
        int ret;
+#ifdef DEBUG_STRESS_WR
+       u32 dbg_reg_addr = SNVS_LPGRP;
+       u32 dbg_reg = readl(dbg_reg_addr) + 1;
+#endif
 
        memset(&pcc, 0, sizeof(pcc));
 
@@ -737,7 +799,15 @@ void imx_pcie_init(void)
        if (!ret) {
                pci_register_hose(hose);
                hose->last_busno = pci_hose_scan(hose);
+#ifdef DEBUG_STRESS_WR
+               dbg_reg += 1<<16;
+#endif
        }
+#ifdef DEBUG_STRESS_WR
+       writel(dbg_reg, dbg_reg_addr);
+       DBGF("PCIe Successes/Attempts: %d/%d\n",
+                       dbg_reg >> 16, dbg_reg & 0xffff);
+#endif
 }
 
 void imx_pcie_remove(void)