Message ID | e42a6bb8ff0ddd6eaa31fe381875425a3730a73f.1532090446.git.leonard.crestez@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Hi Leonard, On Fri, Jul 20, 2018 at 9:47 AM, Leonard Crestez <leonard.crestez@nxp.com> wrote: > +static int imx6_pcie_resume_noirq(struct device *dev) > +{ > + int ret = 0; There is no need for initializing 'ret' here. > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > + struct pcie_port *pp = &imx6_pcie->pci->pp; > + > + if (imx6_pcie->variant != IMX7D) > + return 0; > + > + imx6_pcie_assert_core_reset(imx6_pcie); > + imx6_pcie_init_phy(imx6_pcie); > + imx6_pcie_deassert_core_reset(imx6_pcie); > + dw_pcie_setup_rc(pp); > + > + ret = imx6_pcie_establish_link(imx6_pcie); > + if (ret < 0) > + pr_err("pcie link is down after resume.\n"); Shouldn't the error be propagated? Also, dev_err() is preferred instead of pr_err().
Hi Leonard, Am Freitag, den 20.07.2018, 15:47 +0300 schrieb Leonard Crestez: > On imx7d the pcie-phy power domain is turned off in suspend and this can > make the system hang after resume when attempting any read from PCI. > > Fix this by adding minimal suspend/resume code from the nxp internal > tree. This will prepare for powering down on suspend and reset the block > on resume. > > Code is only for imx7d but a very similar sequence can be used for > other socs. > > > The original author is mostly Richard Zhu <hongxing.zhu@nxp.com>, this > patch adjusts the code to the upstream imx7d implemention using reset > controls and power domains. > > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> > --- > drivers/pci/controller/dwc/pci-imx6.c | 95 +++++++++++++++++++++++++-- > 1 file changed, 90 insertions(+), 5 deletions(-) > > diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c > index 80f604602783..daebee905108 100644 > --- a/drivers/pci/controller/dwc/pci-imx6.c > +++ b/drivers/pci/controller/dwc/pci-imx6.c > @@ -540,10 +540,27 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) > > > dev_err(dev, "Speed change timeout\n"); > > return -EINVAL; > } > > +static void imx6_pcie_ltssm_enable(struct device *dev) > +{ > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > + > > + switch (imx6_pcie->variant) { > > + case IMX6Q: > > + case IMX6SX: > > + case IMX6QP: > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > + IMX6Q_GPR12_PCIE_CTL_2, > > + IMX6Q_GPR12_PCIE_CTL_2); > > + break; > > + case IMX7D: > > + reset_control_deassert(imx6_pcie->apps_reset); > > + } > +} > + > static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) > { > > struct dw_pcie *pci = imx6_pcie->pci; > > struct device *dev = pci->dev; > > u32 tmp; > @@ -558,15 +575,11 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) > > tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; > > tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; > > dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); > > > /* Start LTSSM. */ > > - if (imx6_pcie->variant == IMX7D) > > - reset_control_deassert(imx6_pcie->apps_reset); > > - else > > - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); > > + imx6_pcie_ltssm_enable(dev); > > > ret = imx6_pcie_wait_for_link(imx6_pcie); > > if (ret) > > goto err_reset_phy; > > @@ -681,10 +694,81 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, > > static const struct dw_pcie_ops dw_pcie_ops = { > > .link_up = imx6_pcie_link_up, > }; > > +#ifdef CONFIG_PM_SLEEP > +static void imx6_pcie_ltssm_disable(struct device *dev) > +{ > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > + > > + switch (imx6_pcie->variant) { > > + case IMX6Q: > > + case IMX6SX: > > + case IMX6QP: > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > + IMX6Q_GPR12_PCIE_CTL_2, 0); Has this been tested on i.MX6? LTSSM disable requires a more complex sequence on this SoC to avoid hanging the system. See commit 3e3e406e3807 "PCI: imx6: Put LTSSM in "Detect" state before disabling it". Note that implementing the correct sequence requires the core clocks to still be on when disabling LTSSM, so would need to switch ordering of the function calls in imx6_pcie_suspend_noirq. > + break; > > + case IMX7D: > > + reset_control_assert(imx6_pcie->apps_reset); > > + break; > > + } > +} > + > +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) > +{ > > + clk_disable_unprepare(imx6_pcie->pcie); > > + clk_disable_unprepare(imx6_pcie->pcie_phy); > > + clk_disable_unprepare(imx6_pcie->pcie_bus); > + > > + if (imx6_pcie->variant == IMX7D) { > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, > > + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); > > + } > +} > + > +static int imx6_pcie_suspend_noirq(struct device *dev) > +{ > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > + > > + if (imx6_pcie->variant != IMX7D) > > + return 0; > + > > + imx6_pcie_clk_disable(imx6_pcie); > > + imx6_pcie_ltssm_disable(dev); > + > > + return 0; > +} > + > +static int imx6_pcie_resume_noirq(struct device *dev) > +{ > > + int ret = 0; > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > + struct pcie_port *pp = &imx6_pcie->pci->pp; > + > > + if (imx6_pcie->variant != IMX7D) > > + return 0; > + > > + imx6_pcie_assert_core_reset(imx6_pcie); > > + imx6_pcie_init_phy(imx6_pcie); > > + imx6_pcie_deassert_core_reset(imx6_pcie); > > + dw_pcie_setup_rc(pp); > + > > + ret = imx6_pcie_establish_link(imx6_pcie); > > + if (ret < 0) > + pr_err("pcie link is down after resume.\n"); dev_err(), please. Regards, Lucas > + > > + return 0; > +} > +#endif > + > +static const struct dev_pm_ops imx6_pcie_pm_ops = { > > + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, > > + imx6_pcie_resume_noirq) > +}; > + > static int imx6_pcie_probe(struct platform_device *pdev) > { > > struct device *dev = &pdev->dev; > > struct dw_pcie *pci; > > struct imx6_pcie *imx6_pcie; > @@ -847,10 +931,11 @@ static const struct of_device_id imx6_pcie_of_match[] = { > static struct platform_driver imx6_pcie_driver = { > > .driver = { > > > .name = "imx6q-pcie", > > .of_match_table = imx6_pcie_of_match, > > .suppress_bind_attrs = true, > > + .pm = &imx6_pcie_pm_ops, > > }, > > .probe = imx6_pcie_probe, > > .shutdown = imx6_pcie_shutdown, > }; >
On Mon, 2018-07-23 at 11:38 +0200, Lucas Stach wrote: > Hi Leonard, > > Am Freitag, den 20.07.2018, 15:47 +0300 schrieb Leonard Crestez: > > On imx7d the pcie-phy power domain is turned off in suspend and this can > > make the system hang after resume when attempting any read from PCI. > > > > Fix this by adding minimal suspend/resume code from the nxp internal > > tree. This will prepare for powering down on suspend and reset the block > > on resume. > > > > Code is only for imx7d but a very similar sequence can be used for > > other socs. > > > > +static void imx6_pcie_ltssm_disable(struct device *dev) > > +{ > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > + > > + switch (imx6_pcie->variant) { > > + case IMX6Q: > > + case IMX6SX: > > + case IMX6QP: > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > + IMX6Q_GPR12_PCIE_CTL_2, 0); > > Has this been tested on i.MX6? LTSSM disable requires a more complex > sequence on this SoC to avoid hanging the system. See commit > 3e3e406e3807 "PCI: imx6: Put LTSSM in "Detect" state before disabling > it". This patch only enables suspend/resume for imx7d with other SOCs to follow later. The ltssm_disable function is just symmetric with ltssm_enable. The 6Q parts are affected by errata "ERR005723 PCIe: PCIe does not support L2 power down [i.MX 6Dual/6Quad Only]". This design error seems to have the same root cause as your problem (no dedicated reset control) so this works out quite nicely: the solution is to never power down pci on affected chips. > > +static int imx6_pcie_resume_noirq(struct device *dev) > > +{ > > + int ret = 0; > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > + struct pcie_port *pp = &imx6_pcie->pci->pp; > > + > > + if (imx6_pcie->variant != IMX7D) > > + return 0; > > + > > + imx6_pcie_assert_core_reset(imx6_pcie); > > + imx6_pcie_init_phy(imx6_pcie); > > + imx6_pcie_deassert_core_reset(imx6_pcie); > > + dw_pcie_setup_rc(pp); > > + > > + ret = imx6_pcie_establish_link(imx6_pcie); > > + if (ret < 0) > > + pr_err("pcie link is down after resume.\n"); > > dev_err(), please. The imx6_pcie_establish_link function already seems to link error information so the message could be dropped. However it's still helpful to know that those pci link errors are specifically related to resume. Fabio suggested I propagate the return code but I'm not sure that's helpful since "link down" is what happens when the slot is empty and this is clearly not a "error" or "failure". It's not clear if "slot empty" can be distinguished in some way. I'll switch to dev_info and drop the error code, is this OK? One aspect that I skipped is PME_Turn_Off support: The PCI standard mandates that this is sent before entering L2/L3 and the designware core supports this but it's not part of this patch. Is it fine if I post this separately or should it be part of the same series? The turnoff bit is in IOMUX gpr for imx6 but SRC for imx7 so it would require additional patches in reset, dts and then pci.
Am Montag, den 23.07.2018, 12:37 +0000 schrieb Leonard Crestez: > On Mon, 2018-07-23 at 11:38 +0200, Lucas Stach wrote: > > Hi Leonard, > > > > Am Freitag, den 20.07.2018, 15:47 +0300 schrieb Leonard Crestez: > > > On imx7d the pcie-phy power domain is turned off in suspend and this can > > > make the system hang after resume when attempting any read from PCI. > > > > > > Fix this by adding minimal suspend/resume code from the nxp internal > > > tree. This will prepare for powering down on suspend and reset the block > > > on resume. > > > > > > Code is only for imx7d but a very similar sequence can be used for > > > other socs. > > > > > > +static void imx6_pcie_ltssm_disable(struct device *dev) > > > +{ > > > > > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > > + > > > > > > + switch (imx6_pcie->variant) { > > > > > > + case IMX6Q: > > > > > > + case IMX6SX: > > > > > > + case IMX6QP: > > > > > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > > + IMX6Q_GPR12_PCIE_CTL_2, 0); > > > > Has this been tested on i.MX6? LTSSM disable requires a more complex > > sequence on this SoC to avoid hanging the system. See commit > > 3e3e406e3807 "PCI: imx6: Put LTSSM in "Detect" state before disabling > > it". > > This patch only enables suspend/resume for imx7d with other SOCs to > follow later. The ltssm_disable function is just symmetric with > ltssm_enable. > > The 6Q parts are affected by errata "ERR005723 PCIe: PCIe does not > support L2 power down [i.MX 6Dual/6Quad Only]". > > This design error seems to have the same root cause as your problem (no > dedicated reset control) so this works out quite nicely: the solution > is to never power down pci on affected chips. I don't quite like code that looks like it is doing the right thing, but then doesn't. Can we at least emit a warning that there might be dragons if anyone tries to call this on i.MX6? > > > +static int imx6_pcie_resume_noirq(struct device *dev) > > > +{ > > > > > > + int ret = 0; > > > > > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > > > > > + struct pcie_port *pp = &imx6_pcie->pci->pp; > > > + > > > > > > + if (imx6_pcie->variant != IMX7D) > > > > > > + return 0; > > > + > > > > > > + imx6_pcie_assert_core_reset(imx6_pcie); > > > > > > + imx6_pcie_init_phy(imx6_pcie); > > > > > > + imx6_pcie_deassert_core_reset(imx6_pcie); > > > > > > + dw_pcie_setup_rc(pp); > > > + > > > > > > + ret = imx6_pcie_establish_link(imx6_pcie); > > > > > > + if (ret < 0) > > > + pr_err("pcie link is down after resume.\n"); > > > > dev_err(), please. > > The imx6_pcie_establish_link function already seems to link error > information so the message could be dropped. However it's still helpful > to know that those pci link errors are specifically related to resume. > > Fabio suggested I propagate the return code but I'm not sure that's > helpful since "link down" is what happens when the slot is empty and > this is clearly not a "error" or "failure". It's not clear if "slot > empty" can be distinguished in some way. I don't think we have a generic way to distinguish between the two cases. > I'll switch to dev_info and drop the error code, is this OK? Yes, that's fine with me. > > One aspect that I skipped is PME_Turn_Off support: The PCI standard > mandates that this is sent before entering L2/L3 and the designware > core supports this but it's not part of this patch. > > Is it fine if I post this separately or should it be part of the same > series? The turnoff bit is in IOMUX gpr for imx6 but SRC for imx7 so it > would require additional patches in reset, dts and then pci. IMO it is fine to have this as a follow on patchset. Regards, Lucas
On Tue, 2018-07-24 at 12:09 +0200, Lucas Stach wrote: > Am Montag, den 23.07.2018, 12:37 +0000 schrieb Leonard Crestez: > > On Mon, 2018-07-23 at 11:38 +0200, Lucas Stach wrote: > > > Am Freitag, den 20.07.2018, 15:47 +0300 schrieb Leonard Crestez: > > > > On imx7d the pcie-phy power domain is turned off in suspend and this can > > > > make the system hang after resume when attempting any read from PCI. > > > > > > > > Fix this by adding minimal suspend/resume code from the nxp internal > > > > tree. This will prepare for powering down on suspend and reset the block > > > > on resume. > > > > > > > > Code is only for imx7d but a very similar sequence can be used for > > > > other socs. > > > > > > > > +static void imx6_pcie_ltssm_disable(struct device *dev) > > > > +{ > > > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > > > + > > > > + switch (imx6_pcie->variant) { > > > > + case IMX6Q: > > > > + case IMX6SX: > > > > + case IMX6QP: > > > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > > > + IMX6Q_GPR12_PCIE_CTL_2, 0); > > > > > > Has this been tested on i.MX6? LTSSM disable requires a more complex > > > sequence on this SoC to avoid hanging the system. See commit > > > 3e3e406e3807 "PCI: imx6: Put LTSSM in "Detect" state before disabling > > > it". > > > > This patch only enables suspend/resume for imx7d with other SOCs to > > follow later. The ltssm_disable function is just symmetric with > > ltssm_enable. > > > > The 6Q parts are affected by errata "ERR005723 PCIe: PCIe does not > > support L2 power down [i.MX 6Dual/6Quad Only]". > > > > This design error seems to have the same root cause as your problem (no > > dedicated reset control) so this works out quite nicely: the solution > > is to never power down pci on affected chips. > > I don't quite like code that looks like it is doing the right thing, > but then doesn't. Can we at least emit a warning that there might be > dragons if anyone tries to call this on i.MX6? But the function will indeed toggle the right bits to initiate ltssm disabling. If this is not useful or can't be used right then it's the caller's problem :) I can add a default: clause to the switch which returns -ENOSYS and let IMX6Q fall that way, would that be OK? This would also help when adding new variants.
Am Dienstag, den 24.07.2018, 12:04 +0000 schrieb Leonard Crestez: > On Tue, 2018-07-24 at 12:09 +0200, Lucas Stach wrote: > > Am Montag, den 23.07.2018, 12:37 +0000 schrieb Leonard Crestez: > > > On Mon, 2018-07-23 at 11:38 +0200, Lucas Stach wrote: > > > > Am Freitag, den 20.07.2018, 15:47 +0300 schrieb Leonard Crestez: > > > > > On imx7d the pcie-phy power domain is turned off in suspend and this can > > > > > make the system hang after resume when attempting any read from PCI. > > > > > > > > > > Fix this by adding minimal suspend/resume code from the nxp internal > > > > > tree. This will prepare for powering down on suspend and reset the block > > > > > on resume. > > > > > > > > > > Code is only for imx7d but a very similar sequence can be used for > > > > > other socs. > > > > > > > > > > +static void imx6_pcie_ltssm_disable(struct device *dev) > > > > > +{ > > > > > > > > > > + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); > > > > > + > > > > > > > > > > + switch (imx6_pcie->variant) { > > > > > > > > > > + case IMX6Q: > > > > > > > > > > + case IMX6SX: > > > > > > > > > > + case IMX6QP: > > > > > > > > > > + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, > > > > > + IMX6Q_GPR12_PCIE_CTL_2, 0); > > > > > > > > Has this been tested on i.MX6? LTSSM disable requires a more complex > > > > sequence on this SoC to avoid hanging the system. See commit > > > > 3e3e406e3807 "PCI: imx6: Put LTSSM in "Detect" state before disabling > > > > it". > > > > > > This patch only enables suspend/resume for imx7d with other SOCs to > > > follow later. The ltssm_disable function is just symmetric with > > > ltssm_enable. > > > > > > The 6Q parts are affected by errata "ERR005723 PCIe: PCIe does not > > > support L2 power down [i.MX 6Dual/6Quad Only]". > > > > > > This design error seems to have the same root cause as your problem (no > > > dedicated reset control) so this works out quite nicely: the solution > > > is to never power down pci on affected chips. > > > > I don't quite like code that looks like it is doing the right thing, > > but then doesn't. Can we at least emit a warning that there might be > > dragons if anyone tries to call this on i.MX6? > > But the function will indeed toggle the right bits to initiate ltssm > disabling. If this is not useful or can't be used right then it's the > caller's problem :) I don't agree with that. I would expect a function that is called ltssm_disable to do so in a way that is safe on the hardware that it claims to handle, which in case of i.MX6 means bashing the LTSSM into detect state before toggling the GPR bit. > I can add a default: clause to the switch which returns -ENOSYS and let > IMX6Q fall that way, would that be OK? This would also help when adding > new variants. Yes, given that there is currently no way to test this on i.MX6, returning -ENOSYS sound much better. This at least tells anyone who intends to use this function that there is indeed missing functionality there. Regards, Lucas
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80f604602783..daebee905108 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -540,10 +540,27 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) dev_err(dev, "Speed change timeout\n"); return -EINVAL; } +static void imx6_pcie_ltssm_enable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6Q: + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2); + break; + case IMX7D: + reset_control_deassert(imx6_pcie->apps_reset); + } +} + static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; struct device *dev = pci->dev; u32 tmp; @@ -558,15 +575,11 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); /* Start LTSSM. */ - if (imx6_pcie->variant == IMX7D) - reset_control_deassert(imx6_pcie->apps_reset); - else - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + imx6_pcie_ltssm_enable(dev); ret = imx6_pcie_wait_for_link(imx6_pcie); if (ret) goto err_reset_phy; @@ -681,10 +694,81 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, static const struct dw_pcie_ops dw_pcie_ops = { .link_up = imx6_pcie_link_up, }; +#ifdef CONFIG_PM_SLEEP +static void imx6_pcie_ltssm_disable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6Q: + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 0); + break; + case IMX7D: + reset_control_assert(imx6_pcie->apps_reset); + break; + } +} + +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +{ + clk_disable_unprepare(imx6_pcie->pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); + clk_disable_unprepare(imx6_pcie->pcie_bus); + + if (imx6_pcie->variant == IMX7D) { + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); + } +} + +static int imx6_pcie_suspend_noirq(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_clk_disable(imx6_pcie); + imx6_pcie_ltssm_disable(dev); + + return 0; +} + +static int imx6_pcie_resume_noirq(struct device *dev) +{ + int ret = 0; + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + struct pcie_port *pp = &imx6_pcie->pci->pp; + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_assert_core_reset(imx6_pcie); + imx6_pcie_init_phy(imx6_pcie); + imx6_pcie_deassert_core_reset(imx6_pcie); + dw_pcie_setup_rc(pp); + + ret = imx6_pcie_establish_link(imx6_pcie); + if (ret < 0) + pr_err("pcie link is down after resume.\n"); + + return 0; +} +#endif + +static const struct dev_pm_ops imx6_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, + imx6_pcie_resume_noirq) +}; + static int imx6_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dw_pcie *pci; struct imx6_pcie *imx6_pcie; @@ -847,10 +931,11 @@ static const struct of_device_id imx6_pcie_of_match[] = { static struct platform_driver imx6_pcie_driver = { .driver = { .name = "imx6q-pcie", .of_match_table = imx6_pcie_of_match, .suppress_bind_attrs = true, + .pm = &imx6_pcie_pm_ops, }, .probe = imx6_pcie_probe, .shutdown = imx6_pcie_shutdown, };
On imx7d the pcie-phy power domain is turned off in suspend and this can make the system hang after resume when attempting any read from PCI. Fix this by adding minimal suspend/resume code from the nxp internal tree. This will prepare for powering down on suspend and reset the block on resume. Code is only for imx7d but a very similar sequence can be used for other socs. The original author is mostly Richard Zhu <hongxing.zhu@nxp.com>, this patch adjusts the code to the upstream imx7d implemention using reset controls and power domains. Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> --- drivers/pci/controller/dwc/pci-imx6.c | 95 +++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 5 deletions(-)