Commit 7b86e0a5 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/imx6'

- Fix suspend/resume support on i.MX6QDL, which has a hardware erratum that
  prevents use of L2 (Stefan Eichenberger)

* pci/controller/imx6:
  PCI: imx6: Fix suspend/resume support on i.MX6QDL
parents 2b4049d1 0a726f54
Loading
Loading
Loading
Loading
+46 −11
Original line number Diff line number Diff line
@@ -82,6 +82,11 @@ enum imx_pcie_variants {
#define IMX_PCIE_FLAG_HAS_SERDES		BIT(6)
#define IMX_PCIE_FLAG_SUPPORT_64BIT		BIT(7)
#define IMX_PCIE_FLAG_CPU_ADDR_FIXUP		BIT(8)
/*
 * Because of ERR005723 (PCIe does not support L2 power down) we need to
 * workaround suspend resume on some devices which are affected by this errata.
 */
#define IMX_PCIE_FLAG_BROKEN_SUSPEND		BIT(9)

#define imx_check_flag(pci, val)	(pci->drvdata->flags & val)

@@ -1237,9 +1242,19 @@ static int imx_pcie_suspend_noirq(struct device *dev)
		return 0;

	imx_pcie_msi_save_restore(imx_pcie, true);
	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
		/*
		 * The minimum for a workaround would be to set PERST# and to
		 * set the PCIE_TEST_PD flag. However, we can also disable the
		 * clock which saves some power.
		 */
		imx_pcie_assert_core_reset(imx_pcie);
		imx_pcie->drvdata->enable_ref_clk(imx_pcie, false);
	} else {
		imx_pcie_pm_turnoff(imx_pcie);
		imx_pcie_stop_link(imx_pcie->pci);
		imx_pcie_host_exit(pp);
	}

	return 0;
}
@@ -1253,6 +1268,23 @@ static int imx_pcie_resume_noirq(struct device *dev)
	if (!(imx_pcie->drvdata->flags & IMX_PCIE_FLAG_SUPPORTS_SUSPEND))
		return 0;

	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
		ret = imx_pcie->drvdata->enable_ref_clk(imx_pcie, true);
		if (ret)
			return ret;
		ret = imx_pcie_deassert_core_reset(imx_pcie);
		if (ret)
			return ret;
		/*
		 * Using PCIE_TEST_PD seems to disable MSI and powers down the
		 * root complex. This is why we have to setup the rc again and
		 * why we have to restore the MSI register.
		 */
		ret = dw_pcie_setup_rc(&imx_pcie->pci->pp);
		if (ret)
			return ret;
		imx_pcie_msi_save_restore(imx_pcie, false);
	} else {
		ret = imx_pcie_host_init(pp);
		if (ret)
			return ret;
@@ -1261,6 +1293,7 @@ static int imx_pcie_resume_noirq(struct device *dev)

		if (imx_pcie->link_is_up)
			imx_pcie_start_link(imx_pcie->pci);
	}

	return 0;
}
@@ -1485,7 +1518,9 @@ static const struct imx_pcie_drvdata drvdata[] = {
	[IMX6Q] = {
		.variant = IMX6Q,
		.flags = IMX_PCIE_FLAG_IMX_PHY |
			 IMX_PCIE_FLAG_IMX_SPEED_CHANGE,
			 IMX_PCIE_FLAG_IMX_SPEED_CHANGE |
			 IMX_PCIE_FLAG_BROKEN_SUSPEND |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.dbi_length = 0x200,
		.gpr = "fsl,imx6q-iomuxc-gpr",
		.clk_names = imx6q_clks,