drivers: pci: imx: add imx_pcie_remove function
authorTim Harvey <tharvey@gateworks.com>
Fri, 12 May 2017 19:58:41 +0000 (12:58 -0700)
committerStefano Babic <sbabic@denx.de>
Wed, 31 May 2017 08:09:03 +0000 (10:09 +0200)
There is no dedicated reset signal wired up for the MX6QDL thus if the
bootloader enables the link we need some special handling to get the core
back into a state where it is safe to touch it for configuration.

While there has been some special handling in the Linux kernel to do this,
it was removed in 4.11 thus we need to do it properly in the bootloader
and therefore without this if you enable PCI in the bootloader you will hang
while booting the 4.11 kernel.

This puts the PCIe controller back into a safe state for the kernel driver
before launching the kernel.

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Tested-by: Peter Senna Tschudin <peter.senna@collabora.com>
arch/arm/imx-common/cpu.c
drivers/pci/pcie_imx.c
include/pci.h

index 40fe813d290b45e08805a19bf0c9dc3b7b35d35d..74bdd24ed1e9698b913ab6b3d5a18aa6c589fc09 100644 (file)
@@ -275,6 +275,9 @@ u32 get_ahb_clk(void)
 
 void arch_preboot_os(void)
 {
+#if defined(CONFIG_PCIE_IMX)
+       imx_pcie_remove();
+#endif
 #if defined(CONFIG_CMD_SATA)
        sata_stop();
 #if defined(CONFIG_MX6)
index 732d59d711071df9d5155b51b4b02530c2924768..eab0a2b602f884c9934c01d6fb22b51393fa2153 100644 (file)
@@ -42,6 +42,9 @@
 
 /* PCIe Port Logic registers (memory-mapped) */
 #define PL_OFFSET 0x700
+#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
+#define PCIE_PL_PFLR_LINK_STATE_MASK           (0x3f << 16)
+#define PCIE_PL_PFLR_FORCE_LINK                        (1 << 15)
 #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
 #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
 #define PCIE_PHY_DEBUG_R1_LINK_UP              (1 << 4)
@@ -445,6 +448,36 @@ static int imx6_pcie_assert_core_reset(void)
        /* Power up PCIe PHY */
        setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
 #else
+       /*
+        * If the bootloader already enabled the link we need some special
+        * handling to get the core back into a state where it is safe to
+        * touch it for configuration.  As there is no dedicated reset signal
+        * wired up for MX6QDL, we need to manually force LTSSM into "detect"
+        * state before completely disabling LTSSM, which is a prerequisite
+        * for core configuration.
+        *
+        * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
+        * indication that the bootloader activated the link.
+        */
+       if (is_mx6dq()) {
+               u32 val, gpr1, gpr12;
+
+               gpr1 = readl(&iomuxc_regs->gpr[1]);
+               gpr12 = readl(&iomuxc_regs->gpr[12]);
+               if ((gpr1 & IOMUXC_GPR1_PCIE_REF_CLK_EN) &&
+                   (gpr12 & IOMUXC_GPR12_PCIE_CTL_2)) {
+                       val = readl(MX6_DBI_ADDR + PCIE_PL_PFLR);
+                       val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+                       val |= PCIE_PL_PFLR_FORCE_LINK;
+
+                       imx_pcie_fix_dabt_handler(true);
+                       writel(val, MX6_DBI_ADDR + PCIE_PL_PFLR);
+                       imx_pcie_fix_dabt_handler(false);
+
+                       gpr12 &= ~IOMUXC_GPR12_PCIE_CTL_2;
+                       writel(val, &iomuxc_regs->gpr[12]);
+               }
+       }
        setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
        clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
 #endif
@@ -652,6 +685,11 @@ void imx_pcie_init(void)
        }
 }
 
+void imx_pcie_remove(void)
+{
+       imx6_pcie_assert_core_reset();
+}
+
 /* Probe function. */
 void pci_init_board(void)
 {
index d3c955eb8019c1996ea8caa3f41be9ffdf5fa83e..c8ef997d0de91ce0a9be21df5ece3e6d704c2c92 100644 (file)
@@ -754,6 +754,10 @@ int pci_last_busno(void);
 extern void pci_mpc85xx_init (struct pci_controller *hose);
 #endif
 
+#ifdef CONFIG_PCIE_IMX
+extern void imx_pcie_remove(void);
+#endif
+
 #if !defined(CONFIG_DM_PCI) || defined(CONFIG_DM_PCI_COMPAT)
 /**
  * pci_write_bar32() - Write the address of a BAR including control bits