[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