Message ID | 20200306101412.15376-2-patrick.delaunay@st.com |
---|---|
State | Accepted |
Commit | 9368bdfebde16368cdb642adbb12f9c871c94d63 |
Headers | show |
Series | ram: stm32mp1: fixes | expand |
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
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 --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);
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(-)