From 69ffb5577a0fa4d47e34a7684861d88e556f1d48 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 9 Mar 2020 14:59:22 +0100 Subject: clk: stm32mp1: correct CKSELR masks Correct three masks used to access on the RCC register RCC_QSPICKSELR, RCC_FMCCKSELR and RCC_ADCCKSELR: only 3 bits. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/clk/clk_stm32mp1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index fd8c821e48b..42f9ef4e46d 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -621,13 +621,13 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), STM32MP1_CLK_PARENT(_ETH_SEL, RCC_ETHCKSELR, 0, 0x3, eth_parents), - STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), - STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), + STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0x3, qspi_parents), + STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0x3, fmc_parents), STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), - STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), + STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT, (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT), -- cgit v1.2.3 From 0c90e0cf63531bfdfb09a54acbd28c53d4c261ea Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 9 Mar 2020 14:59:23 +0100 Subject: clk: stm32mp1: add SPI5_K support Add clock support for SPI5, as this instance is available on extension connector of ST board. Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/clk/clk_stm32mp1.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 42f9ef4e46d..52bd8e96f3e 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -95,6 +95,7 @@ DECLARE_GLOBAL_DATA_PTR; #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 #define RCC_SPI2S1CKSELR 0x8D8 +#define RCC_SPI45CKSELR 0x8E0 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 #define RCC_UART35CKSELR 0x8EC @@ -304,6 +305,7 @@ enum stm32mp1_parent_sel { _DSI_SEL, _ADC12_SEL, _SPI1_SEL, + _SPI45_SEL, _RTC_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, @@ -527,6 +529,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 10, SPI5_K, _SPI45_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), @@ -603,6 +606,8 @@ static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, _PLL3_R}; +static const u8 spi45_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, + _HSE_KER}; static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { @@ -629,6 +634,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), + STM32MP1_CLK_PARENT(_SPI45_SEL, RCC_SPI45CKSELR, 0, 0x7, spi45_parents), STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT, (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT), rtc_parents), @@ -747,6 +753,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", [_SPI1_SEL] = "SPI1", + [_SPI45_SEL] = "SPI45", [_RTC_SEL] = "RTC", }; -- cgit v1.2.3 From e9a20f8a198c11a4108ca4b4deef8398f0cd93aa Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:03 +0100 Subject: ram: stm32mp1: increase vdd2_ddr: buck2 for 32bits LPDDR 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 --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index d765a46f7c2..a87914f2d56 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"); -- cgit v1.2.3 From c8eb4e038cf4dab68d7f79ec740198e30b6005a2 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:04 +0100 Subject: ram: stm32mp1: display result for software read DQS gating 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(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 4e1c1fab54c..e3e6f0f79c3 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 -- cgit v1.2.3 From 1c55a91b9d35ddd30a37bb5efe4ba1ea66b5720d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:05 +0100 Subject: ram: stm32mp1: don't display the prompt two times 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(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index cc9b2e7c96c..cedf92cb5f1 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; -- cgit v1.2.3 From f711d1f0804e01586b8f68af81cde6a15b58d427 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:06 +0100 Subject: ram: stm32mp1: tuning: add timeout for polling BISTGSR.BDDONE 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(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index e3e6f0f79c3..cab6cf087a4 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 */ -- cgit v1.2.3 From 27e7b4edeabe87be1cb9dc549b2f7d91c1f3e3a7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:07 +0100 Subject: ram: stm32mp1: tuning: deactivate derating during BIST test 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(+) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index cab6cf087a4..37d3ec8fef9 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; } -- cgit v1.2.3 From 8c9ce0807545976c4080621be80dfb02b4ead400 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:08 +0100 Subject: ram: stm32mp1: update BIST config for tuning 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(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 37d3ec8fef9..07d57d496c3 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()) { -- cgit v1.2.3 From b604a41c6bcfb6273e7478089ff3e7b65e233645 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:09 +0100 Subject: ram: stm32mp1_ddr: fix self refresh disable during DQS training 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 --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 5 ++++- drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index a87914f2d56..b9300dd6d16 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 9d33186b3a2..afd93c518eb 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) -- cgit v1.2.3 From d424e6786f637d3181ffa9e2cc9ed6bca00aa30f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:10 +0100 Subject: ram: stm32mp1: reduce delay after BIST reset for tuning 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(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 07d57d496c3..3013b7b6676 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, -- cgit v1.2.3 From 9368bdfebde16368cdb642adbb12f9c871c94d63 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Mar 2020 11:14:11 +0100 Subject: 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 Acked-by: Patrice Chotard --- 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 ++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index b9300dd6d16..11b14ae6520 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 52b748f3ca2..4998f044394 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 cedf92cb5f1..805c9ddaadc 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 eb78f1198d7..b1e593f86bd 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); -- cgit v1.2.3 From c32446557627699cd17c93d1077b9d0466a81589 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 6 Mar 2020 11:09:14 +0100 Subject: i2c: stm32f7_i2c: allows for any bus frequency Do not limit to 3 (100KHz, 400KHz, 1MHz) bus frequencies, but instead allow for any frequency. Depending on the requested frequency (via the clock-frequency DT entry), use the spec data from either Standard, Fast or Fast Plus mode. In order to do so, the driver do not use anymore spec identifier by directly handle the requested frequency and from it retrieve the corresponding spec data to be used for the computation of the timing register. Signed-off-by: Alain Volmat Reviewed-by: Patrick DELAUNAY Signed-off-by: Patrick Delaunay Acked-by: Patrice Chotard --- drivers/i2c/stm32f7_i2c.c | 105 ++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 7d046c1a1e6..fc5c1221e1e 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -7,10 +7,10 @@ #include #include #include -#include #include #include +#include #include /* STM32 I2C registers */ @@ -145,7 +145,6 @@ struct stm32_i2c_spec { /** * struct stm32_i2c_setup - private I2C timing setup parameters - * @speed: I2C speed mode (standard, Fast Plus) * @speed_freq: I2C speed frequency (Hz) * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) @@ -154,7 +153,6 @@ struct stm32_i2c_spec { * @analog_filter: Analog filter delay (On/Off) */ struct stm32_i2c_setup { - enum i2c_speed_mode speed; u32 speed_freq; u32 clock_src; u32 rise_time; @@ -184,10 +182,11 @@ struct stm32_i2c_priv { struct stm32_i2c_regs *regs; struct clk clk; struct stm32_i2c_setup *setup; - int speed; + u32 speed; }; static const struct stm32_i2c_spec i2c_specs[] = { + /* Standard speed - 100 KHz */ [IC_SPEED_MODE_STANDARD] = { .rate = I2C_SPEED_STANDARD_RATE, .rate_min = 8000, @@ -200,6 +199,7 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 4700, .h_min = 4000, }, + /* Fast speed - 400 KHz */ [IC_SPEED_MODE_FAST] = { .rate = I2C_SPEED_FAST_RATE, .rate_min = 320000, @@ -212,6 +212,7 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 1300, .h_min = 600, }, + /* Fast Plus Speed - 1 MHz */ [IC_SPEED_MODE_FAST_PLUS] = { .rate = I2C_SPEED_FAST_PLUS_RATE, .rate_min = 800000, @@ -474,6 +475,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, } static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions) { struct stm32_i2c_timings *v; @@ -490,13 +492,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, af_delay_max = setup->analog_filter ? STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0; - sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - + sdadel_min = specs->hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; - sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - + sdadel_max = specs->vddat_max - setup->rise_time - af_delay_max - (setup->dnf + 4) * i2cclk; - scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min; + scldel_min = setup->rise_time + specs->sudat_min; if (sdadel_min < 0) sdadel_min = 0; @@ -548,6 +550,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, } static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions, struct stm32_i2c_timings *s) { @@ -570,8 +573,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, dnf_delay = setup->dnf * i2cclk; tsync = af_delay_min + dnf_delay + (2 * i2cclk); - clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; - clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; + clk_max = STM32_NSEC_PER_SEC / specs->rate_min; + clk_min = STM32_NSEC_PER_SEC / specs->rate_max; /* * Among Prescaler possibilities discovered above figures out SCL Low @@ -589,7 +592,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, for (l = 0; l < STM32_SCLL_MAX; l++) { u32 tscl_l = (l + 1) * prescaler + tsync; - if ((tscl_l < i2c_specs[setup->speed].l_min) || + if (tscl_l < specs->l_min || (i2cclk >= ((tscl_l - af_delay_min - dnf_delay) / 4))) { continue; @@ -601,7 +604,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, setup->rise_time + setup->fall_time; if ((tscl >= clk_min) && (tscl <= clk_max) && - (tscl_h >= i2c_specs[setup->speed].h_min) && + (tscl_h >= specs->h_min) && (i2cclk < tscl_h)) { u32 clk_error; @@ -630,26 +633,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, return ret; } +static const struct stm32_i2c_spec *get_specs(u32 rate) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) + if (rate <= i2c_specs[i].rate) + return &i2c_specs[i]; + + /* NOT REACHED */ + return ERR_PTR(-EINVAL); +} + static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_setup *setup, struct stm32_i2c_timings *output) { + const struct stm32_i2c_spec *specs; struct stm32_i2c_timings *v, *_v; struct list_head solutions; int ret; - if (setup->speed >= ARRAY_SIZE(i2c_specs)) { - pr_err("%s: speed out of bound {%d/%d}\n", __func__, - setup->speed, ARRAY_SIZE(i2c_specs) - 1); + specs = get_specs(setup->speed_freq); + if (specs == ERR_PTR(-EINVAL)) { + pr_err("%s: speed out of bound {%d}\n", __func__, + setup->speed_freq); return -EINVAL; } - if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || - (setup->fall_time > i2c_specs[setup->speed].fall_max)) { + if (setup->rise_time > specs->rise_max || + setup->fall_time > specs->fall_max) { pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", __func__, - setup->rise_time, i2c_specs[setup->speed].rise_max, - setup->fall_time, i2c_specs[setup->speed].fall_max); + setup->rise_time, specs->rise_max, + setup->fall_time, specs->fall_max); return -EINVAL; } @@ -659,18 +676,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, return -EINVAL; } - if (setup->speed_freq > i2c_specs[setup->speed].rate) { - pr_err("%s: Freq {%d/%d}\n", __func__, - setup->speed_freq, i2c_specs[setup->speed].rate); - return -EINVAL; - } - INIT_LIST_HEAD(&solutions); - ret = stm32_i2c_compute_solutions(setup, &solutions); + ret = stm32_i2c_compute_solutions(setup, specs, &solutions); if (ret) goto exit; - ret = stm32_i2c_choose_solution(setup, &solutions, output); + ret = stm32_i2c_choose_solution(setup, specs, &solutions, output); if (ret) goto exit; @@ -689,14 +700,24 @@ exit: return ret; } +static u32 get_lower_rate(u32 rate) +{ + int i; + + for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) + if (rate > i2c_specs[i].rate) + return i2c_specs[i].rate; + + return i2c_specs[0].rate; +} + static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_timings *timing) { struct stm32_i2c_setup *setup = i2c_priv->setup; int ret = 0; - setup->speed = i2c_priv->speed; - setup->speed_freq = i2c_specs[setup->speed].rate; + setup->speed_freq = i2c_priv->speed; setup->clock_src = clk_get_rate(&i2c_priv->clk); if (!setup->clock_src) { @@ -709,13 +730,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, if (ret) { debug("%s: failed to compute I2C timings.\n", __func__); - if (i2c_priv->speed > IC_SPEED_MODE_STANDARD) { - i2c_priv->speed--; - setup->speed = i2c_priv->speed; + if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) { setup->speed_freq = - i2c_specs[setup->speed].rate; + get_lower_rate(setup->speed_freq); debug("%s: downgrade I2C Speed Freq to (%i)\n", - __func__, i2c_specs[setup->speed].rate); + __func__, setup->speed_freq); } else { break; } @@ -727,13 +746,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, return ret; } - debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__, - setup->speed, setup->speed_freq, setup->clock_src); + debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__, + setup->speed_freq, setup->clock_src); debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__, setup->rise_time, setup->fall_time); debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__, setup->analog_filter ? "On" : "Off", setup->dnf); + i2c_priv->speed = setup->speed_freq; + return 0; } @@ -773,21 +794,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus); - switch (speed) { - case I2C_SPEED_STANDARD_RATE: - i2c_priv->speed = IC_SPEED_MODE_STANDARD; - break; - case I2C_SPEED_FAST_RATE: - i2c_priv->speed = IC_SPEED_MODE_FAST; - break; - case I2C_SPEED_FAST_PLUS_RATE: - i2c_priv->speed = IC_SPEED_MODE_FAST_PLUS; - break; - default: + if (speed > I2C_SPEED_FAST_PLUS_RATE) { debug("%s: Speed %d not supported\n", __func__, speed); return -EINVAL; } + i2c_priv->speed = speed; + return stm32_i2c_hw_config(i2c_priv); } -- cgit v1.2.3 From 123123d695a9b024a1413645eeff4bb41f610332 Mon Sep 17 00:00:00 2001 From: Nicolas Heemeryck Date: Fri, 13 Mar 2020 23:42:43 +0100 Subject: timer: sti: convert to livetree Update STI timer to support a live tree Signed-off-by: Nicolas Heemeryck Cc: Patrice Chotard Acked-by: Patrice Chotard --- drivers/timer/sti-timer.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/timer/sti-timer.c b/drivers/timer/sti-timer.c index 9def7e02f4b..eac22ae39b0 100644 --- a/drivers/timer/sti-timer.c +++ b/drivers/timer/sti-timer.c @@ -6,14 +6,11 @@ #include #include -#include #include #include #include -DECLARE_GLOBAL_DATA_PTR; - struct sti_timer_priv { struct globaltimer *global_timer; }; @@ -44,13 +41,13 @@ static int sti_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct sti_timer_priv *priv = dev_get_priv(dev); - fdt_addr_t addr; uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; /* get arm global timer base address */ - addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg"); - priv->global_timer = (struct globaltimer *)addr; + priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev); + if (!priv->global_timer) + return -ENOENT; /* init timer */ writel(0x01, &priv->global_timer->ctl); -- cgit v1.2.3 From 5b5699cdc97122e08e7fd0886a9e4474ca3ccb35 Mon Sep 17 00:00:00 2001 From: Nicolas Heemeryck Date: Fri, 13 Mar 2020 23:42:44 +0100 Subject: timer: sti: use clk API to get timer clock rate Retrieve clock rate through device tree. This mimics the behavior of arm_global_timer in Linux. Signed-off-by: Nicolas Heemeryck Cc: Patrice Chotard Acked-by: Patrice Chotard --- drivers/timer/sti-timer.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/timer/sti-timer.c b/drivers/timer/sti-timer.c index eac22ae39b0..ff42056abdd 100644 --- a/drivers/timer/sti-timer.c +++ b/drivers/timer/sti-timer.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include @@ -41,14 +43,25 @@ static int sti_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct sti_timer_priv *priv = dev_get_priv(dev); - - uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; + struct clk clk; + int err; + ulong ret; /* get arm global timer base address */ priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev); if (!priv->global_timer) return -ENOENT; + err = clk_get_by_index(dev, 0, &clk); + if (!err) { + ret = clk_get_rate(&clk); + if (IS_ERR_VALUE(ret)) + return ret; + uc_priv->clock_rate = ret; + } else { + uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; + } + /* init timer */ writel(0x01, &priv->global_timer->ctl); -- cgit v1.2.3