PCI: imx6: Save and restore the LUT setting during suspend/resume for i.MX95 SoC
authorRichard Zhu <hongxing.zhu@nxp.com>
Wed, 16 Apr 2025 08:13:14 +0000 (16:13 +0800)
committerManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Sun, 27 Apr 2025 11:49:24 +0000 (17:19 +0530)
The look up table (LUT) setting would be lost during the PCIe suspend on
i.MX95 SoC. So to ensure proper functionality after resume, save it during
suspend and restore it while resuming.

Fixes: 9d6b1bd6b3c8 ("PCI: imx6: Add i.MX8MQ, i.MX8Q and i.MX95 PM support")
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
[mani: subject and description rewording]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Link: https://patch.msgid.link/20250416081314.3929794-8-hongxing.zhu@nxp.com
drivers/pci/controller/dwc/pci-imx6.c

index 4cff667949902980268795681c6e3acf9fabb5f3..5a38cfaf989b1c9606660f2e0bcd10d88fa2d6b1 100644 (file)
@@ -139,6 +139,11 @@ struct imx_pcie_drvdata {
        const struct dw_pcie_host_ops *ops;
 };
 
+struct imx_lut_data {
+       u32 data1;
+       u32 data2;
+};
+
 struct imx_pcie {
        struct dw_pcie          *pci;
        struct gpio_desc        *reset_gpiod;
@@ -158,6 +163,8 @@ struct imx_pcie {
        struct regulator        *vph;
        void __iomem            *phy_base;
 
+       /* LUT data for pcie */
+       struct imx_lut_data     luts[IMX95_MAX_LUT];
        /* power domain for pcie */
        struct device           *pd_pcie;
        /* power domain for pcie phy */
@@ -1484,6 +1491,42 @@ static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save)
        }
 }
 
+static void imx_pcie_lut_save(struct imx_pcie *imx_pcie)
+{
+       u32 data1, data2;
+       int i;
+
+       for (i = 0; i < IMX95_MAX_LUT; i++) {
+               regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL,
+                            IMX95_PEO_LUT_RWA | i);
+               regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, &data1);
+               regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2);
+               if (data1 & IMX95_PE0_LUT_VLD) {
+                       imx_pcie->luts[i].data1 = data1;
+                       imx_pcie->luts[i].data2 = data2;
+               } else {
+                       imx_pcie->luts[i].data1 = 0;
+                       imx_pcie->luts[i].data2 = 0;
+               }
+       }
+}
+
+static void imx_pcie_lut_restore(struct imx_pcie *imx_pcie)
+{
+       int i;
+
+       for (i = 0; i < IMX95_MAX_LUT; i++) {
+               if ((imx_pcie->luts[i].data1 & IMX95_PE0_LUT_VLD) == 0)
+                       continue;
+
+               regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1,
+                            imx_pcie->luts[i].data1);
+               regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2,
+                            imx_pcie->luts[i].data2);
+               regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, i);
+       }
+}
+
 static int imx_pcie_suspend_noirq(struct device *dev)
 {
        struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
@@ -1492,6 +1535,8 @@ static int imx_pcie_suspend_noirq(struct device *dev)
                return 0;
 
        imx_pcie_msi_save_restore(imx_pcie, true);
+       if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
+               imx_pcie_lut_save(imx_pcie);
        if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
                /*
                 * The minimum for a workaround would be to set PERST# and to
@@ -1536,6 +1581,8 @@ static int imx_pcie_resume_noirq(struct device *dev)
                if (ret)
                        return ret;
        }
+       if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
+               imx_pcie_lut_restore(imx_pcie);
        imx_pcie_msi_save_restore(imx_pcie, false);
 
        return 0;