From patchwork Fri Mar 6 10:14:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243290 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:03 +0100 Subject: [PATCH 1/9] ram: stm32mp1: increase vdd2_ddr: buck2 for 32bits LPDDR In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.1.Ifeb02af238a2e3d0407465a868761e5efd7f968b@changeid> Need to increase the LPDDR2/LPDDR3 the voltage vdd2_ddr: buck2 form 1.2V to 1.25V for 32bits configuration. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- arch/arm/mach-stm32mp/include/mach/ddr.h | 6 +++-- board/st/stm32mp1/board.c | 23 ++++++++++++++---- drivers/ram/stm32mp1/stm32mp1_ddr.c | 30 ++++++++++++++++++++---- include/power/stpmic1.h | 1 + 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/ddr.h b/arch/arm/mach-stm32mp/include/mach/ddr.h index b8a17cfbdd..bfc42a7c48 100644 --- a/arch/arm/mach-stm32mp/include/mach/ddr.h +++ b/arch/arm/mach-stm32mp/include/mach/ddr.h @@ -9,8 +9,10 @@ /* DDR power initializations */ enum ddr_type { STM32MP_DDR3, - STM32MP_LPDDR2, - STM32MP_LPDDR3, + STM32MP_LPDDR2_16, + STM32MP_LPDDR2_32, + STM32MP_LPDDR3_16, + STM32MP_LPDDR3_32, }; int board_ddr_power_init(enum ddr_type ddr_type); diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index c3d832f584..4e35d36c76 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -43,6 +43,7 @@ int board_ddr_power_init(enum ddr_type ddr_type) struct udevice *dev; bool buck3_at_1800000v = false; int ret; + u32 buck2; ret = uclass_get_device_by_driver(UCLASS_PMIC, DM_GET_DRIVER(pmic_stpmic1), &dev); @@ -102,8 +103,10 @@ int board_ddr_power_init(enum ddr_type ddr_type) break; - case STM32MP_LPDDR2: - case STM32MP_LPDDR3: + case STM32MP_LPDDR2_16: + case STM32MP_LPDDR2_32: + case STM32MP_LPDDR3_16: + case STM32MP_LPDDR3_32: /* * configure VDD_DDR1 = LDO3 * Set LDO3 to 1.8V @@ -133,11 +136,23 @@ int board_ddr_power_init(enum ddr_type ddr_type) if (ret < 0) return ret; - /* VDD_DDR2 : Set BUCK2 to 1.2V */ + /* VDD_DDR2 : Set BUCK2 to 1.2V (16bits) or 1.25V (32 bits)*/ + switch (ddr_type) { + case STM32MP_LPDDR2_32: + case STM32MP_LPDDR3_32: + buck2 = STPMIC1_BUCK2_1250000V; + break; + default: + case STM32MP_LPDDR2_16: + case STM32MP_LPDDR3_16: + buck2 = STPMIC1_BUCK2_1200000V; + break; + } + ret = pmic_clrsetbits(dev, STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), STPMIC1_BUCK_VOUT_MASK, - STPMIC1_BUCK2_1200000V); + buck2); if (ret < 0) return ret; diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index d765a46f7c..a87914f2d5 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -668,14 +668,34 @@ void stm32mp1_ddr_init(struct ddr_info *priv, { u32 pir; int ret = -EINVAL; + char bus_width; + + switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { + case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER: + bus_width = 8; + break; + case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: + bus_width = 16; + break; + default: + bus_width = 32; + break; + } + if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) ret = board_ddr_power_init(STM32MP_DDR3); - else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) - ret = board_ddr_power_init(STM32MP_LPDDR2); - else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) - ret = board_ddr_power_init(STM32MP_LPDDR3); - + else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) { + if (bus_width == 32) + ret = board_ddr_power_init(STM32MP_LPDDR2_32); + else + ret = board_ddr_power_init(STM32MP_LPDDR2_16); + } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) { + if (bus_width == 32) + ret = board_ddr_power_init(STM32MP_LPDDR3_32); + else + ret = board_ddr_power_init(STM32MP_LPDDR3_16); + } if (ret) panic("ddr power init failed\n"); diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h index dc8b5a7459..1493a677f0 100644 --- a/include/power/stpmic1.h +++ b/include/power/stpmic1.h @@ -37,6 +37,7 @@ #define STPMIC1_BUCK_VOUT(sel) (sel << STPMIC1_BUCK_VOUT_SHIFT) #define STPMIC1_BUCK2_1200000V STPMIC1_BUCK_VOUT(24) +#define STPMIC1_BUCK2_1250000V STPMIC1_BUCK_VOUT(26) #define STPMIC1_BUCK2_1350000V STPMIC1_BUCK_VOUT(30) #define STPMIC1_BUCK3_1800000V STPMIC1_BUCK_VOUT(39) From patchwork Fri Mar 6 10:14:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243291 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:04 +0100 Subject: [PATCH 2/9] ram: stm32mp1: display result for software read DQS gating In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.2.I7aa349c91deffa4a6f096fbadfa22b01844a7c4d@changeid> Display result information for software read DQS gating, the tuning 0 which be used by CubeMX DDR tuning tools. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 4e1c1fab54..e3e6f0f79c 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1182,15 +1182,17 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]); pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n"); - set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]); - set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]); } } else { /* if intermitant, restore defaut values */ pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n"); - set_r0dgsl_delay(phy, byte, 0); - set_r0dgps_delay(phy, byte, 2); + dqs_gate_values[byte][0] = 0; + dqs_gate_values[byte][1] = 2; } + set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]); + set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]); + printf("Byte %d, R0DGSL = %d, R0DGPS = %d\n", + byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]); /* return 0 if intermittent or if both left_bound * and right_bound are not found From patchwork Fri Mar 6 10:14:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243292 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:05 +0100 Subject: [PATCH 3/9] ram: stm32mp1: don't display the prompt two times In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.3.I6004c77337da88fcc073b421245687c3f74b30a8@changeid> Remove one "DDR>" display on command - next - step - go Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_interactive.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index cc9b2e7c96..cedf92cb5f 100644 --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -367,7 +367,6 @@ bool stm32mp1_ddr_interactive(void *priv, enum stm32mp1_ddr_interact_step step, const struct stm32mp1_ddr_config *config) { - const char *prompt = "DDR>"; char buffer[CONFIG_SYS_CBSIZE]; char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ int argc; @@ -403,13 +402,12 @@ bool stm32mp1_ddr_interactive(void *priv, } printf("%d:%s\n", step, step_str[step]); - printf("%s\n", prompt); if (next_step > step) return false; while (next_step == step) { - cli_readline_into_buffer(prompt, buffer, 0); + cli_readline_into_buffer("DDR>", buffer, 0); argc = cli_simple_parse_line(buffer, argv); if (!argc) continue; From patchwork Fri Mar 6 10:14:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243295 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:06 +0100 Subject: [PATCH 4/9] ram: stm32mp1: tuning: add timeout for polling BISTGSR.BDDONE In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.4.If03eb32f9863bed008f5367b47116f667bb85099@changeid> Avoid to block the tuning procedure on BIST error (not finished BIST procedure) by adding a 1000us timeout on the polling of BISTGSR.BDDONE executed to detect the end of BIST. The normal duration of the BIST test is around 5us. This patch also cleanup comments. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 45 ++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index e3e6f0f79c..cab6cf087a 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "stm32mp1_ddr_regs.h" #include "stm32mp1_ddr.h" @@ -246,6 +247,8 @@ static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, bool result = true; /* BIST_SUCCESS */ u32 cnt = 0; u32 error = 0; + u32 val; + int ret; bist->test_result = true; @@ -274,27 +277,29 @@ run: 0x00000001); /* Write BISTRR.BINST = 3?b001; */ - /* Wait for a number of CTL clocks before reading BIST register*/ - /* Wait 300 ctl_clk cycles; ... IS it really needed?? */ - /* Perform BIST Instruction Stop*/ - /* Write BISTRR.BINST = 3?b010;*/ - - /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */ - while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE)) - ; - - /*Check if received correct number of words*/ - /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */ - if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) == - readl(&phy->bistwcr)) { - /*Determine if there is a data comparison error*/ - /* if (Read BISTGSR.BDXERR = 1?b0) */ - if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR) - result = false; /* BIST_FAIL; */ - else - result = true; /* BIST_SUCCESS; */ - } else { + /* poll on BISTGSR.BDONE and wait max 1000 us */ + ret = readl_poll_timeout(&phy->bistgsr, val, + val & DDRPHYC_BISTGSR_BDDONE, 1000); + + if (ret < 0) { + printf("warning: BIST timeout\n"); result = false; /* BIST_FAIL; */ + /*Perform BIST Stop */ + clrsetbits_le32(&phy->bistrr, 0x00000007, 0x00000002); + } else { + /*Check if received correct number of words*/ + /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */ + if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) + == readl(&phy->bistwcr)) { + /*Determine if there is a data comparison error*/ + /* if (Read BISTGSR.BDXERR = 1?b0) */ + if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR) + result = false; /* BIST_FAIL; */ + else + result = true; /* BIST_SUCCESS; */ + } else { + result = false; /* BIST_FAIL; */ + } } /* loop while success */ From patchwork Fri Mar 6 10:14:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243294 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:07 +0100 Subject: [PATCH 5/9] ram: stm32mp1: tuning: deactivate derating during BIST test In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.5.I2f3d97c071fc1de6dae7e15ee0bbc1df0f16fd9a@changeid> The derating (timing parameter derating using MR4 read value) can't be activated during BIST test, as the MR4 read answer will be not understood by BIST (BISTGSR.BDONE bit stay at 0, BISTWCSR.DXWCNT = 0x206 instead of BISTWCR.BWCNT = 0x200). This patch only impacts the tuning on LPDDR2/LPDDR3, if derateen.derate_enable = 1. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index cab6cf087a..37d3ec8fef 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1288,11 +1288,16 @@ static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = read_dqs_gating(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } @@ -1303,11 +1308,16 @@ static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = bit_deskew(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } @@ -1318,11 +1328,16 @@ static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = eye_training(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } From patchwork Fri Mar 6 10:14:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243297 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:08 +0100 Subject: [PATCH 6/9] ram: stm32mp1: update BIST config for tuning In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.6.Id09f75f6aa43a345f0eccb009481c6423933358b@changeid> Update the BIST config to compute the real use mask for the real bank, row and col of the used DDR. The values are get from addrmap register value. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 151 +++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 9 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 37d3ec8fef..07d57d496c 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "stm32mp1_ddr_regs.h" @@ -76,6 +77,133 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl) return nb_bytes; } +static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl) +{ + /* Count bank address bits */ + u8 bits = 0; + u32 reg, val; + + reg = readl(&ctl->addrmap1); + /* addrmap1.addrmap_bank_b1 */ + val = (reg & GENMASK(5, 0)) >> 0; + if (val <= 31) + bits++; + /* addrmap1.addrmap_bank_b2 */ + val = (reg & GENMASK(13, 8)) >> 8; + if (val <= 31) + bits++; + /* addrmap1.addrmap_bank_b3 */ + val = (reg & GENMASK(21, 16)) >> 16; + if (val <= 31) + bits++; + + return bits; +} + +static u8 get_nb_col(struct stm32mp1_ddrctl *ctl) +{ + u8 bits; + u32 reg, val; + + /* Count column address bits, start at 2 for b0 and b1 (fixed) */ + bits = 2; + + reg = readl(&ctl->addrmap2); + /* addrmap2.addrmap_col_b2 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b3 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b4 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b5 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + reg = readl(&ctl->addrmap3); + /* addrmap3.addrmap_col_b6 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b7 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b8 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b9 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + reg = readl(&ctl->addrmap4); + /* addrmap4.addrmap_col_b10 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap4.addrmap_col_b11 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + + return bits; +} + +static u8 get_nb_row(struct stm32mp1_ddrctl *ctl) +{ + /* Count row address bits */ + u8 bits = 0; + u32 reg, val; + + reg = readl(&ctl->addrmap5); + /* addrmap5.addrmap_row_b0 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 11) + bits++; + /* addrmap5.addrmap_row_b1 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 11) + bits++; + /* addrmap5.addrmap_row_b2_10 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 11) + bits += 9; + else + printf("warning: addrmap5.addrmap_row_b2_10 not supported\n"); + /* addrmap5.addrmap_row_b11 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 11) + bits++; + + reg = readl(&ctl->addrmap6); + /* addrmap6.addrmap_row_b12 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b13 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b14 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b15 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + return bits; +} + static void itm_soft_reset(struct stm32mp1_ddrphy *phy) { stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); @@ -170,8 +298,13 @@ static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, } /* Basic BIST configuration for data lane tests. */ -static void config_BIST(struct stm32mp1_ddrphy *phy) +static void config_BIST(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy) { + u8 nb_bank = get_nb_bank(ctl); + u8 nb_row = get_nb_row(ctl); + u8 nb_col = get_nb_col(ctl); + /* Selects the SDRAM bank address to be used during BIST. */ u32 bbank = 0; /* Selects the SDRAM row address to be used during BIST. */ @@ -191,18 +324,20 @@ static void config_BIST(struct stm32mp1_ddrphy *phy) * must be 0 with single rank */ u32 brank = 0; + /* Specifies the maximum SDRAM bank address to be used during * BIST before the address & increments to the next rank. */ - u32 bmbank = 1; + u32 bmbank = (1 << nb_bank) - 1; /* Specifies the maximum SDRAM row address to be used during * BIST before the address & increments to the next bank. */ - u32 bmrow = 0x7FFF; /* To check */ + u32 bmrow = (1 << nb_row) - 1; /* Specifies the maximum SDRAM column address to be used during * BIST before the address & increments to the next row. */ - u32 bmcol = 0x3FF; /* To check */ + u32 bmcol = (1 << nb_col) - 1; + u32 bmode_conf = 0x00000001; /* DRam mode */ u32 bdxen_conf = 0x00000001; /* BIST on Data byte */ u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */ @@ -224,8 +359,6 @@ static void config_BIST(struct stm32mp1_ddrphy *phy) writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0); writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1); - - /* To check this line : */ writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2); } @@ -399,7 +532,7 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* Config the BIST block */ - config_BIST(phy); + config_BIST(ctl, phy); pr_debug("BIST Config done.\n"); /* Train each byte */ @@ -812,7 +945,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* Config the BIST block */ - config_BIST(phy); + config_BIST(ctl, phy); for (byte = 0; byte < nb_bytes; byte++) { if (ctrlc()) { @@ -1234,7 +1367,7 @@ static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* config the bist block */ - config_BIST(phy); + config_BIST(ctl, phy); for (byte = 0; byte < nb_bytes; byte++) { if (ctrlc()) { From patchwork Fri Mar 6 10:14:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243293 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:09 +0100 Subject: [PATCH 7/9] ram: stm32mp1_ddr: fix self refresh disable during DQS training In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.7.I0f31274f26e4299269ef3c7d5a581d2abe96aad2@changeid> DDRCTRL_PWRCTL.SELFREF_EN needs to be reset before DQS training step, not to enter in self refresh mode during the execution of this phase. Depending on settings, it can be set after the DQS training. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 5 ++++- drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index a87914f2d5..b9300dd6d1 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -639,7 +639,8 @@ void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) start_sw_done(ctl); /* quasi-dynamic register update*/ setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); - clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); + clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN | + DDRCTRL_PWRCTL_SELFREF_EN); clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); wait_sw_done_ack(ctl); } @@ -652,6 +653,8 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); + if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN)) + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); wait_sw_done_ack(ctl); } diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h index 9d33186b3a..afd93c518e 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h @@ -260,6 +260,7 @@ struct stm32mp1_ddrphy { #define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0) +#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) From patchwork Fri Mar 6 10:14:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243296 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:10 +0100 Subject: [PATCH 8/9] ram: stm32mp1: reduce delay after BIST reset for tuning In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306111355.8.I2ed443e2c15db6b007f836254b3753da9b06e76d@changeid> Reduce the delay after BIST delay, from 1ms to 10us which is enough accoriding datasheet. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 07d57d496c..3013b7b667 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -402,7 +402,7 @@ run: writel(rand(), &phy->bistlsr); /* some delay to reset BIST */ - mdelay(1); + udelay(10); /*Perform BIST Run*/ clrsetbits_le32(&phy->bistrr, From patchwork Fri Mar 6 10:14:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Delaunay X-Patchwork-Id: 243298 List-Id: U-Boot discussion From: patrick.delaunay at st.com (Patrick Delaunay) Date: Fri, 6 Mar 2020 11:14:11 +0100 Subject: [PATCH 9/9] ram: stm32mp1: the property st, phy-cal becomes optional In-Reply-To: <20200306101412.15376-1-patrick.delaunay@st.com> References: <20200306101412.15376-1-patrick.delaunay@st.com> Message-ID: <20200306101412.15376-2-patrick.delaunay@st.com> 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 Acked-by: Patrice Chotard --- 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 changes DDR information\n" - " with = step, name, size or speed\n" + " with = step, name, size, speed or cal\n" "freq displays the DDR PHY frequency in kHz\n" "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);