diff mbox series

[v1,5/5] PCI: imx6: Save and restore the LUT setting for i.MX95 PCIe

Message ID 20250324062647.1891896-6-hongxing.zhu@nxp.com (mailing list archive)
State Superseded
Delegated to: Krzysztof WilczyƄski
Headers show
Series Add some enhancements for i.MX95 PCIe | expand

Commit Message

Richard Zhu March 24, 2025, 6:26 a.m. UTC
LUT(look up table) setting would be lost during PCIe suspend on i.MX95.

To let i.MX95 PCIe PM work fine, save and restore the LUT setting in
suspend and resume operations.

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

Comments

Frank Li March 24, 2025, 7:22 p.m. UTC | #1
On Mon, Mar 24, 2025 at 02:26:47PM +0800, Richard Zhu wrote:
> LUT(look up table) setting would be lost during PCIe suspend on i.MX95.
>
> To let i.MX95 PCIe PM work fine, save and restore the LUT setting in
> suspend and resume operations.
>
> Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> ---
>  drivers/pci/controller/dwc/pci-imx6.c | 46 +++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> index dda3eed99bb8..a3a032cbaa3c 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c
> @@ -135,6 +135,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;
> @@ -154,6 +159,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 */
> @@ -1468,6 +1475,41 @@ static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save)
>  	}
>  }
>
> +static void imx_pcie_lut_save_restore(struct imx_pcie *imx_pcie, bool save)
> +{
> +	int i;
> +	u32 data1, data2;

Reverse Christmas order.

> +
> +	for (i = 0; i < IMX95_MAX_LUT; i++) {
> +		if (save) {
> +			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;
> +			}

Almost no shared part between save and restore. Suggest use two helper
function imx_pcie_lut_save() and imx_pcie_lut_restore().

Frank

> +		} else {
> +			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);
> @@ -1476,6 +1518,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_restore(imx_pcie, true);
>  	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
>  		/*
>  		 * The minimum for a workaround would be to set PERST# and to
> @@ -1520,6 +1564,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_save_restore(imx_pcie, false);
>  	imx_pcie_msi_save_restore(imx_pcie, false);
>
>  	return 0;
> --
> 2.37.1
>
diff mbox series

Patch

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index dda3eed99bb8..a3a032cbaa3c 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -135,6 +135,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;
@@ -154,6 +159,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 */
@@ -1468,6 +1475,41 @@  static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save)
 	}
 }
 
+static void imx_pcie_lut_save_restore(struct imx_pcie *imx_pcie, bool save)
+{
+	int i;
+	u32 data1, data2;
+
+	for (i = 0; i < IMX95_MAX_LUT; i++) {
+		if (save) {
+			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;
+			}
+		} else {
+			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);
@@ -1476,6 +1518,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_restore(imx_pcie, true);
 	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
 		/*
 		 * The minimum for a workaround would be to set PERST# and to
@@ -1520,6 +1564,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_save_restore(imx_pcie, false);
 	imx_pcie_msi_save_restore(imx_pcie, false);
 
 	return 0;