Since i.MX PCIe doesn't support hot-plug, reduce power consumption as much as possible by disabling clocks and regulators and returning error when the link is down. Add a new host_exit() callback for i.MX PCIe driver to disable the clocks, regulators and so on in the error handling after host_init is finished. Signed-off-by: Richard Zhu <hongxing.zhu@xxxxxxx> --- drivers/pci/controller/dwc/pci-imx6.c | 34 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 160a0bd02098..f8b15f0bc9ce 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -849,7 +849,9 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - dw_pcie_wait_for_link(pci); + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_out; if (pci->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ @@ -880,12 +882,14 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) ret = imx6_pcie_wait_for_speed_change(imx6_pcie); if (ret) { dev_err(dev, "Failed to bring link up!\n"); - goto err_reset_phy; + goto err_out; } } /* Make sure link training is finished as well! */ - dw_pcie_wait_for_link(pci); + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_out; } else { dev_info(dev, "Link: Gen2 disabled\n"); } @@ -894,11 +898,10 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS); return 0; -err_reset_phy: +err_out: dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1)); - imx6_pcie_reset_phy(imx6_pcie); return ret; } @@ -922,8 +925,29 @@ static int imx6_pcie_host_init(struct pcie_port *pp) return 0; } +static void imx6_pcie_host_exit(struct pcie_port *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; + struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); + + imx6_pcie_reset_phy(imx6_pcie); + imx6_pcie_clk_disable(imx6_pcie); + switch (imx6_pcie->drvdata->variant) { + case IMX8MM: + if (phy_power_off(imx6_pcie->phy)) + dev_err(dev, "unable to power off phy\n"); + break; + default: + break; + } + if (imx6_pcie->vpcie) + regulator_disable(imx6_pcie->vpcie); +} + static const struct dw_pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, + .host_exit = imx6_pcie_host_exit, }; static const struct dw_pcie_ops dw_pcie_ops = { -- 2.25.1