diff mbox series

[9/9] ram: stm32mp1: the property st,phy-cal becomes optional

Message ID 20200306101412.15376-2-patrick.delaunay@st.com
State Accepted
Commit 9368bdfebde16368cdb642adbb12f9c871c94d63
Headers show
Series ram: stm32mp1: fixes | expand

Commit Message

Patrick Delaunay March 6, 2020, 10:14 a.m. UTC
This parameter "st,phy-cal" becomes optional and when it is
absent the built-in PHY calibration is done.

It is the case in the helper dtsi file "stm32mp15-ddr.dtsi"
except if DDR_PHY_CAL_SKIP is defined.

This patch also impact the ddr interactive mode
- the registers of the param 'phy.cal' are initialized to 0 when
  "st,phy-cal" is not present in device tree (default behavior when
  DDR_PHY_CAL_SKIP is not activated)
- the info 'cal' field can be use to change the calibration behavior
  - cal=1 => use param phy.cal to initialize the PHY, built-in training
             is skipped
  - cal=0 => param phy.cal is absent, built-in training is used (default)

Signed-off-by: Patrick Delaunay <patrick.delaunay at st.com>
---

 arch/arm/dts/stm32mp15-ddr.dtsi               |  3 ++
 .../memory-controllers/st,stm32mp1-ddr.txt    |  2 ++
 drivers/ram/stm32mp1/stm32mp1_ddr.c           | 19 +++++++----
 drivers/ram/stm32mp1/stm32mp1_ddr.h           |  1 +
 drivers/ram/stm32mp1/stm32mp1_interactive.c   | 13 ++++++-
 drivers/ram/stm32mp1/stm32mp1_ram.c           | 34 ++++++++++++++-----
 6 files changed, 56 insertions(+), 16 deletions(-)

Comments

Patrice CHOTARD March 18, 2020, 9:52 a.m. UTC | #1
On 3/6/20 11:14 AM, Patrick Delaunay wrote:
> This parameter "st,phy-cal" becomes optional and when it is
> absent the built-in PHY calibration is done.
>
> It is the case in the helper dtsi file "stm32mp15-ddr.dtsi"
> except if DDR_PHY_CAL_SKIP is defined.
>
> This patch also impact the ddr interactive mode
> - the registers of the param 'phy.cal' are initialized to 0 when
>   "st,phy-cal" is not present in device tree (default behavior when
>   DDR_PHY_CAL_SKIP is not activated)
> - the info 'cal' field can be use to change the calibration behavior
>   - cal=1 => use param phy.cal to initialize the PHY, built-in training
>              is skipped
>   - cal=0 => param phy.cal is absent, built-in training is used (default)
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay at st.com>
> ---
>
>  arch/arm/dts/stm32mp15-ddr.dtsi               |  3 ++
>  .../memory-controllers/st,stm32mp1-ddr.txt    |  2 ++
>  drivers/ram/stm32mp1/stm32mp1_ddr.c           | 19 +++++++----
>  drivers/ram/stm32mp1/stm32mp1_ddr.h           |  1 +
>  drivers/ram/stm32mp1/stm32mp1_interactive.c   | 13 ++++++-
>  drivers/ram/stm32mp1/stm32mp1_ram.c           | 34 ++++++++++++++-----
>  6 files changed, 56 insertions(+), 16 deletions(-)
>
> diff --git a/arch/arm/dts/stm32mp15-ddr.dtsi b/arch/arm/dts/stm32mp15-ddr.dtsi
> index 38f29bb789..8b20b5e173 100644
> --- a/arch/arm/dts/stm32mp15-ddr.dtsi
> +++ b/arch/arm/dts/stm32mp15-ddr.dtsi
> @@ -133,6 +133,7 @@
>  				DDR_MR3
>  			>;
>  
> +#ifdef DDR_PHY_CAL_SKIP
>  			st,phy-cal = <
>  				DDR_DX0DLLCR
>  				DDR_DX0DQTR
> @@ -148,6 +149,8 @@
>  				DDR_DX3DQSTR
>  			>;
>  
> +#endif
> +
>  			status = "okay";
>  		};
>  	};
> diff --git a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
> index ee708ce92c..ac6a7df432 100644
> --- a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
> +++ b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
> @@ -129,6 +129,8 @@ phyc attributes:
>  		MR3
>  
>  - st,phy-cal	: phy cal depending of calibration or tuning of DDR
> +	This parameter is optional; when it is absent the built-in PHY
> +	calibration is done.
>  	for STM32MP15x: 12 values are requested in this order
>  		DX0DLLCR
>  		DX0DQTR
> diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
> index b9300dd6d1..11b14ae652 100644
> --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
> +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
> @@ -769,7 +769,8 @@ start:
>   */
>  	set_reg(priv, REGPHY_REG, &config->p_reg);
>  	set_reg(priv, REGPHY_TIMING, &config->p_timing);
> -	set_reg(priv, REGPHY_CAL, &config->p_cal);
> +	if (config->p_cal_present)
> +		set_reg(priv, REGPHY_CAL, &config->p_cal);
>  
>  	if (INTERACTIVE(STEP_PHY_INIT))
>  		goto start;
> @@ -804,13 +805,16 @@ start:
>  
>  	wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
>  
> -	debug("DDR DQS training : ");
> +	if (config->p_cal_present) {
> +		debug("DDR DQS training skipped.\n");
> +	} else {
> +		debug("DDR DQS training : ");
>  /*  8. Disable Auto refresh and power down by setting
>   *    - RFSHCTL3.dis_au_refresh = 1
>   *    - PWRCTL.powerdown_en = 0
>   *    - DFIMISC.dfiinit_complete_en = 0
>   */
> -	stm32mp1_refresh_disable(priv->ctl);
> +		stm32mp1_refresh_disable(priv->ctl);
>  
>  /*  9. Program PUBL PGCR to enable refresh during training and rank to train
>   *     not done => keep the programed value in PGCR
> @@ -818,14 +822,15 @@ start:
>  
>  /* 10. configure PUBL PIR register to specify which training step to run */
>  	/* warning : RVTRN  is not supported by this PUBL */
> -	stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
> +		stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
>  
>  /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
> -	ddrphy_idone_wait(priv->phy);
> +		ddrphy_idone_wait(priv->phy);
>  
>  /* 12. set back registers in step 8 to the orginal values if desidered */
> -	stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
> -				 config->c_reg.pwrctl);
> +		stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
> +					 config->c_reg.pwrctl);
> +	} /* if (config->p_cal_present) */
>  
>  	/* enable uMCTL2 AXI port 0 and 1 */
>  	setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
> diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
> index 52b748f3ca..4998f04439 100644
> --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
> +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
> @@ -170,6 +170,7 @@ struct stm32mp1_ddr_config {
>  	struct stm32mp1_ddrphy_reg p_reg;
>  	struct stm32mp1_ddrphy_timing p_timing;
>  	struct stm32mp1_ddrphy_cal p_cal;
> +	bool p_cal_present;
>  };
>  
>  int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
> diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
> index cedf92cb5f..805c9ddaad 100644
> --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
> +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
> @@ -106,7 +106,7 @@ static void stm32mp1_do_usage(void)
>  		"help                       displays help\n"
>  		"info                       displays DDR information\n"
>  		"info  <param> <val>        changes DDR information\n"
> -		"      with <param> = step, name, size or speed\n"
> +		"      with <param> = step, name, size, speed or cal\n"
>  		"freq                       displays the DDR PHY frequency in kHz\n"
>  		"freq  <freq>               changes the DDR PHY frequency\n"
>  		"param [type|reg]           prints input parameters\n"
> @@ -160,6 +160,7 @@ static void stm32mp1_do_info(struct ddr_info *priv,
>  		printf("name = %s\n", config->info.name);
>  		printf("size = 0x%x\n", config->info.size);
>  		printf("speed = %d kHz\n", config->info.speed);
> +		printf("cal = %d\n", config->p_cal_present);
>  		return;
>  	}
>  
> @@ -208,6 +209,16 @@ static void stm32mp1_do_info(struct ddr_info *priv,
>  		}
>  		return;
>  	}
> +	if (!strcmp(argv[1], "cal")) {
> +		if (strict_strtoul(argv[2], 10, &value) < 0 ||
> +		    (value != 0 && value != 1)) {
> +			printf("invalid value %s\n", argv[2]);
> +		} else {
> +			config->p_cal_present = value;
> +			printf("cal = %d\n", config->p_cal_present);
> +		}
> +		return;
> +	}
>  	printf("argument %s invalid\n", argv[1]);
>  }
>  
> diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
> index eb78f1198d..b1e593f86b 100644
> --- a/drivers/ram/stm32mp1/stm32mp1_ram.c
> +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
> @@ -65,18 +65,22 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
>  	struct clk axidcg;
>  	struct stm32mp1_ddr_config config;
>  
> -#define PARAM(x, y) \
> -	{ x,\
> -	  offsetof(struct stm32mp1_ddr_config, y),\
> -	  sizeof(config.y) / sizeof(u32)}
> +#define PARAM(x, y, z)							\
> +	{	.name = x,						\
> +		.offset = offsetof(struct stm32mp1_ddr_config, y),	\
> +		.size = sizeof(config.y) / sizeof(u32),			\
> +		.present = z,						\
> +	}
>  
> -#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
> -#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
> +#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
> +#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
> +#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
>  
>  	const struct {
>  		const char *name; /* name in DT */
>  		const u32 offset; /* offset in config struct */
>  		const u32 size;   /* size of parameters */
> +		bool * const present;  /* presence indication for opt */
>  	} param[] = {
>  		CTL_PARAM(reg),
>  		CTL_PARAM(timing),
> @@ -84,7 +88,7 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
>  		CTL_PARAM(perf),
>  		PHY_PARAM(reg),
>  		PHY_PARAM(timing),
> -		PHY_PARAM(cal)
> +		PHY_PARAM_OPT(cal)
>  	};
>  
>  	config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
> @@ -103,11 +107,25 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
>  					 param[idx].size);
>  		debug("%s: %s[0x%x] = %d\n", __func__,
>  		      param[idx].name, param[idx].size, ret);
> -		if (ret) {
> +		if (ret &&
> +		    (ret != -FDT_ERR_NOTFOUND || !param[idx].present)) {
>  			pr_err("%s: Cannot read %s, error=%d\n",
>  			       __func__, param[idx].name, ret);
>  			return -EINVAL;
>  		}
> +		if (param[idx].present) {
> +			/* save presence of optional parameters */
> +			*param[idx].present = true;
> +			if (ret == -FDT_ERR_NOTFOUND) {
> +				*param[idx].present = false;
> +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
> +				/* reset values if used later */
> +				memset((void *)((u32)&config +
> +						param[idx].offset),
> +					0, param[idx].size * sizeof(u32));
> +#endif
> +			}
> +		}
>  	}
>  
>  	ret = clk_get_by_name(dev, "axidcg", &axidcg);

Acked-by: Patrice Chotard <patrice.chotard at st.com>

Thanks

Patrice
Patrick Delaunay March 24, 2020, 8:51 a.m. UTC | #2
Hi,

> From: Patrick DELAUNAY <patrick.delaunay at st.com>
> Sent: vendredi 6 mars 2020 11:14
> 
> This parameter "st,phy-cal" becomes optional and when it is absent the built-in
> PHY calibration is done.
> 
> It is the case in the helper dtsi file "stm32mp15-ddr.dtsi"
> except if DDR_PHY_CAL_SKIP is defined.
> 
> This patch also impact the ddr interactive mode
> - the registers of the param 'phy.cal' are initialized to 0 when
>   "st,phy-cal" is not present in device tree (default behavior when
>   DDR_PHY_CAL_SKIP is not activated)
> - the info 'cal' field can be use to change the calibration behavior
>   - cal=1 => use param phy.cal to initialize the PHY, built-in training
>              is skipped
>   - cal=0 => param phy.cal is absent, built-in training is used (default)
> 
> Signed-off-by: Patrick Delaunay <patrick.delaunay at st.com>
> ---

Applied to u-boot-stm/next, thanks!

Regards

Patrick
diff mbox series

Patch

diff --git a/arch/arm/dts/stm32mp15-ddr.dtsi b/arch/arm/dts/stm32mp15-ddr.dtsi
index 38f29bb789..8b20b5e173 100644
--- a/arch/arm/dts/stm32mp15-ddr.dtsi
+++ b/arch/arm/dts/stm32mp15-ddr.dtsi
@@ -133,6 +133,7 @@ 
 				DDR_MR3
 			>;
 
+#ifdef DDR_PHY_CAL_SKIP
 			st,phy-cal = <
 				DDR_DX0DLLCR
 				DDR_DX0DQTR
@@ -148,6 +149,8 @@ 
 				DDR_DX3DQSTR
 			>;
 
+#endif
+
 			status = "okay";
 		};
 	};
diff --git a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
index ee708ce92c..ac6a7df432 100644
--- a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
+++ b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
@@ -129,6 +129,8 @@  phyc attributes:
 		MR3
 
 - st,phy-cal	: phy cal depending of calibration or tuning of DDR
+	This parameter is optional; when it is absent the built-in PHY
+	calibration is done.
 	for STM32MP15x: 12 values are requested in this order
 		DX0DLLCR
 		DX0DQTR
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
index b9300dd6d1..11b14ae652 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -769,7 +769,8 @@  start:
  */
 	set_reg(priv, REGPHY_REG, &config->p_reg);
 	set_reg(priv, REGPHY_TIMING, &config->p_timing);
-	set_reg(priv, REGPHY_CAL, &config->p_cal);
+	if (config->p_cal_present)
+		set_reg(priv, REGPHY_CAL, &config->p_cal);
 
 	if (INTERACTIVE(STEP_PHY_INIT))
 		goto start;
@@ -804,13 +805,16 @@  start:
 
 	wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
 
-	debug("DDR DQS training : ");
+	if (config->p_cal_present) {
+		debug("DDR DQS training skipped.\n");
+	} else {
+		debug("DDR DQS training : ");
 /*  8. Disable Auto refresh and power down by setting
  *    - RFSHCTL3.dis_au_refresh = 1
  *    - PWRCTL.powerdown_en = 0
  *    - DFIMISC.dfiinit_complete_en = 0
  */
-	stm32mp1_refresh_disable(priv->ctl);
+		stm32mp1_refresh_disable(priv->ctl);
 
 /*  9. Program PUBL PGCR to enable refresh during training and rank to train
  *     not done => keep the programed value in PGCR
@@ -818,14 +822,15 @@  start:
 
 /* 10. configure PUBL PIR register to specify which training step to run */
 	/* warning : RVTRN  is not supported by this PUBL */
-	stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+		stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
 
 /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
-	ddrphy_idone_wait(priv->phy);
+		ddrphy_idone_wait(priv->phy);
 
 /* 12. set back registers in step 8 to the orginal values if desidered */
-	stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
-				 config->c_reg.pwrctl);
+		stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+					 config->c_reg.pwrctl);
+	} /* if (config->p_cal_present) */
 
 	/* enable uMCTL2 AXI port 0 and 1 */
 	setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
index 52b748f3ca..4998f04439 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -170,6 +170,7 @@  struct stm32mp1_ddr_config {
 	struct stm32mp1_ddrphy_reg p_reg;
 	struct stm32mp1_ddrphy_timing p_timing;
 	struct stm32mp1_ddrphy_cal p_cal;
+	bool p_cal_present;
 };
 
 int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
index cedf92cb5f..805c9ddaad 100644
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -106,7 +106,7 @@  static void stm32mp1_do_usage(void)
 		"help                       displays help\n"
 		"info                       displays DDR information\n"
 		"info  <param> <val>        changes DDR information\n"
-		"      with <param> = step, name, size or speed\n"
+		"      with <param> = step, name, size, speed or cal\n"
 		"freq                       displays the DDR PHY frequency in kHz\n"
 		"freq  <freq>               changes the DDR PHY frequency\n"
 		"param [type|reg]           prints input parameters\n"
@@ -160,6 +160,7 @@  static void stm32mp1_do_info(struct ddr_info *priv,
 		printf("name = %s\n", config->info.name);
 		printf("size = 0x%x\n", config->info.size);
 		printf("speed = %d kHz\n", config->info.speed);
+		printf("cal = %d\n", config->p_cal_present);
 		return;
 	}
 
@@ -208,6 +209,16 @@  static void stm32mp1_do_info(struct ddr_info *priv,
 		}
 		return;
 	}
+	if (!strcmp(argv[1], "cal")) {
+		if (strict_strtoul(argv[2], 10, &value) < 0 ||
+		    (value != 0 && value != 1)) {
+			printf("invalid value %s\n", argv[2]);
+		} else {
+			config->p_cal_present = value;
+			printf("cal = %d\n", config->p_cal_present);
+		}
+		return;
+	}
 	printf("argument %s invalid\n", argv[1]);
 }
 
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index eb78f1198d..b1e593f86b 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -65,18 +65,22 @@  static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
 	struct clk axidcg;
 	struct stm32mp1_ddr_config config;
 
-#define PARAM(x, y) \
-	{ x,\
-	  offsetof(struct stm32mp1_ddr_config, y),\
-	  sizeof(config.y) / sizeof(u32)}
+#define PARAM(x, y, z)							\
+	{	.name = x,						\
+		.offset = offsetof(struct stm32mp1_ddr_config, y),	\
+		.size = sizeof(config.y) / sizeof(u32),			\
+		.present = z,						\
+	}
 
-#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
-#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
+#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
 
 	const struct {
 		const char *name; /* name in DT */
 		const u32 offset; /* offset in config struct */
 		const u32 size;   /* size of parameters */
+		bool * const present;  /* presence indication for opt */
 	} param[] = {
 		CTL_PARAM(reg),
 		CTL_PARAM(timing),
@@ -84,7 +88,7 @@  static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
 		CTL_PARAM(perf),
 		PHY_PARAM(reg),
 		PHY_PARAM(timing),
-		PHY_PARAM(cal)
+		PHY_PARAM_OPT(cal)
 	};
 
 	config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
@@ -103,11 +107,25 @@  static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
 					 param[idx].size);
 		debug("%s: %s[0x%x] = %d\n", __func__,
 		      param[idx].name, param[idx].size, ret);
-		if (ret) {
+		if (ret &&
+		    (ret != -FDT_ERR_NOTFOUND || !param[idx].present)) {
 			pr_err("%s: Cannot read %s, error=%d\n",
 			       __func__, param[idx].name, ret);
 			return -EINVAL;
 		}
+		if (param[idx].present) {
+			/* save presence of optional parameters */
+			*param[idx].present = true;
+			if (ret == -FDT_ERR_NOTFOUND) {
+				*param[idx].present = false;
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+				/* reset values if used later */
+				memset((void *)((u32)&config +
+						param[idx].offset),
+					0, param[idx].size * sizeof(u32));
+#endif
+			}
+		}
 	}
 
 	ret = clk_get_by_name(dev, "axidcg", &axidcg);