mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-19 03:15:00 +00:00
ram: stm32mp1: the property st, phy-cal becomes optional
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@st.com> Acked-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
parent
d424e6786f
commit
9368bdfebd
6 changed files with 56 additions and 16 deletions
|
@ -133,6 +133,7 @@
|
||||||
DDR_MR3
|
DDR_MR3
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
#ifdef DDR_PHY_CAL_SKIP
|
||||||
st,phy-cal = <
|
st,phy-cal = <
|
||||||
DDR_DX0DLLCR
|
DDR_DX0DLLCR
|
||||||
DDR_DX0DQTR
|
DDR_DX0DQTR
|
||||||
|
@ -148,6 +149,8 @@
|
||||||
DDR_DX3DQSTR
|
DDR_DX3DQSTR
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -129,6 +129,8 @@ phyc attributes:
|
||||||
MR3
|
MR3
|
||||||
|
|
||||||
- st,phy-cal : phy cal depending of calibration or tuning of DDR
|
- 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
|
for STM32MP15x: 12 values are requested in this order
|
||||||
DX0DLLCR
|
DX0DLLCR
|
||||||
DX0DQTR
|
DX0DQTR
|
||||||
|
|
|
@ -769,7 +769,8 @@ start:
|
||||||
*/
|
*/
|
||||||
set_reg(priv, REGPHY_REG, &config->p_reg);
|
set_reg(priv, REGPHY_REG, &config->p_reg);
|
||||||
set_reg(priv, REGPHY_TIMING, &config->p_timing);
|
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))
|
if (INTERACTIVE(STEP_PHY_INIT))
|
||||||
goto start;
|
goto start;
|
||||||
|
@ -804,13 +805,16 @@ start:
|
||||||
|
|
||||||
wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
|
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
|
/* 8. Disable Auto refresh and power down by setting
|
||||||
* - RFSHCTL3.dis_au_refresh = 1
|
* - RFSHCTL3.dis_au_refresh = 1
|
||||||
* - PWRCTL.powerdown_en = 0
|
* - PWRCTL.powerdown_en = 0
|
||||||
* - DFIMISC.dfiinit_complete_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
|
/* 9. Program PUBL PGCR to enable refresh during training and rank to train
|
||||||
* not done => keep the programed value in PGCR
|
* 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 */
|
/* 10. configure PUBL PIR register to specify which training step to run */
|
||||||
/* warning : RVTRN is not supported by this PUBL */
|
/* 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 */
|
/* 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 */
|
/* 12. set back registers in step 8 to the orginal values if desidered */
|
||||||
stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
|
stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
|
||||||
config->c_reg.pwrctl);
|
config->c_reg.pwrctl);
|
||||||
|
} /* if (config->p_cal_present) */
|
||||||
|
|
||||||
/* enable uMCTL2 AXI port 0 and 1 */
|
/* enable uMCTL2 AXI port 0 and 1 */
|
||||||
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
|
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
|
||||||
|
|
|
@ -170,6 +170,7 @@ struct stm32mp1_ddr_config {
|
||||||
struct stm32mp1_ddrphy_reg p_reg;
|
struct stm32mp1_ddrphy_reg p_reg;
|
||||||
struct stm32mp1_ddrphy_timing p_timing;
|
struct stm32mp1_ddrphy_timing p_timing;
|
||||||
struct stm32mp1_ddrphy_cal p_cal;
|
struct stm32mp1_ddrphy_cal p_cal;
|
||||||
|
bool p_cal_present;
|
||||||
};
|
};
|
||||||
|
|
||||||
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
|
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
|
||||||
|
|
|
@ -106,7 +106,7 @@ static void stm32mp1_do_usage(void)
|
||||||
"help displays help\n"
|
"help displays help\n"
|
||||||
"info displays DDR information\n"
|
"info displays DDR information\n"
|
||||||
"info <param> <val> changes 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 displays the DDR PHY frequency in kHz\n"
|
||||||
"freq <freq> changes the DDR PHY frequency\n"
|
"freq <freq> changes the DDR PHY frequency\n"
|
||||||
"param [type|reg] prints input parameters\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("name = %s\n", config->info.name);
|
||||||
printf("size = 0x%x\n", config->info.size);
|
printf("size = 0x%x\n", config->info.size);
|
||||||
printf("speed = %d kHz\n", config->info.speed);
|
printf("speed = %d kHz\n", config->info.speed);
|
||||||
|
printf("cal = %d\n", config->p_cal_present);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +209,16 @@ static void stm32mp1_do_info(struct ddr_info *priv,
|
||||||
}
|
}
|
||||||
return;
|
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]);
|
printf("argument %s invalid\n", argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,18 +65,22 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
|
||||||
struct clk axidcg;
|
struct clk axidcg;
|
||||||
struct stm32mp1_ddr_config config;
|
struct stm32mp1_ddr_config config;
|
||||||
|
|
||||||
#define PARAM(x, y) \
|
#define PARAM(x, y, z) \
|
||||||
{ x,\
|
{ .name = x, \
|
||||||
offsetof(struct stm32mp1_ddr_config, y),\
|
.offset = offsetof(struct stm32mp1_ddr_config, y), \
|
||||||
sizeof(config.y) / sizeof(u32)}
|
.size = sizeof(config.y) / sizeof(u32), \
|
||||||
|
.present = z, \
|
||||||
|
}
|
||||||
|
|
||||||
#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
|
#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
|
||||||
#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
|
#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 struct {
|
||||||
const char *name; /* name in DT */
|
const char *name; /* name in DT */
|
||||||
const u32 offset; /* offset in config struct */
|
const u32 offset; /* offset in config struct */
|
||||||
const u32 size; /* size of parameters */
|
const u32 size; /* size of parameters */
|
||||||
|
bool * const present; /* presence indication for opt */
|
||||||
} param[] = {
|
} param[] = {
|
||||||
CTL_PARAM(reg),
|
CTL_PARAM(reg),
|
||||||
CTL_PARAM(timing),
|
CTL_PARAM(timing),
|
||||||
|
@ -84,7 +88,7 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
|
||||||
CTL_PARAM(perf),
|
CTL_PARAM(perf),
|
||||||
PHY_PARAM(reg),
|
PHY_PARAM(reg),
|
||||||
PHY_PARAM(timing),
|
PHY_PARAM(timing),
|
||||||
PHY_PARAM(cal)
|
PHY_PARAM_OPT(cal)
|
||||||
};
|
};
|
||||||
|
|
||||||
config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
|
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);
|
param[idx].size);
|
||||||
debug("%s: %s[0x%x] = %d\n", __func__,
|
debug("%s: %s[0x%x] = %d\n", __func__,
|
||||||
param[idx].name, param[idx].size, ret);
|
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",
|
pr_err("%s: Cannot read %s, error=%d\n",
|
||||||
__func__, param[idx].name, ret);
|
__func__, param[idx].name, ret);
|
||||||
return -EINVAL;
|
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);
|
ret = clk_get_by_name(dev, "axidcg", &axidcg);
|
||||||
|
|
Loading…
Add table
Reference in a new issue