From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9741FC54F4D for ; Tue, 28 Jul 2026 16:38:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:In-Reply-To:Content-Type: MIME-Version:Message-ID:Subject:Cc:To:From:Date:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:References: List-Owner; bh=VaDP40JoGOSQxXmgmR3af5oPCK1LSZo99YVjzP4O+2E=; b=VSS7KwPLTxRVLG hyUD2a7WteLa8WnT/JjFwy13pQMzyY+S5qRxgDMt9FA6HUGrXMCna5R4fUhmVtWPllzLlXnM1bGvv AFhZZ+EjuyheGxy09YtHaXTjaXKBIpvrARXqItwS3ClbyGbZyzmf4RmzjQND2psPC8ATBoOTjr65B sj9ZBgD2xzeE0H2VQ79bs8dbhXt9fDaNiKuGbPJ/DulYbHX7ADWSHF0BxHZrn8PbJ+zS7wexKrGNe AaMfjROG8y4M2jJqLzsq8RuwaSwSEDUqaq/6/pkpLV3iGied7sdrZ0e3uq8Eni7KK/Uc3CHl4vmBo L7TNvCJzAuhnurJGF/pg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1wokoW-00000005q7W-00yp; Tue, 28 Jul 2026 16:37:56 +0000 Received: from tor.source.kernel.org ([2600:3c04:e001:324:0:1991:8:25]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1wokoU-00000005q73-3uR6 for linux-arm-kernel@lists.infradead.org; Tue, 28 Jul 2026 16:37:55 +0000 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by tor.source.kernel.org (Postfix) with ESMTP id E702F60A8C; Tue, 28 Jul 2026 16:37:53 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 702EC1F000E9; Tue, 28 Jul 2026 16:37:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785256673; bh=VaDP40JoGOSQxXmgmR3af5oPCK1LSZo99YVjzP4O+2E=; h=Date:From:To:Cc:Subject:In-Reply-To; b=MwZw/ie+VMuOaZJGGkyDSli4aTKGmcIXxhmj654dvcSKOlPloSaUaRxqJ6D7pWWd+ ZYBfw24z09CfaOyJhubrf65ZWc5pSDK4BzDeJ4lHkQLBzczrKdveNGRHk4+QxMvCq/ eAQ9jRhHaz85kZ6qSpaD3bUXFwc9/Ri3pIYipMvWCZbHJ9qws+2Yb76pLpQI3L480R CThzCvCl2QzsgSIU7NQiF7x6knRnIXBu+uwFN+EW3wkzj/GA2mdXkJA/o6Bs6ocfZy oDdBxtWAzEmOFaBTTc+MFa5XoGjTc1alEX5otaMoW7pCepT3G/gUGZPAuhuAxEytt7 N35zj92SU8zUw== Date: Tue, 28 Jul 2026 11:37:52 -0500 From: Bjorn Helgaas To: hongxing.zhu@oss.nxp.com Cc: frank.li@nxp.com, l.stach@pengutronix.de, lpieralisi@kernel.org, kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org, bhelgaas@google.com, s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com, linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org, imx@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Zhu , Leonardo Costa , Leonardo Costa Subject: Re: [PATCH v5] PCI: imx6: Fix i.MX6Q/DL boot hang caused by improper PHY power sequencing Message-ID: <20260728163752.GA1328281@bhelgaas> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260728035159.2702021-1-hongxing.zhu@oss.nxp.com> X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Tue, Jul 28, 2026 at 11:51:59AM +0800, hongxing.zhu@oss.nxp.com wrote: > From: Richard Zhu > > commit 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling regulators") > introduced a boot hang on i.MX6Q/DL variants by reordering > imx_pcie_host_init() to call imx6q_pcie_enable_ref_clk() (which powered up > the PHY) before imx6q_pcie_core_reset() (which powered it back down). > > Before 610fa91d9863, the sequence was: > > 1. imx_pcie_assert_core_reset() - power down PHY (set TEST_PD), set > REF_CLK_EN > 2. imx_pcie_clk_enable() - power up PHY (clear TEST_PD), set REF_CLK_EN > 3. Link training starts with PHY powered up (TEST_PD cleared) > 4. Link training succeeds > > After 610fa91d9863, the sequence became: > > 1. imx_pcie_clk_enable() - power up PHY (clear TEST_PD), set REF_CLK_EN > 2. imx_pcie_assert_core_reset() - power down PHY (set TEST_PD), set > REF_CLK_EN > 3. imx_pcie_deassert_core_reset() - does nothing > 4. Link training starts with PHY powered down (TEST_PD set) > 5. Link training fails and boot hangs > > To fix this: > > - Remove TEST_PD PHY power control from imx6q_pcie_enable_ref_clk() > - Remove REF_CLK_EN control from imx6q_pcie_core_reset() > - Add TEST_PD PHY power control to imx6qp_pcie_core_reset(), which > previously relied on imx6q_pcie_enable_ref_clk() to power up the PHY by > clearing TEST_PD > - Clear TEST_PD to power on PHY in imx_pcie_deassert_core_reset() > > These changes together ensure the correct sequence: > > 1. REF_CLK_EN set in clk_enable() (TEST_PD untouched) > 2. TEST_PD set in assert_core_reset() (PHY power off) > 3. TEST_PD cleared in deassert_core_reset() (PHY power on) > 4. Link training starts with proper PHY state > > The i.MX6Q/DL PCIe PHY requires approximately 120us between TEST_PD > de-assertion and link training start. Add usleep_range(200, 500) in > imx6q_pcie_core_reset() after clearing TEST_PD to satisfy this requirement. > > Add explicit imx_pcie_assert_core_reset() calls in error paths and > host_exit() to ensure no power leak. > > Fixes: 610fa91d9863 ("PCI: imx6: Assert PERST# before enabling regulators") > Signed-off-by: Richard Zhu > Reported-by: Leonardo Costa > Closes: https://lore.kernel.org/lkml/20260629143439.361560-1-leoreis.costa@gmail.com/ > Tested-by: Leonardo Costa > Reviewed-by: Frank Li Applied to pci/for-linus for v7.2, thanks very much! > --- > Changes in v5: > Update the commit log suggested by Bjorn. > > Changes in v4: > Refer to Sashiko' reivew of v3 patch. > - Adjust imx_pcie_assert_core_reset() in imx_pcie_host_exit(). > - Add the delay explicitly after TEST_PD is cleared, since the PERST# GPIO > might be optional. > > Changes in v3: > Update the commit descriptions to address the following items. > - Clarify the root cause of this regresssion. > - Describe why both changes are mandatory required to fix this > regression. > - Justify the delay removal also. > > Changes in v2: > Per Sashiko's review, invoke imx_pcie_assert_core_reset() explicitly > in error path of imx_pcie_host_init() and imx_pcie_host_exit(). > --- > drivers/pci/controller/dwc/pci-imx6.c | 41 ++++++++++++++------------- > 1 file changed, 22 insertions(+), 19 deletions(-) > > diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c > index e25f938eefe23..c94b5e991aecd 100644 > --- a/drivers/pci/controller/dwc/pci-imx6.c > +++ b/drivers/pci/controller/dwc/pci-imx6.c > @@ -681,21 +681,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; > } > @@ -826,6 +817,12 @@ static int imx6sx_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) > > static int imx6qp_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) > { > + 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); > regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_SW_RST, > assert ? IMX6Q_GPR1_PCIE_SW_RST : 0); > if (!assert) > @@ -836,11 +833,15 @@ 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) > { > - if (!assert) > - return 0; > + 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); > > - 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); > + if (!assert) > + usleep_range(200, 500); > > return 0; > } > @@ -1451,6 +1452,7 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp) > return 0; > > err_phy_off: > + imx_pcie_assert_core_reset(imx_pcie); > phy_power_off(imx_pcie->phy); > err_phy_exit: > phy_exit(imx_pcie->phy); > @@ -1470,6 +1472,7 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp) > struct dw_pcie *pci = to_dw_pcie_from_pp(pp); > struct imx_pcie *imx_pcie = to_imx_pcie(pci); > > + imx_pcie_assert_core_reset(imx_pcie); > if (imx_pcie->phy) { > if (phy_power_off(imx_pcie->phy)) > dev_err(pci->dev, "unable to power off PHY\n"); > -- > 2.34.1 >