[PATCH v1] PCI: imx6: Fix i.MX6Q/DL boot hang by separating PHY power and reference clock control
Hongxing Zhu (OSS)
hongxing.zhu at oss.nxp.com
Mon Jul 6 20:03:03 PDT 2026
> -----Original Message-----
> From: Soeren Moch <smoch at web.de>
> Sent: Monday, July 6, 2026 10:09 PM
> To: Hongxing Zhu (OSS) <hongxing.zhu at oss.nxp.com>; Frank Li
> <frank.li at nxp.com>; l.stach at pengutronix.de; lpieralisi at kernel.org;
> kwilczynski at kernel.org; mani at kernel.org; robh at kernel.org;
> bhelgaas at google.com; s.hauer at pengutronix.de; kernel at pengutronix.de;
> festevam at gmail.com
> Cc: linux-pci at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> imx at lists.linux.dev; linux-kernel at vger.kernel.org; Hongxing Zhu
> <hongxing.zhu at nxp.com>
> Subject: Re: [PATCH v1] PCI: imx6: Fix i.MX6Q/DL boot hang by separating PHY
> power and reference clock control
>
>
>
> On 06.07.26 05:06, hongxing.zhu at oss.nxp.com wrote:
> > From: Richard Zhu <hongxing.zhu at nxp.com>
> >
> > Commit 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling
> > regulators") introduced a boot hang on i.MX6Q/DL variants by changing
> > the initialization sequence.
> >
> > The issue stems from coupling PHY power (TEST_PD) and reference clock
> > (REF_CLK_EN) control in imx6q_pcie_enable_ref_clk(). When these are
> > managed together, the timing between PHY power-up and reference clock
> > enablement cannot be properly controlled, leading to initialization
> > failures.
> >
> > Fix this by separating the two concerns:
> >
> > - Move PHY power control (TEST_PD) to imx6q_pcie_core_reset() where it
> > logically belongs with reset operations. This ensures PHY power state
> > is managed as part of the core reset sequence.
> >
> > - Update imx6qp_pcie_core_reset() to call imx6q_pcie_core_reset() for
> > shared PHY power management, avoiding code duplication.
> >
> > - Make imx6q_pcie_enable_ref_clk() responsible only for reference clock
> > (REF_CLK_EN) control, simplifying its purpose.
> >
> > - Remove the 10us delay workaround from imx6q_pcie_enable_ref_clk() as
> > proper sequencing is now handled by the core_reset functions.
> >
> > This refactoring ensures PHY power is controlled during reset
> > operations, fixing the boot hang while improving code maintainability.
> >
> > Fixes: 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling
> > regulators")
> > Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
> With this patch on top of v7.2-rc2 I see everything booting, lspci shows the
> root complex, but no PCIe device behind it.
> Tested on a i.MX6Q based tbs2910 board.
>
> For me it is not clear whether this fail to detect PCIe devices is related to the
> patches in question, the reset timing, or something else. Needs further
> investigation.
Thanks for your kindly help to tests.
Did you ever encounter the boot failure without this patch based on v7.2-rc1
or later?
After applied this patch, my i.MX6Q Sabresd board can boot up successfully.
And the endpoint device can be detected as well.
My Local commits:
ad5939d49b268 (HEAD -> v7.2-rc2_pcie) PCI: imx6: Add runtime PM support for i.MX95
db7b15f198125 PCI: imx6: Update MPLLB bandwidth for i.MX95 PCIe Gen3 stability
a26735515c076 PCI: imx6: Fix i.MX6Q/DL boot hang by separating PHY power and reference clock control
d617eadf52a46 PCI: dwc: Add force_l2 flag for platforms requiring L2 entry without D3cold
8cdeaa50eae8d (tag: v7.2-rc2) Linux 7.2-rc2
Kernel logs:
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 7.2.0-rc2-00004-gad5939d49b26 (nxa08258 at shlinux89) (arm-poky-linux-gnueabi-gcc (GCC) 15.2.0, GNU ld (GNU Binutils) 2.45.0.20250908) #38 SMP Tue Jul 7 02:36:46 UTC 2026
...
root at imx6qpdlsolox:~# lspci
00:00.0 PCI bridge: Synopsys, Inc. DWC_usb3 / PCIe bridge (rev 01)
01:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
Best Regards
Richard Zhu
>
> Regards,
> Soeren
> > ---
> > drivers/pci/controller/dwc/pci-imx6.c | 43 +++++++++++----------------
> > 1 file changed, 18 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pci-imx6.c
> > b/drivers/pci/controller/dwc/pci-imx6.c
> > index ea0b4eb03c1d0..6924a06bde305 100644
> > --- a/drivers/pci/controller/dwc/pci-imx6.c
> > +++ b/drivers/pci/controller/dwc/pci-imx6.c
> > @@ -680,21 +680,12 @@ static int imx_pcie_attach_pd(struct device
> > *dev)
> >
> > static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool
> enable)
> > {
> > - if (enable) {
> > - /* power up core phy and enable ref clock */
> > - regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_TEST_PD);
> > - /*
> > - * The async reset input need ref clock to sync internally,
> > - * when the ref clock comes after reset, internal synced
> > - * reset time is too short, cannot meet the requirement.
> > - * Add a ~10us delay here.
> > - */
> > - usleep_range(10, 100);
> > - regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > - } else {
> > - regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > - regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_TEST_PD);
> > - }
> > + if (enable)
> > + regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > + IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > + else
> > + regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > + IMX6Q_GPR1_PCIE_REF_CLK_EN);
> >
> > return 0;
> > }
> > @@ -823,23 +814,25 @@ static int imx6sx_pcie_core_reset(struct imx_pcie
> *imx_pcie, bool assert)
> > return 0;
> > }
> >
> > -static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > assert)
> > +static int imx6q_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > +assert)
> > {
> > - regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_SW_RST,
> > - assert ? IMX6Q_GPR1_PCIE_SW_RST : 0);
> > - if (!assert)
> > - usleep_range(200, 500);
> > + if (assert)
> > + regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > + IMX6Q_GPR1_PCIE_TEST_PD);
> > + else
> > + regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> > + IMX6Q_GPR1_PCIE_TEST_PD);
> >
> > return 0;
> > }
> >
> > -static int imx6q_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > assert)
> > +static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool
> > +assert)
> > {
> > + imx6q_pcie_core_reset(imx_pcie, assert);
> > + regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_SW_RST,
> > + assert ? IMX6Q_GPR1_PCIE_SW_RST : 0);
> > if (!assert)
> > - return 0;
> > -
> > - regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_TEST_PD);
> > - regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
> IMX6Q_GPR1_PCIE_REF_CLK_EN);
> > + usleep_range(200, 500);
> >
> > return 0;
> > }
More information about the linux-arm-kernel
mailing list