PCI: imx6: Toggle the core reset for i.MX95 PCIe
authorRichard Zhu <hongxing.zhu@nxp.com>
Wed, 16 Apr 2025 08:13:10 +0000 (16:13 +0800)
committerManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Sun, 27 Apr 2025 11:38:50 +0000 (17:08 +0530)
Add toggling core reset for i.MX95 to align with PHY's power-up sequence.
Note that the register is named as IMX95_PCIE_COLD_RST in hardware, though
it is used to reset the PCIe core.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[mani: subject and description rewording]
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20250416081314.3929794-4-hongxing.zhu@nxp.com
drivers/pci/controller/dwc/pci-imx6.c

index c5871c3d4194b3f861da050c9220fe0ccade3cde..7c60b712480ac816a2eeec31fc7bac8630d99720 100644 (file)
@@ -71,6 +71,9 @@
 #define IMX95_SID_MASK                         GENMASK(5, 0)
 #define IMX95_MAX_LUT                          32
 
+#define IMX95_PCIE_RST_CTRL                    0x3010
+#define IMX95_PCIE_COLD_RST                    BIT(0)
+
 #define to_imx_pcie(x) dev_get_drvdata((x)->dev)
 
 enum imx_pcie_variants {
@@ -773,6 +776,43 @@ static int imx7d_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
        return 0;
 }
 
+static int imx95_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
+{
+       u32 val;
+
+       if (assert) {
+               /*
+                * From i.MX95 PCIe PHY perspective, the COLD reset toggle
+                * should be complete after power-up by the following sequence.
+                *                 > 10us(at power-up)
+                *                 > 10ns(warm reset)
+                *               |<------------>|
+                *                ______________
+                * phy_reset ____/              \________________
+                *                                   ____________
+                * ref_clk_en_______________________/
+                * Toggle COLD reset aligned with this sequence for i.MX95 PCIe.
+                */
+               regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
+                               IMX95_PCIE_COLD_RST);
+               /*
+                * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the
+                * hardware by doing a read. Otherwise, there is no guarantee
+                * that the write has reached the hardware before udelay().
+                */
+               regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
+                                    &val);
+               udelay(15);
+               regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
+                                 IMX95_PCIE_COLD_RST);
+               regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
+                                    &val);
+               udelay(10);
+       }
+
+       return 0;
+}
+
 static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie)
 {
        reset_control_assert(imx_pcie->pciephy_reset);
@@ -1739,6 +1779,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
                .ltssm_mask = IMX95_PCIE_LTSSM_EN,
                .mode_off[0]  = IMX95_PE0_GEN_CTRL_1,
                .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
+               .core_reset = imx95_pcie_core_reset,
                .init_phy = imx95_pcie_init_phy,
        },
        [IMX8MQ_EP] = {
@@ -1792,6 +1833,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
                .mode_off[0]  = IMX95_PE0_GEN_CTRL_1,
                .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
                .init_phy = imx95_pcie_init_phy,
+               .core_reset = imx95_pcie_core_reset,
                .epc_features = &imx95_pcie_epc_features,
                .mode = DW_PCIE_EP_TYPE,
        },