[PATCH v6 11/11] PCI: imx6: Add a callback to clear CLKREQ# override

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

Clock Request is a reference clock request signal as defined by the PCIe
Mini CEM and M.2 specification; Also used by L1 PM Substates. But it's
an optional signal added in PCIe CEM r4.0, sec 2. The CLKREQ# support is
relied on the exact hardware board and device designs.

To support L1 PM Substates, add a callback to clear CLKREQ# override on
the boards that support CLKREQ# in the hardware designs.

The CLKREQ# override can be cleared safely when supports-clkreq is
present and PCIe link is up later. Because the CLKREQ# would be driven
low by the card at this time.

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

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index aa5a4900d0eb6..7cd0dc62ffd3b 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -138,6 +138,7 @@ struct imx_pcie_drvdata {
int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable);
int (*core_reset)(struct imx_pcie *pcie, bool assert);
int (*wait_pll_lock)(struct imx_pcie *pcie);
+ void (*clr_clkreq_override)(struct imx_pcie *pcie);
const struct dw_pcie_host_ops *ops;
};

@@ -151,6 +152,7 @@ struct imx_pcie {
struct gpio_desc *reset_gpiod;
struct clk_bulk_data *clks;
int num_clks;
+ bool supports_clkreq;
struct regmap *iomuxc_gpr;
u16 msi_ctrl;
u32 controller_id;
@@ -729,6 +731,16 @@ static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
return 0;
}

+static void imx8mm_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie)
+{
+ imx8mm_pcie_clkreq_override(imx_pcie, false);
+}
+
+static void imx95_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie)
+{
+ imx95_pcie_clkreq_override(imx_pcie, false);
+}
+
static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie)
{
struct dw_pcie *pci = imx_pcie->pci;
@@ -1345,6 +1357,12 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
dw_pcie_dbi_ro_wr_dis(pci);
}
+
+ /* Clear CLKREQ# override if supports_clkreq is true and link is up */
+ if (dw_pcie_link_up(pci) && imx_pcie->supports_clkreq) {
+ if (imx_pcie->drvdata->clr_clkreq_override)
+ imx_pcie->drvdata->clr_clkreq_override(imx_pcie);
+ }
}

/*
@@ -1763,6 +1781,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
/* Limit link speed */
pci->max_link_speed = 1;
of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed);
+ imx_pcie->supports_clkreq = of_property_read_bool(node, "supports-clkreq");

ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux");
if (ret < 0 && ret != -ENODEV)
@@ -1896,6 +1915,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
.init_phy = imx8mq_pcie_init_phy,
.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
+ .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
},
[IMX8MM] = {
.variant = IMX8MM,
@@ -1906,6 +1926,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
+ .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
},
[IMX8MP] = {
.variant = IMX8MP,
@@ -1916,6 +1937,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
+ .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
},
[IMX8Q] = {
.variant = IMX8Q,
@@ -1937,6 +1959,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
.init_phy = imx95_pcie_init_phy,
.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
.enable_ref_clk = imx95_pcie_enable_ref_clk,
+ .clr_clkreq_override = imx95_pcie_clr_clkreq_override,
},
[IMX8MQ_EP] = {
.variant = IMX8MQ_EP,
--
2.37.1