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
This commit is contained in:
Bjorn Helgaas 2024-11-25 13:40:57 -06:00
commit 7b86e0a589

View File

@ -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);
imx_pcie_pm_turnoff(imx_pcie);
imx_pcie_stop_link(imx_pcie->pci);
imx_pcie_host_exit(pp);
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,14 +1268,32 @@ static int imx_pcie_resume_noirq(struct device *dev)
if (!(imx_pcie->drvdata->flags & IMX_PCIE_FLAG_SUPPORTS_SUSPEND))
return 0;
ret = imx_pcie_host_init(pp);
if (ret)
return ret;
imx_pcie_msi_save_restore(imx_pcie, false);
dw_pcie_setup_rc(pp);
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;
imx_pcie_msi_save_restore(imx_pcie, false);
dw_pcie_setup_rc(pp);
if (imx_pcie->link_is_up)
imx_pcie_start_link(imx_pcie->pci);
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,