diff mbox series

phy: xilinx: phy-zynqmp: Fix SGMII linkup failure on resume

Message ID 1721155263-2913528-1-git-send-email-radhey.shyam.pandey@amd.com (mailing list archive)
State New, archived
Headers show
Series phy: xilinx: phy-zynqmp: Fix SGMII linkup failure on resume | expand

Commit Message

Radhey Shyam Pandey July 16, 2024, 6:41 p.m. UTC
From: Piyush Mehta <piyush.mehta@amd.com>

On a few Kria KR260 Robotics Starter Kit the PS-GEM SGMII linkup is not
happening after the resume. This is because serdes registers are reset
when FPD is off (in suspend state) and needs to be reprogrammed in the
resume path with the same default initialization as done in the first
stage bootloader psu_init routine.

To address the failure introduce a set of serdes registers to be saved in
the suspend path and then restore it on resume.

Signed-off-by: Piyush Mehta <piyush.mehta@amd.com>
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
 drivers/phy/xilinx/phy-zynqmp.c | 56 +++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)


base-commit: d67978318827d06f1c0fa4c31343a279e9df6fde

Comments

Vinod Koul Aug. 4, 2024, 5:20 p.m. UTC | #1
On 17-07-24, 00:11, Radhey Shyam Pandey wrote:
> From: Piyush Mehta <piyush.mehta@amd.com>
> 
> On a few Kria KR260 Robotics Starter Kit the PS-GEM SGMII linkup is not
> happening after the resume. This is because serdes registers are reset
> when FPD is off (in suspend state) and needs to be reprogrammed in the
> resume path with the same default initialization as done in the first
> stage bootloader psu_init routine.
> 
> To address the failure introduce a set of serdes registers to be saved in
> the suspend path and then restore it on resume.
> 
> Signed-off-by: Piyush Mehta <piyush.mehta@amd.com>
> Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
> ---
>  drivers/phy/xilinx/phy-zynqmp.c | 56 +++++++++++++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 
> diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
> index dc8319bda43d..bdcc8d7c3dfa 100644
> --- a/drivers/phy/xilinx/phy-zynqmp.c
> +++ b/drivers/phy/xilinx/phy-zynqmp.c
> @@ -165,6 +165,24 @@
>  /* Timeout values */
>  #define TIMEOUT_US			1000
>  
> +/* Lane 0/1/2/3 offset */
> +#define DIG_8(n)		((0x4000 * (n)) + 0x1074)
> +#define ILL13(n)		((0x4000 * (n)) + 0x1994)
> +#define DIG_10(n)		((0x4000 * (n)) + 0x107C)
> +#define RST_DLY(n)		((0x4000 * (n)) + 0x19A4)
> +#define BYP_15(n)		((0x4000 * (n)) + 0x1038)
> +#define BYP_12(n)		((0x4000 * (n)) + 0x102C)
> +#define MISC3(n)		((0x4000 * (n)) + 0x19AC)
> +#define EQ11(n)			((0x4000 * (n)) + 0x1978)

Lower case hex value please

> +
> +static u32 save_reg_address[] = {
> +	/* Lane 0/1/2/3 Register */
> +	DIG_8(0), ILL13(0), DIG_10(0), RST_DLY(0), BYP_15(0), BYP_12(0), MISC3(0), EQ11(0),
> +	DIG_8(1), ILL13(1), DIG_10(1), RST_DLY(1), BYP_15(1), BYP_12(1), MISC3(1), EQ11(1),
> +	DIG_8(2), ILL13(2), DIG_10(2), RST_DLY(2), BYP_15(2), BYP_12(2), MISC3(2), EQ11(2),
> +	DIG_8(3), ILL13(3), DIG_10(3), RST_DLY(3), BYP_15(3), BYP_12(3), MISC3(3), EQ11(3),
> +};
> +
>  struct xpsgtr_dev;
>  
>  /**
> @@ -213,6 +231,7 @@ struct xpsgtr_phy {
>   * @tx_term_fix: fix for GT issue
>   * @saved_icm_cfg0: stored value of ICM CFG0 register
>   * @saved_icm_cfg1: stored value of ICM CFG1 register
> + * @saved_regs: registers to be saved/restored during suspend/resume
>   */
>  struct xpsgtr_dev {
>  	struct device *dev;
> @@ -225,6 +244,7 @@ struct xpsgtr_dev {
>  	bool tx_term_fix;
>  	unsigned int saved_icm_cfg0;
>  	unsigned int saved_icm_cfg1;
> +	u32 *saved_regs;
>  };
>  
>  /*
> @@ -298,6 +318,32 @@ static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
>  	writel((readl(addr) & ~clr) | set, addr);
>  }
>  
> +/**
> + * xpsgtr_save_lane_regs - Saves registers on suspend
> + * @gtr_dev: pointer to phy controller context structure
> + */
> +static void xpsgtr_save_lane_regs(struct xpsgtr_dev *gtr_dev)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
> +		gtr_dev->saved_regs[i] = xpsgtr_read(gtr_dev,
> +						     save_reg_address[i]);
> +}
> +
> +/**
> + * xpsgtr_restore_lane_regs - Restores registers on resume
> + * @gtr_dev: pointer to phy controller context structure
> + */
> +static void xpsgtr_restore_lane_regs(struct xpsgtr_dev *gtr_dev)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
> +		xpsgtr_write(gtr_dev, save_reg_address[i],
> +			     gtr_dev->saved_regs[i]);
> +}
> +
>  /*
>   * Hardware Configuration
>   */
> @@ -837,6 +883,8 @@ static int xpsgtr_runtime_suspend(struct device *dev)
>  	gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
>  	gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
>  
> +	xpsgtr_save_lane_regs(gtr_dev);
> +
>  	return 0;
>  }
>  
> @@ -847,6 +895,8 @@ static int xpsgtr_runtime_resume(struct device *dev)
>  	unsigned int i;
>  	bool skip_phy_init;
>  
> +	xpsgtr_restore_lane_regs(gtr_dev);
> +
>  	icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
>  	icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
>  
> @@ -992,6 +1042,12 @@ static int xpsgtr_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
> +					   sizeof(save_reg_address),
> +					   GFP_KERNEL);
> +	if (!gtr_dev->saved_regs)
> +		return -ENOMEM;
> +
>  	return 0;
>  }
>  
> 
> base-commit: d67978318827d06f1c0fa4c31343a279e9df6fde
> -- 
> 2.34.1
diff mbox series

Patch

diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index dc8319bda43d..bdcc8d7c3dfa 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -165,6 +165,24 @@ 
 /* Timeout values */
 #define TIMEOUT_US			1000
 
+/* Lane 0/1/2/3 offset */
+#define DIG_8(n)		((0x4000 * (n)) + 0x1074)
+#define ILL13(n)		((0x4000 * (n)) + 0x1994)
+#define DIG_10(n)		((0x4000 * (n)) + 0x107C)
+#define RST_DLY(n)		((0x4000 * (n)) + 0x19A4)
+#define BYP_15(n)		((0x4000 * (n)) + 0x1038)
+#define BYP_12(n)		((0x4000 * (n)) + 0x102C)
+#define MISC3(n)		((0x4000 * (n)) + 0x19AC)
+#define EQ11(n)			((0x4000 * (n)) + 0x1978)
+
+static u32 save_reg_address[] = {
+	/* Lane 0/1/2/3 Register */
+	DIG_8(0), ILL13(0), DIG_10(0), RST_DLY(0), BYP_15(0), BYP_12(0), MISC3(0), EQ11(0),
+	DIG_8(1), ILL13(1), DIG_10(1), RST_DLY(1), BYP_15(1), BYP_12(1), MISC3(1), EQ11(1),
+	DIG_8(2), ILL13(2), DIG_10(2), RST_DLY(2), BYP_15(2), BYP_12(2), MISC3(2), EQ11(2),
+	DIG_8(3), ILL13(3), DIG_10(3), RST_DLY(3), BYP_15(3), BYP_12(3), MISC3(3), EQ11(3),
+};
+
 struct xpsgtr_dev;
 
 /**
@@ -213,6 +231,7 @@  struct xpsgtr_phy {
  * @tx_term_fix: fix for GT issue
  * @saved_icm_cfg0: stored value of ICM CFG0 register
  * @saved_icm_cfg1: stored value of ICM CFG1 register
+ * @saved_regs: registers to be saved/restored during suspend/resume
  */
 struct xpsgtr_dev {
 	struct device *dev;
@@ -225,6 +244,7 @@  struct xpsgtr_dev {
 	bool tx_term_fix;
 	unsigned int saved_icm_cfg0;
 	unsigned int saved_icm_cfg1;
+	u32 *saved_regs;
 };
 
 /*
@@ -298,6 +318,32 @@  static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
 	writel((readl(addr) & ~clr) | set, addr);
 }
 
+/**
+ * xpsgtr_save_lane_regs - Saves registers on suspend
+ * @gtr_dev: pointer to phy controller context structure
+ */
+static void xpsgtr_save_lane_regs(struct xpsgtr_dev *gtr_dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
+		gtr_dev->saved_regs[i] = xpsgtr_read(gtr_dev,
+						     save_reg_address[i]);
+}
+
+/**
+ * xpsgtr_restore_lane_regs - Restores registers on resume
+ * @gtr_dev: pointer to phy controller context structure
+ */
+static void xpsgtr_restore_lane_regs(struct xpsgtr_dev *gtr_dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
+		xpsgtr_write(gtr_dev, save_reg_address[i],
+			     gtr_dev->saved_regs[i]);
+}
+
 /*
  * Hardware Configuration
  */
@@ -837,6 +883,8 @@  static int xpsgtr_runtime_suspend(struct device *dev)
 	gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
 	gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
 
+	xpsgtr_save_lane_regs(gtr_dev);
+
 	return 0;
 }
 
@@ -847,6 +895,8 @@  static int xpsgtr_runtime_resume(struct device *dev)
 	unsigned int i;
 	bool skip_phy_init;
 
+	xpsgtr_restore_lane_regs(gtr_dev);
+
 	icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
 	icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
 
@@ -992,6 +1042,12 @@  static int xpsgtr_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
+					   sizeof(save_reg_address),
+					   GFP_KERNEL);
+	if (!gtr_dev->saved_regs)
+		return -ENOMEM;
+
 	return 0;
 }