[PATCH v6 10/11] PCI: imx6: Add CLKREQ# override to enable REFCLK for i.MX95 PCIe

Richard Zhu
2025-10-15T03:06:03Z

The CLKREQ# is an open drain, active low signal that is driven low by
the card to request reference clock. It's an optional signal added in
PCIe CEM r4.0, sec 2. Thus, this signal wouldn't be driven low if it's
reserved.

On i.MX95 EVK board, the PCIe slot connected to the second PCIe
controller is one standard PCIe slot. The default voltage of CLKREQ# is
not active low, and may not be driven to active low due to the potential
scenario listed above (e.x INTEL e1000e network card).

Since the reference clock controlled by CLKREQ# is required by i.MX95
PCIe host too. To make sure this clock is ready even when the CLKREQ#
isn't driven low by the card(e.x the scenario described above), force
CLKREQ# override active low for i.MX95 PCIe host to enable reference
clock.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
drivers/pci/controller/dwc/pci-imx6.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index a60fe7c337e08..aa5a4900d0eb6 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -52,6 +52,8 @@
#define IMX95_PCIE_REF_CLKEN BIT(23)
#define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9)
#define IMX95_PCIE_SS_RW_REG_1 0xf4
+#define IMX95_PCIE_CLKREQ_OVERRIDE_EN BIT(8)
+#define IMX95_PCIE_CLKREQ_OVERRIDE_VAL BIT(9)
#define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31)

#define IMX95_PE0_GEN_CTRL_1 0x1050
@@ -711,6 +713,22 @@ static int imx7d_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
return 0;
}

+static void imx95_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable)
+{
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1,
+ IMX95_PCIE_CLKREQ_OVERRIDE_EN,
+ enable ? IMX95_PCIE_CLKREQ_OVERRIDE_EN : 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1,
+ IMX95_PCIE_CLKREQ_OVERRIDE_VAL,
+ enable ? IMX95_PCIE_CLKREQ_OVERRIDE_VAL : 0);
+}
+
+static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
+{
+ imx95_pcie_clkreq_override(imx_pcie, enable);
+ return 0;
+}
+
static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie)
{
struct dw_pcie *pci = imx_pcie->pci;
@@ -1918,6 +1936,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.core_reset = imx95_pcie_core_reset,
.init_phy = imx95_pcie_init_phy,
.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
+ .enable_ref_clk = imx95_pcie_enable_ref_clk,
},
[IMX8MQ_EP] = {
.variant = IMX8MQ_EP,
@@ -1974,6 +1993,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.core_reset = imx95_pcie_core_reset,
.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
.epc_features = &imx95_pcie_epc_features,
+ .enable_ref_clk = imx95_pcie_enable_ref_clk,
.mode = DW_PCIE_EP_TYPE,
},
};
--
2.37.1