]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: imx6: Clear CLKREQ# override if 'supports-clkreq' DT property is available
authorRichard Zhu <hongxing.zhu@nxp.com>
Tue, 6 Jan 2026 11:49:19 +0000 (17:19 +0530)
committerManivannan Sadhasivam <mani@kernel.org>
Wed, 21 Jan 2026 07:39:48 +0000 (13:09 +0530)
CLKREQ# is an optional reference clock request signal defined by the PCIe
CEM and M.2 specifications to request REFCLK and exit the L1 Substates. The
imx6 controller driver so far forced the CLKREQ# signal to low by enabling
the CLKREQ# override logic as the slots do not expose this signal.

Now, there are board designs coming up exposing this signal to the endpoint
devices. This is identified using the 'supports-clkreq' DT property in the
controller node.

So when the DT node has this property, clear the CLKREQ# override after
link up in host_post_init() callback to allow the endpoint to drive the
CLKREQ# signal.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
[mani: squashed the imx8mm_pcie_clkreq_override helper patch & reworded description]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
drivers/pci/controller/dwc/pci-imx6.c

index e523cc08c6d9b42db64ace642e27f412ebfd0ddf..1d8677d7de048f1a4e9a71c4483592e6d80e6347 100644 (file)
@@ -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;
        bool                    enable_ext_refclk;
        struct regmap           *iomuxc_gpr;
        u16                     msi_ctrl;
@@ -689,7 +691,7 @@ static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
        return 0;
 }
 
-static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
+static void imx8mm_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable)
 {
        int offset = imx_pcie_grp_offset(imx_pcie);
 
@@ -699,6 +701,11 @@ static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
        regmap_update_bits(imx_pcie->iomuxc_gpr, offset,
                           IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
                           enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0);
+}
+
+static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
+{
+       imx8mm_pcie_clkreq_override(imx_pcie, enable);
        return 0;
 }
 
@@ -726,6 +733,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;
@@ -1342,6 +1359,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 +1786,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 +1920,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 +1931,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 +1942,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 +1964,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,