summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2018-12-16 21:19:07 -0800
committerSascha Hauer <s.hauer@pengutronix.de>2019-01-08 16:28:48 +0100
commite93ea04d5f0776a445071dccf4135e10878ea4c3 (patch)
treeac165dadd00c58bb20e2dd2559984efce3331360
parentc6e81bac2b4c75c9c4ba769d4a9e26e7e1b18440 (diff)
downloadbarebox-e93ea04d5f0776a445071dccf4135e10878ea4c3.tar.gz
barebox-e93ea04d5f0776a445071dccf4135e10878ea4c3.tar.xz
PCI: imx6: Remove LTSSM disable workaround
Port of a Linux commit a71280722eeba8f1afa51ad6656028dcb96e110b This causes CPU hangs when the system is reset by the watchdog, as the GPRs aren't cleared, but the clocks are back to disabled state. If the bootloader uses PCIe, it must take care to bring it down into a safe state, before passing control to the Linux kernel. This is the only way to get a properly operating system at all times and circumstances. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> LTSSM disable workaround still needs to be performed before passing control to Linux. However, in order to avoid the hang described above, we move it to imx6_pcie_remove() and apply it without relying on values in GPR. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--drivers/pci/pci-imx6.c57
1 files changed, 28 insertions, 29 deletions
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index a9a4be927b..023e6f07fd 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -239,8 +239,7 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
- u32 val, gpr1, gpr12;
+ u32 gpr1;
switch (imx6_pcie->variant) {
case IMX6QP:
@@ -249,34 +248,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
break;
case IMX6Q:
- /*
- * 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.
- */
gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
- gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-
- if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
- (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
- val = dw_pcie_readl_rc(pp, PCIE_PL_PFLR);
- val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
- val |= PCIE_PL_PFLR_FORCE_LINK;
-
- data_abort_mask();
- dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val);
- data_abort_unmask();
-
- gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
- writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- }
-
gpr1 |= IMX6Q_GPR1_PCIE_TEST_PD;
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
@@ -642,6 +614,33 @@ static void imx6_pcie_remove(struct device_d *dev)
{
struct imx6_pcie *imx6_pcie = dev->priv;
+ if (imx6_pcie->variant == IMX6Q) {
+ /*
+ * 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.
+ */
+ struct pcie_port *pp = &imx6_pcie->pp;
+ u32 gpr12, val;
+
+ val = dw_pcie_readl_rc(pp, PCIE_PL_PFLR);
+ val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+ val |= PCIE_PL_PFLR_FORCE_LINK;
+
+ data_abort_mask();
+ dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val);
+ data_abort_unmask();
+
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ }
+
imx6_pcie_assert_core_reset(imx6_pcie);
}