From a718a5d0f43b9094c9abb04ed0d9999a32d69091 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 14 May 2020 15:00:23 +0200 Subject: [PATCH 01/36] net: dwc_eth_qos: update the compatible supported for STM32 Update the compatible associated with the STM32 MPU glue in the DWC ethernet driver. The supported compatible is the specific "st,stm32mp1-dwmac" as indicated in Linux binding Documentation/devicetree/bindings/net/stm32-dwmac.txt and not the "snps,dwmac-4.20a" only used to the select IP version. This glue is implemented in Linux kernel in: drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c For information in stm32mp151.dtsi, the 2 compatibles are supported: ethernet0: ethernet@5800a000 { compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; ... }; Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/net/dwc_eth_qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 3f4437069b..62941bb175 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -2170,7 +2170,7 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_tegra186_config }, { - .compatible = "snps,dwmac-4.20a", + .compatible = "st,stm32mp1-dwmac", .data = (ulong)&eqos_stm32_config }, { From 95bd49a5aa8bd7b1018e7de1ff547efa54552e62 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:41 +0200 Subject: [PATCH 02/36] arm: stm32mp: spl: add bsec driver in SPL Add the bsec driver in SPL, as it is needed by SOC part number detection to found the supported OPP. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15-u-boot.dtsi | 2 +- arch/arm/mach-stm32mp/Makefile | 2 +- arch/arm/mach-stm32mp/bsec.c | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/arm/dts/stm32mp15-u-boot.dtsi b/arch/arm/dts/stm32mp15-u-boot.dtsi index 1279589a56..a0d971ad88 100644 --- a/arch/arm/dts/stm32mp15-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15-u-boot.dtsi @@ -65,7 +65,7 @@ }; &bsec { - u-boot,dm-pre-proper; + u-boot,dm-pre-reloc; }; &clk_csi { diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 66bb8cf92f..c8aa24d489 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -6,12 +6,12 @@ obj-y += cpu.o obj-y += dram_init.o obj-y += syscon.o +obj-y += bsec.o ifdef CONFIG_SPL_BUILD obj-y += spl.o else obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ -obj-y += bsec.o obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-$(CONFIG_TFABOOT) += boot_params.o diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fc39230113..059ef0b1f5 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -474,20 +474,23 @@ static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) return 0; } -#ifndef CONFIG_TFABOOT static int stm32mp_bsec_probe(struct udevice *dev) { +#if !defined(CONFIG_TFABOOT) && !defined(CONFIG_SPL_BUILD) int otp; struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); - /* update unlocked shadow for OTP cleared by the rom code */ + /* + * update unlocked shadow for OTP cleared by the rom code + * only executed in U-Boot proper when TF-A is not used + */ for (otp = 57; otp <= BSEC_OTP_MAX_VALUE; otp++) if (!bsec_read_SR_lock(plat->base, otp)) bsec_shadow_register(plat->base, otp); +#endif return 0; } -#endif static const struct udevice_id stm32mp_bsec_ids[] = { { .compatible = "st,stm32mp15-bsec" }, @@ -501,7 +504,5 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), .ops = &stm32mp_bsec_ops, -#ifndef CONFIG_TFABOOT .probe = stm32mp_bsec_probe, -#endif }; From 6f2e0ad1945a188d39e759f7b87a66cc9274ecc1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:42 +0200 Subject: [PATCH 03/36] ARM: dts: stm32: add cpufreq support on stm32mp15x This commit adds cpufreq support on stm32mp15x SOC. STM32 cpufreq uses operating points V2 bindings (no legacy). Nvmem cells have to be used to know the chip version and then which OPPs are available. Note that STM32 cpufreq driver is mainly based on "cpufreq-dt" driver. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp151.dtsi | 21 +++++++++++++++++++++ arch/arm/dts/stm32mp157c-ed1.dts | 8 ++++++++ arch/arm/dts/stm32mp15xx-dkx.dtsi | 8 ++++++++ 3 files changed, 37 insertions(+) diff --git a/arch/arm/dts/stm32mp151.dtsi b/arch/arm/dts/stm32mp151.dtsi index 75d2c0d296..d5216a1831 100644 --- a/arch/arm/dts/stm32mp151.dtsi +++ b/arch/arm/dts/stm32mp151.dtsi @@ -20,6 +20,24 @@ clock-frequency = <650000000>; device_type = "cpu"; reg = <0>; + operating-points-v2 = <&cpu0_opp_table>; + nvmem-cells = <&part_number_otp>; + nvmem-cell-names = "part_number"; + }; + }; + + cpu0_opp_table: cpu0-opp-table { + compatible = "operating-points-v2"; + opp-shared; + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + opp-microvolt = <1200000>; + opp-supported-hw = <0x1>; + }; + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1350000>; + opp-supported-hw = <0x2>; }; }; @@ -1522,6 +1540,9 @@ reg = <0x5c005000 0x400>; #address-cells = <1>; #size-cells = <1>; + part_number_otp: part_number_otp@4 { + reg = <0x4 0x1>; + }; ts_cal1: calib@5c { reg = <0x5c 0x2>; }; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 186dc46754..c4c1202789 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -107,6 +107,14 @@ }; }; +&cpu0{ + cpu-supply = <&vddcore>; +}; + +&cpu1{ + cpu-supply = <&vddcore>; +}; + &dac { pinctrl-names = "default"; pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; diff --git a/arch/arm/dts/stm32mp15xx-dkx.dtsi b/arch/arm/dts/stm32mp15xx-dkx.dtsi index 7589c6f9dc..e7a46e7b5f 100644 --- a/arch/arm/dts/stm32mp15xx-dkx.dtsi +++ b/arch/arm/dts/stm32mp15xx-dkx.dtsi @@ -116,6 +116,14 @@ status = "okay"; }; +&cpu0{ + cpu-supply = <&vddcore>; +}; + +&cpu1{ + cpu-supply = <&vddcore>; +}; + ðernet0 { status = "okay"; pinctrl-0 = <ðernet0_rgmii_pins_a>; From 918e9c3d638722e5169091594846462e7af69f47 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:43 +0200 Subject: [PATCH 04/36] board: st: create common file stpmic1.c Move function board_ddr_power_init() in a new file stpmic1 in board/st/common to avoid duplicated code in each board using stpmic1 Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/dhelectronics/dh_stm32mp1/Makefile | 2 +- board/st/common/Makefile | 1 + board/st/common/stpmic1.c | 164 +++++++++++++++++++++++ board/st/stm32mp1/board.c | 158 ---------------------- 4 files changed, 166 insertions(+), 159 deletions(-) create mode 100644 board/st/common/stpmic1.c diff --git a/board/dhelectronics/dh_stm32mp1/Makefile b/board/dhelectronics/dh_stm32mp1/Makefile index e8f218da08..5758d9816b 100644 --- a/board/dhelectronics/dh_stm32mp1/Makefile +++ b/board/dhelectronics/dh_stm32mp1/Makefile @@ -7,7 +7,7 @@ ifdef CONFIG_SPL_BUILD obj-y += ../../st/stm32mp1/spl.o endif -obj-y += ../../st/stm32mp1/board.o board.o +obj-y += ../../st/common/stpmic1.o board.o obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += ../../st/common/stm32mp_mtdparts.o obj-$(CONFIG_SET_DFU_ALT_INFO) += ../../st/common/stm32mp_dfu.o diff --git a/board/st/common/Makefile b/board/st/common/Makefile index aa030bacd8..012bfbbe8e 100644 --- a/board/st/common/Makefile +++ b/board/st/common/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_CMD_STBOARD) += cmd_stboard.o +obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o ifeq ($(CONFIG_ARCH_STM32MP),y) obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += stm32mp_mtdparts.o diff --git a/board/st/common/stpmic1.c b/board/st/common/stpmic1.c new file mode 100644 index 0000000000..41111c5923 --- /dev/null +++ b/board/st/common/stpmic1.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include + +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); + if (ret) + /* No PMIC on board */ + return 0; + + switch (ddr_type) { + case STM32MP_DDR3: + /* VTT = Set LDO3 to sync mode */ + ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); + if (ret < 0) + return ret; + + ret &= ~STPMIC1_LDO3_MODE; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL); + + ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + ret); + if (ret < 0) + return ret; + + /* VDD_DDR = Set BUCK2 to 1.35V */ + ret = pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_VOUT_MASK, + STPMIC1_BUCK2_1350000V); + if (ret < 0) + return ret; + + /* Enable VDD_DDR = BUCK2 */ + ret = pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VREF */ + ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VTT = LDO3 */ + ret = pmic_clrsetbits(dev, + STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + break; + + 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 + * + bypass mode if BUCK3 = 1.8V + * + normal mode if BUCK3 != 1.8V + */ + ret = pmic_reg_read(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3)); + if (ret < 0) + return ret; + + if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V) + buck3_at_1800000v = true; + + ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); + if (ret < 0) + return ret; + + ret &= ~STPMIC1_LDO3_MODE; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO3_1800000; + if (buck3_at_1800000v) + ret |= STPMIC1_LDO3_MODE; + + ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + ret); + if (ret < 0) + return ret; + + /* 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, + buck2); + if (ret < 0) + return ret; + + /* Enable VDD_DDR1 = LDO3 */ + ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VDD_DDR2 =BUCK2 */ + ret = pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VREF */ + ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + break; + + default: + break; + }; + + return 0; +} diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index c218d37ecc..00c61c2886 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -4,13 +4,9 @@ */ #include -#include #include -#include #include #include -#include -#include #ifdef CONFIG_DEBUG_UART_BOARD_INIT void board_debug_uart_init(void) @@ -38,157 +34,3 @@ void board_debug_uart_init(void) #endif } #endif - -#ifdef CONFIG_PMIC_STPMIC1 -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); - if (ret) - /* No PMIC on board */ - return 0; - - switch (ddr_type) { - case STM32MP_DDR3: - /* VTT = Set LDO3 to sync mode */ - ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); - if (ret < 0) - return ret; - - ret &= ~STPMIC1_LDO3_MODE; - ret &= ~STPMIC1_LDO12356_VOUT_MASK; - ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL); - - ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), - ret); - if (ret < 0) - return ret; - - /* VDD_DDR = Set BUCK2 to 1.35V */ - ret = pmic_clrsetbits(dev, - STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), - STPMIC1_BUCK_VOUT_MASK, - STPMIC1_BUCK2_1350000V); - if (ret < 0) - return ret; - - /* Enable VDD_DDR = BUCK2 */ - ret = pmic_clrsetbits(dev, - STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), - STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - /* Enable VREF */ - ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR, - STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - /* Enable VTT = LDO3 */ - ret = pmic_clrsetbits(dev, - STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), - STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - break; - - 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 - * + bypass mode if BUCK3 = 1.8V - * + normal mode if BUCK3 != 1.8V - */ - ret = pmic_reg_read(dev, - STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3)); - if (ret < 0) - return ret; - - if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V) - buck3_at_1800000v = true; - - ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); - if (ret < 0) - return ret; - - ret &= ~STPMIC1_LDO3_MODE; - ret &= ~STPMIC1_LDO12356_VOUT_MASK; - ret |= STPMIC1_LDO3_1800000; - if (buck3_at_1800000v) - ret |= STPMIC1_LDO3_MODE; - - ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), - ret); - if (ret < 0) - return ret; - - /* 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, - buck2); - if (ret < 0) - return ret; - - /* Enable VDD_DDR1 = LDO3 */ - ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), - STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - /* Enable VDD_DDR2 =BUCK2 */ - ret = pmic_clrsetbits(dev, - STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), - STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - /* Enable VREF */ - ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR, - STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); - if (ret < 0) - return ret; - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - break; - - default: - break; - }; - - return 0; -} -#endif From 37ad8377af00128adc47fb1192142ac9dfbf1f9d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:44 +0200 Subject: [PATCH 05/36] stm32mp1: clk: configure pll1 with OPP The PLL1 node (st,pll1) is optional in device tree, the max supported frequency define in OPP node is used when the node is absent. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- .../clock/st,stm32mp1.txt | 4 + drivers/clk/clk_stm32mp1.c | 290 ++++++++++++++++-- 2 files changed, 266 insertions(+), 28 deletions(-) diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt index a3d427911d..4d4136d2fc 100644 --- a/doc/device-tree-bindings/clock/st,stm32mp1.txt +++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt @@ -87,6 +87,10 @@ Optional Properties: are listed with associated reg 0 to 3. PLLx is off when the associated node is absent or deactivated. + For PLL1, when the node is absent, the frequency of the OPP node is used + to compute the PLL setting (see compatible "operating-points-v2" in + opp/opp.txt for details). + Here are the available properties for each PLL node: - compatible: should be "st,stm32mp1-pll" diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 6c5eddbd9a..8acbad25f9 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -644,8 +645,18 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { }; #ifdef STM32MP1_CLOCK_TREE_INIT + /* define characteristic of PLL according type */ +#define DIVM_MIN 0 +#define DIVM_MAX 63 #define DIVN_MIN 24 +#define DIVP_MIN 0 +#define DIVP_MAX 127 +#define FRAC_MAX 8192 + +#define PLL1600_VCO_MIN 800000000 +#define PLL1600_VCO_MAX 1600000000 + static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { [PLL_800] = { .refclk_min = 4, @@ -1190,6 +1201,208 @@ static ulong stm32mp1_clk_get_rate(struct clk *clk) } #ifdef STM32MP1_CLOCK_TREE_INIT + +bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type) +{ + unsigned int id; + + switch (opp_id) { + case 1: + case 2: + id = opp_id; + break; + default: + id = 1; /* default value */ + break; + } + + switch (cpu_type) { + case CPU_STM32MP157Fxx: + case CPU_STM32MP157Dxx: + case CPU_STM32MP153Fxx: + case CPU_STM32MP153Dxx: + case CPU_STM32MP151Fxx: + case CPU_STM32MP151Dxx: + return true; + default: + return id == 1; + } +} + +/* + * gets OPP parameters (frequency in KHz and voltage in mV) from + * an OPP table subnode. Platform HW support capabilities are also checked. + * Returns 0 on success and a negative FDT error code on failure. + */ +static int stm32mp1_get_opp(u32 cpu_type, ofnode subnode, + u32 *freq_khz, u32 *voltage_mv) +{ + u32 opp_hw; + u64 read_freq_64; + u32 read_voltage_32; + + *freq_khz = 0; + *voltage_mv = 0; + + opp_hw = ofnode_read_u32_default(subnode, "opp-supported-hw", 0); + if (opp_hw) + if (!stm32mp1_supports_opp(opp_hw, cpu_type)) + return -FDT_ERR_BADVALUE; + + read_freq_64 = ofnode_read_u64_default(subnode, "opp-hz", 0) / + 1000ULL; + read_voltage_32 = ofnode_read_u32_default(subnode, "opp-microvolt", 0) / + 1000U; + + if (!read_voltage_32 || !read_freq_64) + return -FDT_ERR_NOTFOUND; + + /* Frequency value expressed in KHz must fit on 32 bits */ + if (read_freq_64 > U32_MAX) + return -FDT_ERR_BADVALUE; + + /* Millivolt value must fit on 16 bits */ + if (read_voltage_32 > U16_MAX) + return -FDT_ERR_BADVALUE; + + *freq_khz = (u32)read_freq_64; + *voltage_mv = read_voltage_32; + + return 0; +} + +/* + * parses OPP table in DT and finds the parameters for the + * highest frequency supported by the HW platform. + * Returns 0 on success and a negative FDT error code on failure. + */ +int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz) +{ + ofnode node, subnode; + int ret; + u32 freq = 0U, voltage = 0U; + u32 cpu_type = get_cpu_type(); + + node = ofnode_by_compatible(ofnode_null(), "operating-points-v2"); + if (!ofnode_valid(node)) + return -FDT_ERR_NOTFOUND; + + ofnode_for_each_subnode(subnode, node) { + unsigned int read_freq; + unsigned int read_voltage; + + ret = stm32mp1_get_opp(cpu_type, subnode, + &read_freq, &read_voltage); + if (ret) + continue; + + if (read_freq > freq) { + freq = read_freq; + voltage = read_voltage; + } + } + + if (!freq || !voltage) + return -FDT_ERR_NOTFOUND; + + *freq_hz = (u64)1000U * freq; + + return 0; +} + +static int stm32mp1_pll1_opp(struct stm32mp1_clk_priv *priv, int clksrc, + u32 *pllcfg, u32 *fracv) +{ + u32 post_divm; + u32 input_freq; + u64 output_freq; + u64 freq; + u64 vco; + u32 divm, divn, divp, frac; + int i, ret; + u32 diff; + u32 best_diff = U32_MAX; + + /* PLL1 is 1600 */ + const u32 DIVN_MAX = stm32mp1_pll[PLL_1600].divn_max; + const u32 POST_DIVM_MIN = stm32mp1_pll[PLL_1600].refclk_min * 1000000U; + const u32 POST_DIVM_MAX = stm32mp1_pll[PLL_1600].refclk_max * 1000000U; + + ret = stm32mp1_get_max_opp_freq(priv, &output_freq); + if (ret) { + debug("PLL1 OPP configuration not found (%d).\n", ret); + return ret; + } + + switch (clksrc) { + case CLK_PLL12_HSI: + input_freq = stm32mp1_clk_get_fixed(priv, _HSI); + break; + case CLK_PLL12_HSE: + input_freq = stm32mp1_clk_get_fixed(priv, _HSE); + break; + default: + return -EINTR; + } + + /* Following parameters have always the same value */ + pllcfg[PLLCFG_Q] = 0; + pllcfg[PLLCFG_R] = 0; + pllcfg[PLLCFG_O] = PQR(1, 0, 0); + + for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) { + post_divm = (u32)(input_freq / (divm + 1)); + if (post_divm < POST_DIVM_MIN || post_divm > POST_DIVM_MAX) + continue; + + for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) { + freq = output_freq * (divm + 1) * (divp + 1); + divn = (u32)((freq / input_freq) - 1); + if (divn < DIVN_MIN || divn > DIVN_MAX) + continue; + + frac = (u32)(((freq * FRAC_MAX) / input_freq) - + ((divn + 1) * FRAC_MAX)); + /* 2 loops to refine the fractional part */ + for (i = 2; i != 0; i--) { + if (frac > FRAC_MAX) + break; + + vco = (post_divm * (divn + 1)) + + ((post_divm * (u64)frac) / + FRAC_MAX); + if (vco < (PLL1600_VCO_MIN / 2) || + vco > (PLL1600_VCO_MAX / 2)) { + frac++; + continue; + } + freq = vco / (divp + 1); + if (output_freq < freq) + diff = (u32)(freq - output_freq); + else + diff = (u32)(output_freq - freq); + if (diff < best_diff) { + pllcfg[PLLCFG_M] = divm; + pllcfg[PLLCFG_N] = divn; + pllcfg[PLLCFG_P] = divp; + *fracv = frac; + + if (diff == 0) + return 0; + + best_diff = diff; + } + frac++; + } + } + } + + if (best_diff == U32_MAX) + return -1; + + return 0; +} + static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset, u32 mask_on) { @@ -1661,9 +1874,12 @@ static int stm32mp1_clktree(struct udevice *dev) unsigned int clksrc[CLKSRC_NB]; unsigned int clkdiv[CLKDIV_NB]; unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; - ofnode plloff[_PLL_NB]; - int ret, len; - uint i; + unsigned int pllfracv[_PLL_NB]; + unsigned int pllcsg[_PLL_NB][PLLCSG_NB]; + bool pllcfg_valid[_PLL_NB]; + bool pllcsg_set[_PLL_NB]; + int ret; + int i, len; int lse_css = 0; const u32 *pkcs_cell; @@ -1683,16 +1899,43 @@ static int stm32mp1_clktree(struct udevice *dev) /* check mandatory field in each pll */ for (i = 0; i < _PLL_NB; i++) { char name[12]; + ofnode node; sprintf(name, "st,pll@%d", i); - plloff[i] = dev_read_subnode(dev, name); - if (!ofnode_valid(plloff[i])) - continue; - ret = ofnode_read_u32_array(plloff[i], "cfg", - pllcfg[i], PLLCFG_NB); - if (ret < 0) { - debug("field cfg invalid: error %d\n", ret); - return -FDT_ERR_NOTFOUND; + node = dev_read_subnode(dev, name); + pllcfg_valid[i] = ofnode_valid(node); + pllcsg_set[i] = false; + if (pllcfg_valid[i]) { + debug("DT for PLL %d @ %s\n", i, name); + ret = ofnode_read_u32_array(node, "cfg", + pllcfg[i], PLLCFG_NB); + if (ret < 0) { + debug("field cfg invalid: error %d\n", ret); + return -FDT_ERR_NOTFOUND; + } + pllfracv[i] = ofnode_read_u32_default(node, "frac", 0); + + ret = ofnode_read_u32_array(node, "csg", pllcsg[i], + PLLCSG_NB); + if (!ret) { + pllcsg_set[i] = true; + } else if (ret != -FDT_ERR_NOTFOUND) { + debug("invalid csg node for pll@%d res=%d\n", + i, ret); + return ret; + } + } else if (i == _PLL1) { + /* use OPP for PLL1 for A7 CPU */ + debug("DT for PLL %d with OPP\n", i); + ret = stm32mp1_pll1_opp(priv, + clksrc[CLKSRC_PLL12], + pllcfg[i], + &pllfracv[i]); + if (ret) { + debug("PLL %d with OPP error = %d\n", i, ret); + return ret; + } + pllcfg_valid[i] = true; } } @@ -1778,29 +2021,18 @@ static int stm32mp1_clktree(struct udevice *dev) /* configure and start PLLs */ debug("configure PLLs\n"); for (i = 0; i < _PLL_NB; i++) { - u32 fracv; - u32 csg[PLLCSG_NB]; - - debug("configure PLL %d @ %d\n", i, - ofnode_to_offset(plloff[i])); - if (!ofnode_valid(plloff[i])) + if (!pllcfg_valid[i]) continue; - - fracv = ofnode_read_u32_default(plloff[i], "frac", 0); - pll_config(priv, i, pllcfg[i], fracv); - ret = ofnode_read_u32_array(plloff[i], "csg", csg, PLLCSG_NB); - if (!ret) { - pll_csg(priv, i, csg); - } else if (ret != -FDT_ERR_NOTFOUND) { - debug("invalid csg node for pll@%d res=%d\n", i, ret); - return ret; - } + debug("configure PLL %d\n", i); + pll_config(priv, i, pllcfg[i], pllfracv[i]); + if (pllcsg_set[i]) + pll_csg(priv, i, pllcsg[i]); pll_start(priv, i); } /* wait and start PLLs ouptut when ready */ for (i = 0; i < _PLL_NB; i++) { - if (!ofnode_valid(plloff[i])) + if (!pllcfg_valid[i]) continue; debug("output PLL %d\n", i); pll_output(priv, i, pllcfg[i][PLLCFG_O]); @@ -2050,6 +2282,8 @@ static int stm32mp1_clk_probe(struct udevice *dev) /* clock tree init is done only one time, before relocation */ if (!(gd->flags & GD_FLG_RELOC)) result = stm32mp1_clktree(dev); + if (result) + printf("clock tree initialization failed (%d)\n", result); #endif #ifndef CONFIG_SPL_BUILD From 4e62642aef59ef89e00fe05ef1c27f263d80bcf6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:45 +0200 Subject: [PATCH 06/36] arm: stm32mp: add weak function to save vddcore Add a weak functions to save the vddcore voltage value provided in the OPP node when the clock tree is initialized. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/include/mach/sys_proto.h | 3 +++ drivers/clk/clk_stm32mp1.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 4b6c7b8bdd..4149d3a133 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -48,3 +48,6 @@ void get_soc_name(char name[SOC_NAME_SIZE]); u32 get_bootmode(void); int setup_mac_address(void); + +/* board power management : configure vddcore according OPP */ +void board_vddcore_init(u32 voltage_mv); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 8acbad25f9..c8840b9e5f 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -1229,6 +1229,10 @@ bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type) } } +__weak void board_vddcore_init(u32 voltage_mv) +{ +} + /* * gets OPP parameters (frequency in KHz and voltage in mV) from * an OPP table subnode. Platform HW support capabilities are also checked. @@ -1306,6 +1310,7 @@ int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz) return -FDT_ERR_NOTFOUND; *freq_hz = (u64)1000U * freq; + board_vddcore_init(voltage); return 0; } From d1a4b09de6431fbc2f6a9dc53efe8d84cdd31134 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:46 +0200 Subject: [PATCH 07/36] board: st: stpmic1: add function stpmic1_init Add a function stmpic_init to early initialize the PMIC STPMIC1 - keep vdd on during the reset cycle (to avoid issue when backup battery is absent) - Check if debug is enabled to program PMIC according to the bit This patch allows to remove the compilation of spl.c file from stm32mp1 board in dh_stm32mp1. CONFIG_SPL_BOARD_INIT is removed as the new function is called earlier in SPL, in the function board_early_init_f. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/Kconfig | 1 - board/dhelectronics/dh_stm32mp1/Makefile | 4 --- board/dhelectronics/dh_stm32mp1/board.c | 3 ++ board/st/common/stpmic1.c | 31 ++++++++++++++++++ board/st/common/stpmic1.h | 6 ++++ board/st/stm32mp1/spl.c | 41 ++++-------------------- board/st/stm32mp1/stm32mp1.c | 6 ++++ configs/stm32mp15_basic_defconfig | 1 + 8 files changed, 54 insertions(+), 39 deletions(-) create mode 100644 board/st/common/stpmic1.h diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 6c995ed8d8..ea7d57477b 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -1,7 +1,6 @@ if ARCH_STM32MP config SPL - select SPL_BOARD_INIT select SPL_CLK select SPL_DM select SPL_DM_SEQ_ALIAS diff --git a/board/dhelectronics/dh_stm32mp1/Makefile b/board/dhelectronics/dh_stm32mp1/Makefile index 5758d9816b..b368b396a4 100644 --- a/board/dhelectronics/dh_stm32mp1/Makefile +++ b/board/dhelectronics/dh_stm32mp1/Makefile @@ -3,10 +3,6 @@ # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # -ifdef CONFIG_SPL_BUILD -obj-y += ../../st/stm32mp1/spl.o -endif - obj-y += ../../st/common/stpmic1.o board.o obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += ../../st/common/stm32mp_mtdparts.o diff --git a/board/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c index 26e827bc38..0e745ec733 100644 --- a/board/dhelectronics/dh_stm32mp1/board.c +++ b/board/dhelectronics/dh_stm32mp1/board.c @@ -41,6 +41,7 @@ #include #include #include +#include "../../st/common/stpmic1.h" /* SYSCFG registers */ #define SYSCFG_BOOTR 0x00 @@ -198,6 +199,8 @@ int board_stm32mp1_ddr_config_name_match(struct udevice *dev, int board_early_init_f(void) { + if (IS_ENABLED(CONFIG_SPL_BUILD)) + stpmic1_init(); board_get_coding_straps(); return 0; diff --git a/board/st/common/stpmic1.c b/board/st/common/stpmic1.c index 41111c5923..85f950575f 100644 --- a/board/st/common/stpmic1.c +++ b/board/st/common/stpmic1.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -162,3 +163,33 @@ int board_ddr_power_init(enum ddr_type ddr_type) return 0; } + +/* early init of PMIC */ +void stpmic1_init(void) +{ + struct udevice *dev; + + if (uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmic1), &dev)) + return; + + /* Keep vdd on during the reset cycle */ + pmic_clrsetbits(dev, + STPMIC1_BUCKS_MRST_CR, + STPMIC1_MRST_BUCK(STPMIC1_BUCK3), + STPMIC1_MRST_BUCK(STPMIC1_BUCK3)); + + /* Check if debug is enabled to program PMIC according to the bit */ + if (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_DEBUG_ON) { + printf("Keep debug unit ON\n"); + + pmic_clrsetbits(dev, STPMIC1_BUCKS_MRST_CR, + STPMIC1_MRST_BUCK_DEBUG, + STPMIC1_MRST_BUCK_DEBUG); + + if (STPMIC1_MRST_LDO_DEBUG) + pmic_clrsetbits(dev, STPMIC1_LDOS_MRST_CR, + STPMIC1_MRST_LDO_DEBUG, + STPMIC1_MRST_LDO_DEBUG); + } +} diff --git a/board/st/common/stpmic1.h b/board/st/common/stpmic1.h new file mode 100644 index 0000000000..ecc3276697 --- /dev/null +++ b/board/st/common/stpmic1.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +void stpmic1_init(void); diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index e65ff288ea..fa25cefd28 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -5,41 +5,14 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "../common/stpmic1.h" -void spl_board_init(void) +int board_early_init_f(void) { - /* Keep vdd on during the reset cycle */ -#if defined(CONFIG_PMIC_STPMIC1) && defined(CONFIG_SPL_POWER_SUPPORT) - struct udevice *dev; - int ret; + if (IS_ENABLED(CONFIG_PMIC_STPMIC1) && CONFIG_IS_ENABLED(POWER_SUPPORT)) + stpmic1_init(); - ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(pmic_stpmic1), &dev); - if (!ret) - pmic_clrsetbits(dev, - STPMIC1_BUCKS_MRST_CR, - STPMIC1_MRST_BUCK(STPMIC1_BUCK3), - STPMIC1_MRST_BUCK(STPMIC1_BUCK3)); - - /* Check if debug is enabled to program PMIC according to the bit */ - if ((readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_DEBUG_ON) && !ret) { - printf("Keep debug unit ON\n"); - - pmic_clrsetbits(dev, STPMIC1_BUCKS_MRST_CR, - STPMIC1_MRST_BUCK_DEBUG, - STPMIC1_MRST_BUCK_DEBUG); - - if (STPMIC1_MRST_LDO_DEBUG) - pmic_clrsetbits(dev, STPMIC1_LDOS_MRST_CR, - STPMIC1_MRST_LDO_DEBUG, - STPMIC1_MRST_LDO_DEBUG); - } -#endif + return 0; } diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 4553329b25..4cea5bd021 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -84,6 +84,12 @@ DECLARE_GLOBAL_DATA_PTR; #define USB_START_LOW_THRESHOLD_UV 1230000 #define USB_START_HIGH_THRESHOLD_UV 2150000 +int board_early_init_f(void) +{ + /* nothing to do, only used in SPL */ + return 0; +} + int checkboard(void) { int ret; diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index ecdbac65ff..28363e900e 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -18,6 +18,7 @@ CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" +CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 CONFIG_SPL_I2C_SUPPORT=y From 2f238327b7273656eb7670804fdb16de097b39b9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:47 +0200 Subject: [PATCH 08/36] board: stm32mp1: update vddcore in SPL For board using STPMIC1, the vddcore is provided by BUCK1 of STPMIC1 and need to be updated for 800MHz support and only after the clock tree initialization. The VDDCORE voltage value is provided by clock driver, saved in global variable opp_voltage_mv and udpated in SPL board_early_init_f(), just after clock tree initialization. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/dhelectronics/dh_stm32mp1/board.c | 9 ++++++++- board/st/common/stpmic1.c | 23 ++++++++++++++++++++++- board/st/common/stpmic1.h | 2 +- board/st/stm32mp1/spl.c | 11 ++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/board/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c index 0e745ec733..b2b4f3974d 100644 --- a/board/dhelectronics/dh_stm32mp1/board.c +++ b/board/dhelectronics/dh_stm32mp1/board.c @@ -140,6 +140,7 @@ int checkboard(void) static u8 brdcode __section("data"); static u8 ddr3code __section("data"); static u8 somcode __section("data"); +static u32 opp_voltage_mv __section(".data"); static void board_get_coding_straps(void) { @@ -197,10 +198,16 @@ int board_stm32mp1_ddr_config_name_match(struct udevice *dev, return -EINVAL; } +void board_vddcore_init(u32 voltage_mv) +{ + if (IS_ENABLED(CONFIG_SPL_BUILD)) + opp_voltage_mv = voltage_mv; +} + int board_early_init_f(void) { if (IS_ENABLED(CONFIG_SPL_BUILD)) - stpmic1_init(); + stpmic1_init(opp_voltage_mv); board_get_coding_straps(); return 0; diff --git a/board/st/common/stpmic1.c b/board/st/common/stpmic1.c index 85f950575f..3aa379e8a5 100644 --- a/board/st/common/stpmic1.c +++ b/board/st/common/stpmic1.c @@ -164,8 +164,25 @@ int board_ddr_power_init(enum ddr_type ddr_type) return 0; } +static int stmpic_buck1_set(struct udevice *dev, u32 voltage_mv) +{ + u32 value; + + /* VDDCORE= STMPCI1 BUCK1 ramp=+25mV, 5 => 725mV, 36 => 1500mV */ + value = ((voltage_mv - 725) / 25) + 5; + if (value < 5) + value = 5; + if (value > 36) + value = 36; + + return pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK1), + STPMIC1_BUCK_VOUT_MASK, + STPMIC1_BUCK_VOUT(value)); +} + /* early init of PMIC */ -void stpmic1_init(void) +void stpmic1_init(u32 voltage_mv) { struct udevice *dev; @@ -173,6 +190,10 @@ void stpmic1_init(void) DM_GET_DRIVER(pmic_stpmic1), &dev)) return; + /* update VDDCORE = BUCK1 */ + if (voltage_mv) + stmpic_buck1_set(dev, voltage_mv); + /* Keep vdd on during the reset cycle */ pmic_clrsetbits(dev, STPMIC1_BUCKS_MRST_CR, diff --git a/board/st/common/stpmic1.h b/board/st/common/stpmic1.h index ecc3276697..b17d6f1633 100644 --- a/board/st/common/stpmic1.h +++ b/board/st/common/stpmic1.h @@ -3,4 +3,4 @@ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved */ -void stpmic1_init(void); +void stpmic1_init(u32 voltage_mv); diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index fa25cefd28..9a83da8fd3 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -9,10 +9,19 @@ #include #include "../common/stpmic1.h" +/* board early initialisation in board_f: need to use global variable */ +static u32 opp_voltage_mv __section(".data"); + +void board_vddcore_init(u32 voltage_mv) +{ + if (IS_ENABLED(CONFIG_PMIC_STPMIC1) && CONFIG_IS_ENABLED(POWER_SUPPORT)) + opp_voltage_mv = voltage_mv; +} + int board_early_init_f(void) { if (IS_ENABLED(CONFIG_PMIC_STPMIC1) && CONFIG_IS_ENABLED(POWER_SUPPORT)) - stpmic1_init(); + stpmic1_init(opp_voltage_mv); return 0; } From 4a87fea6de30b6e9c59a5abb6da1d0d84c984d15 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:48 +0200 Subject: [PATCH 09/36] ARM: dts: stm32mp1: use OPP information for PLL1 settings in SPL This patch allows to switch the CPU frequency to 800MHz on the ST Microelectronics board (DK1/DK2 and EV1) or dh electronics SOM using the STM32MP15x SOC and when it is supported by the HW (for STM32MP15xD and STM32MP15xF). Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15-u-boot.dtsi | 10 ++++++++++ arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 9 --------- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 9 --------- arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi | 9 --------- arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi | 9 --------- 5 files changed, 10 insertions(+), 36 deletions(-) diff --git a/arch/arm/dts/stm32mp15-u-boot.dtsi b/arch/arm/dts/stm32mp15-u-boot.dtsi index a0d971ad88..66be7df9ae 100644 --- a/arch/arm/dts/stm32mp15-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15-u-boot.dtsi @@ -88,6 +88,16 @@ u-boot,dm-pre-reloc; }; +&cpu0_opp_table { + u-boot,dm-spl; + opp-650000000 { + u-boot,dm-spl; + }; + opp-800000000 { + u-boot,dm-spl; + }; +}; + &gpioa { u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index e13dade463..7b8c1c1cc7 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -133,15 +133,6 @@ CLK_LPTIM45_LSE >; - /* VCO = 1300.0 MHz => P = 650 (CPU) */ - pll1: st,pll@0 { - compatible = "st,stm32mp1-pll"; - reg = <0>; - cfg = < 2 80 0 0 0 PQR(1,0,0) >; - frac = < 0x800 >; - u-boot,dm-pre-reloc; - }; - /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { compatible = "st,stm32mp1-pll"; diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index b16dc28d47..ef3e7f45a3 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -129,15 +129,6 @@ CLK_LPTIM45_LSE >; - /* VCO = 1300.0 MHz => P = 650 (CPU) */ - pll1: st,pll@0 { - compatible = "st,stm32mp1-pll"; - reg = <0>; - cfg = < 2 80 0 0 0 PQR(1,0,0) >; - frac = < 0x800 >; - u-boot,dm-pre-reloc; - }; - /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { compatible = "st,stm32mp1-pll"; diff --git a/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi index df63ad4a24..69c5af4241 100644 --- a/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi @@ -235,15 +235,6 @@ CLK_LPTIM45_LSE >; - /* VCO = 1300.0 MHz => P = 650 (CPU) */ - pll1: st,pll@0 { - compatible = "st,stm32mp1-pll"; - reg = <0>; - cfg = < 2 80 0 0 0 PQR(1,0,0) >; - frac = < 0x800 >; - u-boot,dm-pre-reloc; - }; - /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { compatible = "st,stm32mp1-pll"; diff --git a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi index bd4c2adc35..7529068c51 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi @@ -114,15 +114,6 @@ CLK_LPTIM45_LSE >; - /* VCO = 1300.0 MHz => P = 650 (CPU) */ - pll1: st,pll@0 { - compatible = "st,stm32mp1-pll"; - reg = <0>; - cfg = < 2 80 0 0 0 PQR(1,0,0) >; - frac = < 0x800 >; - u-boot,dm-pre-reloc; - }; - /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { compatible = "st,stm32mp1-pll"; From 4fb46816c7e2defe01213c09742e06322a9e5f62 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 May 2020 12:19:49 +0200 Subject: [PATCH 10/36] board: stm32mp1: move the function board_debug_uart_init in spl.c Move the debug function board_debug_uart_init in spl.c as the debug_uart_init() function is called in arch_cpu_init() only for SPL and remove the board.c file. For TFABOOT, the UART TX pin configuration is done in TF-A. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/stm32mp1/Makefile | 2 -- board/st/stm32mp1/spl.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/board/st/stm32mp1/Makefile b/board/st/stm32mp1/Makefile index 8188075b1a..65560df290 100644 --- a/board/st/stm32mp1/Makefile +++ b/board/st/stm32mp1/Makefile @@ -8,5 +8,3 @@ obj-y += spl.o else obj-y += stm32mp1.o endif - -obj-y += board.o diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index 9a83da8fd3..a6a41780c9 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -6,7 +6,10 @@ #include #include #include +#include #include +#include +#include #include "../common/stpmic1.h" /* board early initialisation in board_f: need to use global variable */ @@ -25,3 +28,28 @@ int board_early_init_f(void) return 0; } + +#ifdef CONFIG_DEBUG_UART_BOARD_INIT +void board_debug_uart_init(void) +{ +#if (CONFIG_DEBUG_UART_BASE == STM32_UART4_BASE) + +#define RCC_MP_APB1ENSETR (STM32_RCC_BASE + 0x0A00) +#define RCC_MP_AHB4ENSETR (STM32_RCC_BASE + 0x0A28) + + /* UART4 clock enable */ + setbits_le32(RCC_MP_APB1ENSETR, BIT(16)); + +#define GPIOG_BASE 0x50008000 + /* GPIOG clock enable */ + writel(BIT(6), RCC_MP_AHB4ENSETR); + /* GPIO configuration for ST boards: Uart4 TX = G11 */ + writel(0xffbfffff, GPIOG_BASE + 0x00); + writel(0x00006000, GPIOG_BASE + 0x24); +#else + +#error("CONFIG_DEBUG_UART_BASE: not supported value") + +#endif +} +#endif From 9ebc326c08d9acc0939977d26435b6f6755596b0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:23 +0200 Subject: [PATCH 11/36] configs: stm32mp1: activate CONFIG_GPIO_HOG This patch activates the new configuration CONFIG_GPIO_HOG. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 28363e900e..7347070c88 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -76,6 +76,7 @@ CONFIG_FASTBOOT_BUF_SIZE=0x02000000 CONFIG_FASTBOOT_USB_DEV=1 CONFIG_FASTBOOT_FLASH=y CONFIG_FASTBOOT_FLASH_MMC_DEV=1 +CONFIG_GPIO_HOG=y CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y CONFIG_DM_I2C=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index ca4a10813b..97a27986a9 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -59,6 +59,7 @@ CONFIG_FASTBOOT_BUF_SIZE=0x02000000 CONFIG_FASTBOOT_USB_DEV=1 CONFIG_FASTBOOT_FLASH=y CONFIG_FASTBOOT_FLASH_MMC_DEV=1 +CONFIG_GPIO_HOG=y CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y CONFIG_DM_I2C=y From 29e4ce3c970f7a183d1218a78d82891d07bf801d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:24 +0200 Subject: [PATCH 12/36] board: stm32mp1: update the gpio hog support This patch updates the current gpio hog implementation and uses the new API gpio_hog_probe_all(), activated with CONFIG_GPIO_HOG. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 4cea5bd021..c5c89d27e5 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -670,17 +670,11 @@ static void board_ev1_init(void) /* board dependent setup after realloc */ int board_init(void) { - struct udevice *dev; - /* address of boot parameters */ gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100; - /* probe all PINCTRL for hog */ - for (uclass_first_device(UCLASS_PINCTRL, &dev); - dev; - uclass_next_device(&dev)) { - pr_debug("probe pincontrol = %s\n", dev->name); - } + if (CONFIG_IS_ENABLED(DM_GPIO_HOG)) + gpio_hog_probe_all(); board_key_check(); From f13ff88b61c32ac8f0e9068c41328b265ef619eb Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:25 +0200 Subject: [PATCH 13/36] gpio: stm32: add ops set_dir_flags Manage flags for GPIO configuration: - open_drain, open_source, push_pull - pull_up, pull_down Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/gpio/stm32_gpio.c | 90 +++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 4f710b6b6a..f120ee9808 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -18,9 +18,48 @@ #include #include -#define MODE_BITS(gpio_pin) (gpio_pin * 2) +#define MODE_BITS(gpio_pin) ((gpio_pin) * 2) #define MODE_BITS_MASK 3 -#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) +#define BSRR_BIT(gpio_pin, value) BIT((gpio_pin) + (value ? 0 : 16)) + +#define PUPD_BITS(gpio_pin) ((gpio_pin) * 2) +#define PUPD_MASK 3 + +#define OTYPE_BITS(gpio_pin) (gpio_pin) +#define OTYPE_MSK 1 + +static void stm32_gpio_set_moder(struct stm32_gpio_regs *regs, + int idx, + int mode) +{ + int bits_index; + int mask; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + clrsetbits_le32(®s->moder, mask, mode << bits_index); +} + +static void stm32_gpio_set_otype(struct stm32_gpio_regs *regs, + int idx, + enum stm32_gpio_otype otype) +{ + int bits; + + bits = OTYPE_BITS(idx); + clrsetbits_le32(®s->otyper, OTYPE_MSK << bits, otype << bits); +} + +static void stm32_gpio_set_pupd(struct stm32_gpio_regs *regs, + int idx, + enum stm32_gpio_pupd pupd) +{ + int bits; + + bits = PUPD_BITS(idx); + clrsetbits_le32(®s->pupdr, PUPD_MASK << bits, pupd << bits); +} /* * convert gpio offset to gpio index taking into account gpio holes @@ -47,18 +86,13 @@ static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index; - int mask; int idx; idx = stm32_offset_to_index(dev, offset); if (idx < 0) return idx; - bits_index = MODE_BITS(idx); - mask = MODE_BITS_MASK << bits_index; - - clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN); return 0; } @@ -68,18 +102,13 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index; - int mask; int idx; idx = stm32_offset_to_index(dev, offset); if (idx < 0) return idx; - bits_index = MODE_BITS(idx); - mask = MODE_BITS_MASK << bits_index; - - clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT); writel(BSRR_BIT(idx, value), ®s->bsrr); @@ -141,12 +170,45 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) return GPIOF_FUNC; } +static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, + ulong flags) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + if (flags & GPIOD_IS_OUT) { + int value = GPIOD_FLAGS_OUTPUT(flags); + + if (flags & GPIOD_OPEN_DRAIN) + stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD); + else + stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP); + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT); + writel(BSRR_BIT(idx, value), ®s->bsrr); + + } else if (flags & GPIOD_IS_IN) { + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN); + if (flags & GPIOD_PULL_UP) + stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_UP); + else if (flags & GPIOD_PULL_DOWN) + stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_DOWN); + } + + return 0; +} + static const struct dm_gpio_ops gpio_stm32_ops = { .direction_input = stm32_gpio_direction_input, .direction_output = stm32_gpio_direction_output, .get_value = stm32_gpio_get_value, .set_value = stm32_gpio_set_value, .get_function = stm32_gpio_get_function, + .set_dir_flags = stm32_gpio_set_dir_flags, }; static int gpio_stm32_probe(struct udevice *dev) From 43efbb6a3ebf0223f9eab8d45916f602d876319f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:26 +0200 Subject: [PATCH 14/36] gpio: stm32: add ops get_dir_flags Add ops get_dir_flags() to read dir flags from GPIO registers. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/gpio/stm32_gpio.c | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index f120ee9808..5bff27f75b 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -41,6 +41,11 @@ static void stm32_gpio_set_moder(struct stm32_gpio_regs *regs, clrsetbits_le32(®s->moder, mask, mode << bits_index); } +static int stm32_gpio_get_moder(struct stm32_gpio_regs *regs, int idx) +{ + return (readl(®s->moder) >> MODE_BITS(idx)) & MODE_BITS_MASK; +} + static void stm32_gpio_set_otype(struct stm32_gpio_regs *regs, int idx, enum stm32_gpio_otype otype) @@ -51,6 +56,12 @@ static void stm32_gpio_set_otype(struct stm32_gpio_regs *regs, clrsetbits_le32(®s->otyper, OTYPE_MSK << bits, otype << bits); } +static enum stm32_gpio_otype stm32_gpio_get_otype(struct stm32_gpio_regs *regs, + int idx) +{ + return (readl(®s->otyper) >> OTYPE_BITS(idx)) & OTYPE_MSK; +} + static void stm32_gpio_set_pupd(struct stm32_gpio_regs *regs, int idx, enum stm32_gpio_pupd pupd) @@ -61,6 +72,12 @@ static void stm32_gpio_set_pupd(struct stm32_gpio_regs *regs, clrsetbits_le32(®s->pupdr, PUPD_MASK << bits, pupd << bits); } +static enum stm32_gpio_pupd stm32_gpio_get_pupd(struct stm32_gpio_regs *regs, + int idx) +{ + return (readl(®s->pupdr) >> PUPD_BITS(idx)) & PUPD_MASK; +} + /* * convert gpio offset to gpio index taking into account gpio holes * into gpio bank @@ -202,6 +219,47 @@ static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, return 0; } +static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, + ulong *flags) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; + ulong dir_flags = 0; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + switch (stm32_gpio_get_moder(regs, idx)) { + case STM32_GPIO_MODE_OUT: + dir_flags |= GPIOD_IS_OUT; + if (stm32_gpio_get_otype(regs, idx) == STM32_GPIO_OTYPE_OD) + dir_flags |= GPIOD_OPEN_DRAIN; + if (readl(®s->idr) & BIT(idx)) + dir_flags |= GPIOD_IS_OUT_ACTIVE; + break; + case STM32_GPIO_MODE_IN: + dir_flags |= GPIOD_IS_IN; + switch (stm32_gpio_get_pupd(regs, idx)) { + case STM32_GPIO_PUPD_UP: + dir_flags |= GPIOD_PULL_UP; + break; + case STM32_GPIO_PUPD_DOWN: + dir_flags |= GPIOD_PULL_DOWN; + break; + default: + break; + } + break; + default: + break; + } + *flags = dir_flags; + + return 0; +} + static const struct dm_gpio_ops gpio_stm32_ops = { .direction_input = stm32_gpio_direction_input, .direction_output = stm32_gpio_direction_output, @@ -209,6 +267,7 @@ static const struct dm_gpio_ops gpio_stm32_ops = { .set_value = stm32_gpio_set_value, .get_function = stm32_gpio_get_function, .set_dir_flags = stm32_gpio_set_dir_flags, + .get_dir_flags = stm32_gpio_get_dir_flags, }; static int gpio_stm32_probe(struct udevice *dev) From 84115cd06648f45e1496e3a55b08a654f8e3a258 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:27 +0200 Subject: [PATCH 15/36] gpio: stmfx: move function to prepare new ops introduction Move the functions stmfx_pinctrl_set_pupd and stmfx_pinctrl_set_type; they can be used by the new ops get_dir_flags and set_dir_flags introduced by next patch. No functional change. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 60 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index a3240ccd5a..d74121725c 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -74,6 +74,36 @@ static int stmfx_write(struct udevice *dev, uint offset, unsigned int val) return dm_i2c_reg_write(dev_get_parent(dev), offset, val); } +static int stmfx_pinctrl_set_pupd(struct udevice *dev, + unsigned int pin, u32 pupd) +{ + u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin); + u32 mask = get_mask(pin); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + ret = (ret & ~mask) | (pupd ? mask : 0); + + return stmfx_write(dev, reg, ret); +} + +static int stmfx_pinctrl_set_type(struct udevice *dev, + unsigned int pin, u32 type) +{ + u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin); + u32 mask = get_mask(pin); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + ret = (ret & ~mask) | (type ? mask : 0); + + return stmfx_write(dev, reg, ret); +} + static int stmfx_gpio_get(struct udevice *dev, unsigned int offset) { u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset); @@ -190,36 +220,6 @@ static const struct pinconf_param stmfx_pinctrl_conf_params[] = { { "output-low", PIN_CONFIG_OUTPUT, 0 }, }; -static int stmfx_pinctrl_set_pupd(struct udevice *dev, - unsigned int pin, u32 pupd) -{ - u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin); - u32 mask = get_mask(pin); - int ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - ret = (ret & ~mask) | (pupd ? mask : 0); - - return stmfx_write(dev, reg, ret); -} - -static int stmfx_pinctrl_set_type(struct udevice *dev, - unsigned int pin, u32 type) -{ - u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin); - u32 mask = get_mask(pin); - int ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - ret = (ret & ~mask) | (type ? mask : 0); - - return stmfx_write(dev, reg, ret); -} - static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, unsigned int param, unsigned int arg) { From 067c7398d5748d1b29df6aa1d5059a528310e4f7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:28 +0200 Subject: [PATCH 16/36] gpio: stmfx: rename function used to change pin configuration Rename the two function used to change the pin configuration from stmfx_pinctrl_.. stmfx_conf_... to clarify the function usage. No functional change. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index d74121725c..657ca2e240 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -74,8 +74,7 @@ static int stmfx_write(struct udevice *dev, uint offset, unsigned int val) return dm_i2c_reg_write(dev_get_parent(dev), offset, val); } -static int stmfx_pinctrl_set_pupd(struct udevice *dev, - unsigned int pin, u32 pupd) +static int stmfx_conf_set_pupd(struct udevice *dev, unsigned int pin, u32 pupd) { u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin); u32 mask = get_mask(pin); @@ -89,8 +88,7 @@ static int stmfx_pinctrl_set_pupd(struct udevice *dev, return stmfx_write(dev, reg, ret); } -static int stmfx_pinctrl_set_type(struct udevice *dev, - unsigned int pin, u32 type) +static int stmfx_conf_set_type(struct udevice *dev, unsigned int pin, u32 type) { u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin); u32 mask = get_mask(pin); @@ -235,22 +233,22 @@ static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_DRIVE_PUSH_PULL: - ret = stmfx_pinctrl_set_type(dev, pin, 0); + ret = stmfx_conf_set_type(dev, pin, 0); break; case PIN_CONFIG_BIAS_PULL_DOWN: - ret = stmfx_pinctrl_set_type(dev, pin, 1); + ret = stmfx_conf_set_type(dev, pin, 1); if (ret) return ret; - ret = stmfx_pinctrl_set_pupd(dev, pin, 0); + ret = stmfx_conf_set_pupd(dev, pin, 0); break; case PIN_CONFIG_BIAS_PULL_UP: - ret = stmfx_pinctrl_set_type(dev, pin, 1); + ret = stmfx_conf_set_type(dev, pin, 1); if (ret) return ret; - ret = stmfx_pinctrl_set_pupd(dev, pin, 1); + ret = stmfx_conf_set_pupd(dev, pin, 1); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - ret = stmfx_pinctrl_set_type(dev, pin, 1); + ret = stmfx_conf_set_type(dev, pin, 1); break; case PIN_CONFIG_OUTPUT: ret = stmfx_gpio_direction_output(plat->gpio, pin, arg); From fabb6e14c86d8d38beaaade8bc18a678cdc06c0a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:29 +0200 Subject: [PATCH 17/36] gpio: stmfx: add function stmfx_read_reg and stmfx_write_reg Add the helper functions stmfx_read_reg() and stmfx_write_reg() to avoid duplicated code for access to stmfx's register with mask. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 98 ++++++++++++++------------------- 1 file changed, 41 insertions(+), 57 deletions(-) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 657ca2e240..5d15424b84 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -74,45 +74,51 @@ static int stmfx_write(struct udevice *dev, uint offset, unsigned int val) return dm_i2c_reg_write(dev_get_parent(dev), offset, val); } -static int stmfx_conf_set_pupd(struct udevice *dev, unsigned int pin, u32 pupd) +static int stmfx_read_reg(struct udevice *dev, u8 reg_base, uint offset) { - u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin); - u32 mask = get_mask(pin); - int ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - ret = (ret & ~mask) | (pupd ? mask : 0); - - return stmfx_write(dev, reg, ret); -} - -static int stmfx_conf_set_type(struct udevice *dev, unsigned int pin, u32 type) -{ - u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin); - u32 mask = get_mask(pin); - int ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - ret = (ret & ~mask) | (type ? mask : 0); - - return stmfx_write(dev, reg, ret); -} - -static int stmfx_gpio_get(struct udevice *dev, unsigned int offset) -{ - u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset); + u8 reg = reg_base + get_reg(offset); u32 mask = get_mask(offset); int ret; ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; return ret < 0 ? ret : !!(ret & mask); } +static int stmfx_write_reg(struct udevice *dev, u8 reg_base, uint offset, + uint val) +{ + u8 reg = reg_base + get_reg(offset); + u32 mask = get_mask(offset); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + ret = (ret & ~mask) | (val ? mask : 0); + + return stmfx_write(dev, reg, ret); +} + +static int stmfx_conf_set_pupd(struct udevice *dev, unsigned int offset, + uint pupd) +{ + return stmfx_write_reg(dev, STMFX_REG_GPIO_PUPD, offset, pupd); +} + +static int stmfx_conf_set_type(struct udevice *dev, unsigned int offset, + uint type) +{ + return stmfx_write_reg(dev, STMFX_REG_GPIO_TYPE, offset, type); +} + +static int stmfx_gpio_get(struct udevice *dev, unsigned int offset) +{ + return stmfx_read_reg(dev, STMFX_REG_GPIO_STATE, offset); +} + static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value) { u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR; @@ -123,50 +129,28 @@ static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value) static int stmfx_gpio_get_function(struct udevice *dev, unsigned int offset) { - u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); - u32 mask = get_mask(offset); - int ret; - - ret = stmfx_read(dev, reg); + int ret = stmfx_read_reg(dev, STMFX_REG_GPIO_DIR, offset); if (ret < 0) return ret; /* On stmfx, gpio pins direction is (0)input, (1)output. */ - return ret & mask ? GPIOF_OUTPUT : GPIOF_INPUT; + return ret ? GPIOF_OUTPUT : GPIOF_INPUT; } static int stmfx_gpio_direction_input(struct udevice *dev, unsigned int offset) { - u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); - u32 mask = get_mask(offset); - int ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - - ret &= ~mask; - - return stmfx_write(dev, reg, ret & ~mask); + return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 0); } static int stmfx_gpio_direction_output(struct udevice *dev, unsigned int offset, int value) { - u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); - u32 mask = get_mask(offset); - int ret; - - ret = stmfx_gpio_set(dev, offset, value); + int ret = stmfx_gpio_set(dev, offset, value); if (ret < 0) return ret; - ret = stmfx_read(dev, reg); - if (ret < 0) - return ret; - - return stmfx_write(dev, reg, ret | mask); + return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1); } static int stmfx_gpio_probe(struct udevice *dev) From 22b3fe4224a9929d025767ec600226de984d0246 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:30 +0200 Subject: [PATCH 18/36] gpio: stmfx: add ops set_dir_flag Manage the flags for GPIO configuration: - open_drain, push_pull - pull_up, pull_down Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 5d15424b84..88df9e61a7 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -153,6 +153,42 @@ static int stmfx_gpio_direction_output(struct udevice *dev, return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1); } +static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, + ulong flags) +{ + int ret = -ENOTSUPP; + + if (flags & GPIOD_IS_OUT) { + if (flags & GPIOD_OPEN_SOURCE) + return -ENOTSUPP; + if (flags & GPIOD_OPEN_DRAIN) + ret = stmfx_conf_set_type(dev, offset, 0); + else /* PUSH-PULL */ + ret = stmfx_conf_set_type(dev, offset, 1); + if (ret) + return ret; + ret = stmfx_gpio_direction_output(dev, offset, + GPIOD_FLAGS_OUTPUT(flags)); + } else if (flags & GPIOD_IS_IN) { + ret = stmfx_gpio_direction_input(dev, offset); + if (ret) + return ret; + if (flags & GPIOD_PULL_UP) { + ret = stmfx_conf_set_type(dev, offset, 1); + if (ret) + return ret; + ret = stmfx_conf_set_pupd(dev, offset, 1); + } else if (flags & GPIOD_PULL_DOWN) { + ret = stmfx_conf_set_type(dev, offset, 1); + if (ret) + return ret; + ret = stmfx_conf_set_pupd(dev, offset, 0); + } + } + + return ret; +} + static int stmfx_gpio_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); @@ -181,6 +217,7 @@ static const struct dm_gpio_ops stmfx_gpio_ops = { .get_function = stmfx_gpio_get_function, .direction_input = stmfx_gpio_direction_input, .direction_output = stmfx_gpio_direction_output, + .set_dir_flags = stmfx_gpio_set_dir_flags, }; U_BOOT_DRIVER(stmfx_gpio) = { From 8d895efffe2313acc419caee53414f2903b8a39c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:31 +0200 Subject: [PATCH 19/36] gpio: stmfx: add ops get_dir_flags Add support of ops get_dir_flags() to read dir flags from STMFX registers. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 88df9e61a7..1d326ecf17 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -108,12 +108,22 @@ static int stmfx_conf_set_pupd(struct udevice *dev, unsigned int offset, return stmfx_write_reg(dev, STMFX_REG_GPIO_PUPD, offset, pupd); } +static int stmfx_conf_get_pupd(struct udevice *dev, unsigned int offset) +{ + return stmfx_read_reg(dev, STMFX_REG_GPIO_PUPD, offset); +} + static int stmfx_conf_set_type(struct udevice *dev, unsigned int offset, uint type) { return stmfx_write_reg(dev, STMFX_REG_GPIO_TYPE, offset, type); } +static int stmfx_conf_get_type(struct udevice *dev, unsigned int offset) +{ + return stmfx_read_reg(dev, STMFX_REG_GPIO_TYPE, offset); +} + static int stmfx_gpio_get(struct udevice *dev, unsigned int offset) { return stmfx_read_reg(dev, STMFX_REG_GPIO_STATE, offset); @@ -189,6 +199,45 @@ static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, return ret; } +static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, + ulong *flags) +{ + ulong dir_flags = 0; + int ret; + + if (stmfx_gpio_get_function(dev, offset) == GPIOF_OUTPUT) { + dir_flags |= GPIOD_IS_OUT; + ret = stmfx_conf_get_type(dev, offset); + if (ret < 0) + return ret; + if (ret == 0) + dir_flags |= GPIOD_OPEN_DRAIN; + /* 1 = push-pull (default), open source not supported */ + ret = stmfx_gpio_get(dev, offset); + if (ret < 0) + return ret; + if (ret) + dir_flags |= GPIOD_IS_OUT_ACTIVE; + } else { + dir_flags |= GPIOD_IS_IN; + ret = stmfx_conf_get_type(dev, offset); + if (ret < 0) + return ret; + if (ret == 1) { + ret = stmfx_conf_get_pupd(dev, offset); + if (ret < 0) + return ret; + if (ret == 1) + dir_flags |= GPIOD_PULL_UP; + else + dir_flags |= GPIOD_PULL_DOWN; + } + } + *flags = dir_flags; + + return 0; +} + static int stmfx_gpio_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); @@ -218,6 +267,7 @@ static const struct dm_gpio_ops stmfx_gpio_ops = { .direction_input = stmfx_gpio_direction_input, .direction_output = stmfx_gpio_direction_output, .set_dir_flags = stmfx_gpio_set_dir_flags, + .get_dir_flags = stmfx_gpio_get_dir_flags, }; U_BOOT_DRIVER(stmfx_gpio) = { From 5593333c2e4f674210a7415b6f61c16f7f3a4593 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:32 +0200 Subject: [PATCH 20/36] pinctrl: stmfx: add information on pin configuration Add information on pin configuration used for pinmux command. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl-stmfx.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 1d326ecf17..c2ea82770e 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -358,6 +358,34 @@ static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev, return pin_name; } +static const char *stmfx_pinctrl_get_pin_conf(struct udevice *dev, + unsigned int pin, int func) +{ + int pupd, type; + + type = stmfx_conf_get_type(dev, pin); + if (type < 0) + return ""; + + if (func == GPIOF_OUTPUT) { + if (type) + return "drive-open-drain"; + else + return ""; /* default: push-pull*/ + } + if (!type) + return ""; /* default: bias-disable*/ + + pupd = stmfx_conf_get_pupd(dev, pin); + if (pupd < 0) + return ""; + + if (pupd) + return "bias-pull-up"; + else + return "bias-pull-down"; +} + static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev, unsigned int selector, char *buf, int size) @@ -369,7 +397,9 @@ static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev, if (func < 0) return func; - snprintf(buf, size, "%s", func == GPIOF_INPUT ? "input" : "output"); + snprintf(buf, size, "%s ", func == GPIOF_INPUT ? "input" : "output"); + + strncat(buf, stmfx_pinctrl_get_pin_conf(dev, selector, func), size); return 0; } From da7a0bb1f279221a85706bee7f75974c83d5e87a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jun 2020 14:30:33 +0200 Subject: [PATCH 21/36] pinctrl: stm32: add information on pin configuration Add information on pin configuration used for pinmux command: - bias configuration for output (disable, pull up, pull down) - otype for input (open drain or push pull) Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index fc241fdcde..71fa29a389 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -45,6 +45,17 @@ static const char * const pinmux_mode[PINMUX_MODE_COUNT] = { "alt function", }; +static const char * const pinmux_output[] = { + [STM32_GPIO_PUPD_NO] = "bias-disable", + [STM32_GPIO_PUPD_UP] = "bias-pull-up", + [STM32_GPIO_PUPD_DOWN] = "bias-pull-down", +}; + +static const char * const pinmux_input[] = { + [STM32_GPIO_OTYPE_PP] = "drive-push-pull", + [STM32_GPIO_OTYPE_OD] = "drive-open-drain", +}; + static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); @@ -182,10 +193,12 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, int size) { struct udevice *gpio_dev; + struct stm32_gpio_priv *priv; const char *label; int mode; int af_num; unsigned int gpio_idx; + u32 pupd, otype; /* look up for the bank which owns the requested pin */ gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); @@ -194,9 +207,9 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, return -ENODEV; mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label); - dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n", selector, gpio_idx, mode); + priv = dev_get_priv(gpio_dev); switch (mode) { @@ -211,9 +224,17 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num); break; case GPIOF_OUTPUT: + pupd = (readl(&priv->regs->pupdr) >> (gpio_idx * 2)) & + PUPD_MASK; + snprintf(buf, size, "%s %s %s", + pinmux_mode[mode], pinmux_output[pupd], + label ? label : ""); + break; case GPIOF_INPUT: - snprintf(buf, size, "%s %s", - pinmux_mode[mode], label ? label : ""); + otype = (readl(&priv->regs->otyper) >> gpio_idx) & OTYPE_MSK; + snprintf(buf, size, "%s %s %s", + pinmux_mode[mode], pinmux_input[otype], + label ? label : ""); break; } From 2ee5005dea1a12bba096abac1f8ebeaea91bf964 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 11 Jun 2020 16:51:17 +0200 Subject: [PATCH 22/36] configs: stm32mp1: activate WATCHDOG As kernel v5.6 have a solution since so we will be able to enable the watchdog at boot time. It is reloaded by the watchdog framework (if CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set) and until the userspace watchdog daemon takes over control. Need presence of kernel patch 85fdc63fe256 ("drivers: watchdog: stm32_iwdg: set WDOG_HW_RUNNING at probe") integrated in v5.6-rc1. This patch revert the previous commit ca351e705a5c ("stm32mp1: deactivate WATCHDOG in defconfig"). Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 7347070c88..4c3bdb6063 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -144,5 +144,7 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y CONFIG_ERRNO_STR=y CONFIG_FDT_FIXUP_PARTITIONS=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 97a27986a9..4ca50d6874 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -128,5 +128,7 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y CONFIG_ERRNO_STR=y CONFIG_FDT_FIXUP_PARTITIONS=y From 8b8c99bd3e1e9463e27ccd1bca18f4a7627901aa Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 12 Jun 2020 10:40:58 +0200 Subject: [PATCH 23/36] power: regulator: stm32: vrefbuf: fix a possible overshoot when re-enabling There maybe an overshoot: - when disabling, then re-enabling vrefbuf too quickly - or upon platform reset as external capacitor maybe slow discharging (VREFBUF is HiZ at reset by default). VREFBUF is used by ADC/DAC on some boards. An overshoot on the reference voltage make the conversions inaccurate for a short period of time. So: - Don't put the VREFBUF in HiZ when disabling, to force an active discharge. - Enforce a 1ms OFF/ON delay, also upon reset Penalty is a 1ms delay is applied (even for a cold boot), when enabling VREFBUF. Fixes: 93cf0ae7758d ("power: regulator: Add support for stm32-vrefbuf") Signed-off-by: Fabrice Gasnier Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard Reviewed-by: Jaehoon Chung --- drivers/power/regulator/stm32-vrefbuf.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c index 250773514f..92136961c2 100644 --- a/drivers/power/regulator/stm32-vrefbuf.c +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -43,8 +43,20 @@ static int stm32_vrefbuf_set_enable(struct udevice *dev, bool enable) u32 val; int ret; - clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ | STM32_ENVR, - enable ? STM32_ENVR : STM32_HIZ); + if (enable && !(readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR)) { + /* + * There maybe an overshoot: + * - when disabling, then re-enabling vrefbuf too quickly + * - or upon platform reset as external capacitor maybe slow + * discharging (VREFBUF is HiZ at reset by default). + * So force active discharge (HiZ=0) for 1ms before enabling. + */ + clrbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ); + udelay(1000); + } + + clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR, + enable ? STM32_ENVR : 0); if (!enable) return 0; From 6072c220bd3f9097f92b5e9aa48584e948f7cecf Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 15 Jun 2020 11:25:13 +0200 Subject: [PATCH 24/36] stm32mp1: configs: activate CMD_ERASEENV Activate the command env erase to reset the environment with the command: > env erase it is simpler than: > env default -a > env save Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 4c3bdb6063..aa05809649 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -30,6 +30,7 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_ELF is not set # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set +CONFIG_CMD_ERASEENV=y CONFIG_CMD_MEMINFO=y CONFIG_CMD_MEMTEST=y CONFIG_SYS_MEMTEST_START=0xc0000000 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 4ca50d6874..8db52cbc51 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -14,6 +14,7 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_ELF is not set # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set +CONFIG_CMD_ERASEENV=y CONFIG_CMD_MEMINFO=y CONFIG_CMD_MEMTEST=y CONFIG_SYS_MEMTEST_START=0xc0000000 From 42400228dce2c300cf1cde921f5f2750540ec8d9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Jun 2020 18:19:28 +0200 Subject: [PATCH 25/36] board: st: stm32mp1: increase teed partition With TEE 3.7.0, the partition teed (OP-TEE pageable code and data) need to increase up to 512KB in NOR device. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/common/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/st/common/Kconfig b/board/st/common/Kconfig index 015ba40939..750dbb6451 100644 --- a/board/st/common/Kconfig +++ b/board/st/common/Kconfig @@ -39,7 +39,7 @@ config MTDPARTS_NOR0_BOOT config MTDPARTS_NOR0_TEE string "mtd tee partitions for nor0" - default "256k(teeh),256k(teed),256k(teex)" + default "256k(teeh),512k(teed),256k(teex)" depends on SYS_MTDPARTS_RUNTIME && ARCH_STM32MP help This define the tee partitions added in mtparts dynamically From 03c4e6224a0650c6de07f7000db444cd1a30b1cc Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Jun 2020 18:25:14 +0200 Subject: [PATCH 26/36] arm: stm32mp: stm32prog: add "Device Name" in iproduct during DFU USB enumeration Add "Device Name" in iproduct during DFU USB enumeration to have this information in STM32CubeProgrammer trace (this tools is compatible with @Name since v2.3) Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c index 969245e199..30547f94c9 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c @@ -197,10 +197,12 @@ bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) bool result; /* USB download gadget for STM32 Programmer */ char product[128]; + char name[SOC_NAME_SIZE]; + get_soc_name(name); snprintf(product, sizeof(product), - "USB download gadget@Device ID /0x%03X, @Revision ID /0x%04X", - get_cpu_dev(), get_cpu_rev()); + "USB download gadget@Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,", + get_cpu_dev(), get_cpu_rev(), name); g_dnl_set_product(product); if (stm32prog_data->phase == PHASE_FLASHLAYOUT) { From bd3f60d29c2494d156b353c33678be7366caafbd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Jun 2020 18:27:44 +0200 Subject: [PATCH 27/36] arm: stm32mp: protect DBGMCU_IDC access with BSEC As debugger must be totally closed on Sec closed chip, the DBGMCU_IDC register is no more accessible (self hosted debug is disabled with OTP). This patch adds a function bsec_dbgswenable() to check if the DBGMCU registers are available before to access them: BSEC_DENABLE.DBGSWENABLE = self hosted debug status. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 25 +++++++++++++++++++++++ arch/arm/mach-stm32mp/cpu.c | 22 ++++++++++++++++---- arch/arm/mach-stm32mp/include/mach/bsec.h | 7 +++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-stm32mp/include/mach/bsec.h diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 059ef0b1f5..0c56b440f5 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #define BSEC_OTP_WRDATA_OFF 0x008 #define BSEC_OTP_STATUS_OFF 0x00C #define BSEC_OTP_LOCK_OFF 0x010 +#define BSEC_DENABLE_OFF 0x014 #define BSEC_DISTURBED_OFF 0x01C #define BSEC_ERROR_OFF 0x034 #define BSEC_WRLOCK_OFF 0x04C /* OTP write permananet lock */ @@ -46,6 +48,9 @@ #define BSEC_MODE_PROGFAIL_MASK 0x10 #define BSEC_MODE_PWR_MASK 0x20 +/* DENABLE Register */ +#define BSEC_DENABLE_DBGSWENABLE BIT(10) + /* * OTP Lock services definition * Value must corresponding to the bit number in the register @@ -506,3 +511,23 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .ops = &stm32mp_bsec_ops, .probe = stm32mp_bsec_probe, }; + +bool bsec_dbgswenable(void) +{ + struct udevice *dev; + struct stm32mp_bsec_platdata *plat; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), &dev); + if (ret || !dev) { + pr_debug("bsec driver not available\n"); + return false; + } + + plat = dev_get_platdata(dev); + if (readl(plat->base + BSEC_DENABLE_OFF) & BSEC_DENABLE_DBGSWENABLE) + return true; + + return false; +} diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 472b140321..382067190c 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -155,8 +156,13 @@ static void dbgmcu_init(void) { setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); - /* Freeze IWDG2 if Cortex-A7 is in debug mode */ - setbits_le32(DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2); + /* + * Freeze IWDG2 if Cortex-A7 is in debug mode + * done in TF-A for TRUSTED boot and + * DBGMCU access is controlled by BSEC_DENABLE.DBGSWENABLE + */ + if (!IS_ENABLED(CONFIG_TFABOOT) && bsec_dbgswenable()) + setbits_le32(DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2); } #endif /* !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) */ @@ -276,9 +282,17 @@ void enable_caches(void) static u32 read_idc(void) { - setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); + /* DBGMCU access is controlled by BSEC_DENABLE.DBGSWENABLE */ + if (bsec_dbgswenable()) { + setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); - return readl(DBGMCU_IDC); + return readl(DBGMCU_IDC); + } + + if (CONFIG_IS_ENABLED(STM32MP15x)) + return CPU_DEV_STM32MP15; /* STM32MP15x and unknown revision */ + else + return 0x0; } u32 get_cpu_dev(void) diff --git a/arch/arm/mach-stm32mp/include/mach/bsec.h b/arch/arm/mach-stm32mp/include/mach/bsec.h new file mode 100644 index 0000000000..252eac3946 --- /dev/null +++ b/arch/arm/mach-stm32mp/include/mach/bsec.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +/* check self hosted debug status = BSEC_DENABLE.DBGSWENABLE */ +bool bsec_dbgswenable(void); From d5d726d3cc47691ace3c68fa31147ad104aaf579 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Jun 2020 18:30:27 +0200 Subject: [PATCH 28/36] configs: stm32mp1: only support SD card after NOR in bootcmd_stm32mp In the boot command used in ST boards, bootcmd_stm32mp, only support the SD card as second stage, where is found the bootfs with DISTRO. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- include/configs/stm32mp1.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index f271b84a59..baaf2ff89c 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -123,7 +123,7 @@ * for serial/usb: execute the stm32prog command * for mmc boot (eMMC, SD card), boot only on the same device * for nand or spi-nand boot, boot with on ubifs partition on UBI partition - * for nor boot, use the default order + * for nor boot, use SD card = mmc0 */ #define STM32MP_BOOTCMD "bootcmd_stm32mp=" \ "echo \"Boot over ${boot_device}${boot_instance}!\";" \ @@ -136,6 +136,8 @@ "if test ${boot_device} = nand ||" \ " test ${boot_device} = spi-nand ;" \ "then env set boot_targets ubifs0; fi;" \ + "if test ${boot_device} = nor;" \ + "then env set boot_targets mmc0; fi;" \ "run distro_bootcmd;" \ "fi;\0" From 03fb03842a1e16f89477d4a968712cc2422be217 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 29 Jun 2020 10:34:06 +0200 Subject: [PATCH 29/36] board: st: move type-c stusb1600 controller code in a driver Migrate the ST Microelectronics STUSB160X Type-C controller code in a generic I2C driver in st/common, based on Linux one in : drivers/usb/typec/stusb160x.c This patch simplifies the stm32mp1 board code and allows to reuse this STUSB160X driver in other boards. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/common/Kconfig | 7 ++++ board/st/common/Makefile | 2 + board/st/common/stusb160x.c | 46 +++++++++++++++++++++++ board/st/common/stusb160x.h | 10 +++++ board/st/stm32mp1/stm32mp1.c | 58 +++-------------------------- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + 7 files changed, 73 insertions(+), 52 deletions(-) create mode 100644 board/st/common/stusb160x.c create mode 100644 board/st/common/stusb160x.h diff --git a/board/st/common/Kconfig b/board/st/common/Kconfig index 750dbb6451..ddcf33a122 100644 --- a/board/st/common/Kconfig +++ b/board/st/common/Kconfig @@ -69,3 +69,10 @@ config DFU_ALT_RAM0 depends on ARCH_STM32MP && SET_DFU_ALT_INFO help This defines the partitions of ram used to build dfu dynamically. + +config TYPEC_STUSB160X + tristate "STMicroelectronics STUSB160X Type-C controller driver" + depends on DM_I2C + help + Say Y if your system has STMicroelectronics STUSB160X Type-C port + controller. diff --git a/board/st/common/Makefile b/board/st/common/Makefile index 012bfbbe8e..65bbebd6ab 100644 --- a/board/st/common/Makefile +++ b/board/st/common/Makefile @@ -10,3 +10,5 @@ ifeq ($(CONFIG_ARCH_STM32MP),y) obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += stm32mp_mtdparts.o obj-$(CONFIG_SET_DFU_ALT_INFO) += stm32mp_dfu.o endif + +obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o diff --git a/board/st/common/stusb160x.c b/board/st/common/stusb160x.c new file mode 100644 index 0000000000..f1197f9faa --- /dev/null +++ b/board/st/common/stusb160x.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * STMicroelectronics STUSB Type-C controller driver + * based on Linux drivers/usb/typec/stusb160x.c + * + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include + +/* REGISTER */ +#define STUSB160X_CC_CONNECTION_STATUS 0x0E + +/* STUSB160X_CC_CONNECTION_STATUS bitfields */ +#define STUSB160X_CC_ATTACH BIT(0) + +int stusb160x_cable_connected(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_I2C_GENERIC, + DM_GET_DRIVER(stusb160x), + &dev); + if (ret < 0) + return ret; + + ret = dm_i2c_reg_read(dev, STUSB160X_CC_CONNECTION_STATUS); + if (ret < 0) + return 0; + + return ret & STUSB160X_CC_ATTACH; +} + +static const struct udevice_id stusb160x_ids[] = { + { .compatible = "st,stusb1600" }, + {} +}; + +U_BOOT_DRIVER(stusb160x) = { + .name = "stusb160x", + .id = UCLASS_I2C_GENERIC, + .of_match = stusb160x_ids, +}; diff --git a/board/st/common/stusb160x.h b/board/st/common/stusb160x.h new file mode 100644 index 0000000000..fe39840b41 --- /dev/null +++ b/board/st/common/stusb160x.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020, STMicroelectronics + */ + +#ifdef CONFIG_TYPEC_STUSB160X +int stusb160x_cable_connected(void); +#else +int stusb160x_cable_connected(void) { return -ENODEV; } +#endif diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index c5c89d27e5..71daf18034 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -41,6 +41,8 @@ #include #include +#include "../../st/common/stusb160x.h" + /* SYSCFG registers */ #define SYSCFG_BOOTR 0x00 #define SYSCFG_PMCSETR 0x04 @@ -181,64 +183,16 @@ static void board_key_check(void) } #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) - -/* STMicroelectronics STUSB1600 Type-C controller */ -#define STUSB1600_CC_CONNECTION_STATUS 0x0E - -/* STUSB1600_CC_CONNECTION_STATUS bitfields */ -#define STUSB1600_CC_ATTACH BIT(0) - -static int stusb1600_init(struct udevice **dev_stusb1600) -{ - ofnode node; - struct udevice *dev, *bus; - int ret; - u32 chip_addr; - - *dev_stusb1600 = NULL; - - /* if node stusb1600 is present, means DK1 or DK2 board */ - node = ofnode_by_compatible(ofnode_null(), "st,stusb1600"); - if (!ofnode_valid(node)) - return -ENODEV; - - ret = ofnode_read_u32(node, "reg", &chip_addr); - if (ret) - return -EINVAL; - - ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node), - &bus); - if (ret) { - printf("bus for stusb1600 not found\n"); - return -ENODEV; - } - - ret = dm_i2c_probe(bus, chip_addr, 0, &dev); - if (!ret) - *dev_stusb1600 = dev; - - return ret; -} - -static int stusb1600_cable_connected(struct udevice *dev) -{ - u8 status; - - if (dm_i2c_read(dev, STUSB1600_CC_CONNECTION_STATUS, &status, 1)) - return 0; - - return status & STUSB1600_CC_ATTACH; -} - #include int g_dnl_board_usb_cable_connected(void) { - struct udevice *stusb1600; struct udevice *dwc2_udc_otg; int ret; - if (!stusb1600_init(&stusb1600)) - return stusb1600_cable_connected(stusb1600); + /* if typec stusb160x is present, means DK1 or DK2 board */ + ret = stusb160x_cable_connected(); + if (ret >= 0) + return ret; ret = uclass_get_device_by_driver(UCLASS_USB_GADGET_GENERIC, DM_GET_DRIVER(dwc2_udc_otg), diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index aa05809649..e68b0b8082 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -10,6 +10,7 @@ CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL=y CONFIG_TARGET_ST_STM32MP15x=y CONFIG_CMD_STM32PROG=y +CONFIG_TYPEC_STUSB160X=y CONFIG_ENV_OFFSET_REDUND=0x2C0000 CONFIG_SPL_SPI_FLASH_SUPPORT=y CONFIG_SPL_SPI_SUPPORT=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 8db52cbc51..f4aa8432a5 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -6,6 +6,7 @@ CONFIG_ENV_OFFSET=0x280000 CONFIG_ENV_SECT_SIZE=0x40000 CONFIG_TARGET_ST_STM32MP15x=y CONFIG_CMD_STM32PROG=y +CONFIG_TYPEC_STUSB160X=y CONFIG_ENV_OFFSET_REDUND=0x2C0000 CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y From 6826d0d82ba6ca2b466117aafdaa3305b666e37b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 15:20:47 +0200 Subject: [PATCH 30/36] board: dh_stm32mp1: update the gpio hog support This patch update the current gpio hog implementation with the new API gpio_hog_probe_all() activated with CONFIG_GPIO_HOG. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/dhelectronics/dh_stm32mp1/board.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/board/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c index b2b4f3974d..b8625f25d3 100644 --- a/board/dhelectronics/dh_stm32mp1/board.c +++ b/board/dhelectronics/dh_stm32mp1/board.c @@ -523,17 +523,11 @@ static void board_init_fmc2(void) /* board dependent setup after realloc */ int board_init(void) { - struct udevice *dev; - /* address of boot parameters */ gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100; - /* probe all PINCTRL for hog */ - for (uclass_first_device(UCLASS_PINCTRL, &dev); - dev; - uclass_next_device(&dev)) { - pr_debug("probe pincontrol = %s\n", dev->name); - } + if (CONFIG_IS_ENABLED(DM_GPIO_HOG)) + gpio_hog_probe_all(); board_key_check(); From 8b5206d9e48576ff94f48e98803154e0e9f8fb1d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 17:43:44 +0200 Subject: [PATCH 31/36] cmd: env: use ENV_IS_IN_DEVICE in env info Use the define ENV_IS_IN_DEVICE to test if one the CONFIG_ENV_IS_IN_... is defined and correct the detection of persistent storage support in the command "env info" if CONFIG_ENV_IS_NOWHERE is activated. Since commit 60d5ed2593c9 ("env: allow ENV_IS_NOWHERE with other storage target") test CONFIG_ENV_IS_NOWHERE is not enough; see also commit 953db29a1e9c6 ("env: enable saveenv command when one CONFIG_ENV_IS_IN is activated"). This patch avoids issue for this command in stm32mp1 platform. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard --- cmd/nvedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 08d49df220..49338b4d36 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1265,7 +1265,7 @@ static int do_env_info(struct cmd_tbl *cmdtp, int flag, /* evaluate whether environment can be persisted */ if (eval_flags & ENV_INFO_IS_PERSISTED) { -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) printf("Environment can be persisted\n"); eval_results |= ENV_INFO_IS_PERSISTED; #else From c16cba88bd469353b0f6265e1f507200f20e3d6d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 17:43:45 +0200 Subject: [PATCH 32/36] stm32mp1: use the command env info in env_check Activate CMD_NVEDIT_INFO and use the new command "env info -d -p -q" to automatically save the environment on first boot. This patch allows to remove the env_default variable. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/Kconfig | 1 + include/configs/stm32mp1.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index ea7d57477b..4003c2e38b 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -45,6 +45,7 @@ config STM32MP15x select STM32_RESET select STM32_SERIAL select SYS_ARCH_TIMER + imply CMD_NVEDIT_INFO imply SYSRESET_PSCI if TFABOOT imply SYSRESET_SYSCON if !TFABOOT help diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index baaf2ff89c..ed20b842ac 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -157,9 +157,7 @@ "splashimage=0xc4300000\0" \ "ramdisk_addr_r=0xc4400000\0" \ "altbootcmd=run bootcmd\0" \ - "env_default=1\0" \ - "env_check=if test $env_default -eq 1;"\ - " then env set env_default 0;env save;fi\0" \ + "env_check=if env info -p -d; then env save; fi\0" \ STM32MP_BOOTCMD \ BOOTENV \ "boot_net_usb_start=true\0" From 1a5be5a416e21fe243141d079f30a5e50bf6e332 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 19:56:34 +0200 Subject: [PATCH 33/36] ram: stm32mp1: protect minimum value in get_bufsize Add protection on minimum value for result of get_bufsize and check the alignment of buffer size: only multiple min_size is allowed; only 4 bytes alignment was checked previously (value & 0x3). For example the "Random" test raises an issue when size is not 8 bytes aligned because address for buffer = address + size / 2 is not word aligned. This patch avoid test error for unsupported size value. Reviewed-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- drivers/ram/stm32mp1/stm32mp1_tests.c | 37 ++++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index bacdd74705..90e82acda7 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR; static int get_bufsize(char *string, int argc, char *argv[], int arg_nb, - size_t *bufsize, size_t default_size) + size_t *bufsize, size_t default_size, size_t min_size) { unsigned long value; @@ -27,13 +27,14 @@ static int get_bufsize(char *string, int argc, char *argv[], int arg_nb, arg_nb, argv[arg_nb]); return -1; } - if (value > STM32_DDR_SIZE || value == 0) { - sprintf(string, "invalid size %s", argv[arg_nb]); + if (value > STM32_DDR_SIZE || value < min_size) { + sprintf(string, "invalid size %s (min=%d)", + argv[arg_nb], min_size); return -1; } - if (value & 0x3) { - sprintf(string, "unaligned size %s", - argv[arg_nb]); + if (value & (min_size - 1)) { + sprintf(string, "unaligned size %s (min=%d)", + argv[arg_nb], min_size); return -1; } *bufsize = value; @@ -441,7 +442,7 @@ static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl, u32 bufsize; u32 error; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (!is_power_of_2(bufsize)) { sprintf(string, "size 0x%x is not a power of 2", @@ -470,7 +471,7 @@ static enum test_result test_memdevice(struct stm32mp1_ddrctl *ctl, size_t bufsize; u32 error; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (get_addr(string, argc, argv, 1, &addr)) return TEST_ERROR; @@ -512,7 +513,7 @@ static enum test_result test_sso(struct stm32mp1_ddrctl *ctl, u32 error = 0; u32 data; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (get_addr(string, argc, argv, 1, &addr)) return TEST_ERROR; @@ -584,7 +585,7 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, u32 error = 0; unsigned int seed; - if (get_bufsize(string, argc, argv, 0, &bufsize, 8 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -744,7 +745,7 @@ static enum test_result test_noise_burst(struct stm32mp1_ddrctl *ctl, int i; enum test_result res = TEST_PASSED; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128)) return TEST_ERROR; if (get_pattern(string, argc, argv, 1, &pattern, 0xFFFFFFFF)) return TEST_ERROR; @@ -920,7 +921,7 @@ static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl, const u32 **patterns; u32 bufsize; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128)) return TEST_ERROR; switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { @@ -1007,7 +1008,7 @@ static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl, u32 checkboard[2] = {0x55555555, 0xAAAAAAAA}; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -1042,7 +1043,7 @@ static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl, u32 bufsize, nb_loop, loop = 0, addr, value; int i; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -1076,7 +1077,7 @@ static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl, u32 bufsize, nb_loop, loop = 0, addr, value; int i; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -1114,7 +1115,7 @@ static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl, u32 bufsize, nb_loop, loop = 0, addr, value; int i; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -1156,7 +1157,7 @@ static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl, u32 bufsize, nb_loop, loop = 0, addr, bitspread[4]; int i, j; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; @@ -1203,7 +1204,7 @@ static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl, u32 bitflip[4]; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; From fcd4890829dc432f6ae6057fc3736fbc463ca5c2 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 19:56:35 +0200 Subject: [PATCH 34/36] ram: stm32mp1: add parameter addr in test FrequencySelectivePattern Add a parameter addr in test FrequencySelectivePattern to select the base address used to execute the tests. Default value (when the parameter is absent) is STM32_DDR_BASE, selected in get_addr() function. Reviewed-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- drivers/ram/stm32mp1/stm32mp1_tests.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 90e82acda7..fec9fd010e 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -919,10 +919,12 @@ static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl, enum test_result res = TEST_PASSED, pattern_res; int i, bus_width; const u32 **patterns; - u32 bufsize; + u32 bufsize, addr; if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128)) return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: @@ -935,15 +937,14 @@ static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl, } printf("running test pattern at 0x%08x length 0x%x width = %d\n", - STM32_DDR_BASE, bufsize, bus_width); + addr, bufsize, bus_width); patterns = (const u32 **)(bus_width == 16 ? patterns_x16 : patterns_x32); for (i = 0; i < NB_PATTERN; i++) { printf("test data pattern %s:", patterns_comments[i]); - pattern_res = test_loop(patterns[i], (u32 *)STM32_DDR_BASE, - bufsize); + pattern_res = test_loop(patterns[i], (u32 *)addr, bufsize); if (pattern_res != TEST_PASSED) { printf("Failed\n"); return pattern_res; @@ -1419,9 +1420,9 @@ const struct test_desc test[] = { "Verifies r/w and memcopy(burst for pseudo random value.", 3 }, - {test_freq_pattern, "FrequencySelectivePattern", "[size]", + {test_freq_pattern, "FrequencySelectivePattern", "[size] [addr]", "write & test patterns: Mostly Zero, Mostly One and F/n", - 1 + 2 }, {test_blockseq, "BlockSequential", "[size] [loop] [addr]", "test incremental pattern", From 81b66b903311cba53e8a0d4ded112076b6fb4498 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 19:56:36 +0200 Subject: [PATCH 35/36] ram: stm32mp1: use the DDR size by default in the test addressBus The test 4 = "AddressBus [size] [addr]" without parameter detects alias for any address bit only when: - size = real size of DDR - addr = start of DDR = 0xC0000000 These value must be the default value when parameters are absent. This patch sets bufsize to STM32_DDR_SIZE and get_bufsize() selects the correct value for bufsize when this parameter is absent = full size of the DDDR On EV1 board : DDR> test 4 running at 0xC0000000 length 0x40000000 On DK2 board DDR> test 4 running at 0xC0000000 length 0x20000000 Reviewed-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- drivers/ram/stm32mp1/stm32mp1_tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index fec9fd010e..a2a69da9a3 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -442,7 +442,7 @@ static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl, u32 bufsize; u32 error; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4)) + if (get_bufsize(string, argc, argv, 0, &bufsize, STM32_DDR_SIZE, 4)) return TEST_ERROR; if (!is_power_of_2(bufsize)) { sprintf(string, "size 0x%x is not a power of 2", @@ -452,6 +452,7 @@ static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl, if (get_addr(string, argc, argv, 1, &addr)) return TEST_ERROR; + printf("running at 0x%08x length 0x%x\n", addr, bufsize); error = (u32)addressbus((u32 *)addr, bufsize); if (error) { sprintf(string, "0x%x: error for address 0x%x", From 6c393e8c0fae98a3a6e2909fc79697075552a152 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 2 Jul 2020 19:56:37 +0200 Subject: [PATCH 36/36] ram: stm32mp1: add size and addr parameter to test all Add size and addr parameter to test "All" to override the default value (4kB and STM32_DDR_BASE) used in tests with these optional parameters: [size] or [addr]. When other optional parameters are present before [addr], they are replaced by default value: - [loop] = "1" - [pattern] = "-" (new: force default pattern) Example to use: DDR>test 0 1 0x20000 DDR>test 0 1 0x1000000 0xD0000000 Reviewed-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- drivers/ram/stm32mp1/stm32mp1_tests.c | 47 +++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index a2a69da9a3..952006aa14 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -14,6 +14,8 @@ #define ADDR_INVALID 0xFFFFFFFF +#define PATTERN_DEFAULT "-" + DECLARE_GLOBAL_DATA_PTR; static int get_bufsize(char *string, int argc, char *argv[], int arg_nb, @@ -103,6 +105,10 @@ static int get_pattern(char *string, int argc, char *argv[], int arg_nb, unsigned long value; if (argc > arg_nb) { + if (!strcmp(argv[arg_nb], PATTERN_DEFAULT)) { + *pattern = default_pattern; + return 0; + } if (strict_strtoul(argv[arg_nb], 16, &value) < 0) { sprintf(string, "invalid %d parameter %s", arg_nb, argv[arg_nb]); @@ -1343,17 +1349,52 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED, result; - int i, nb_error = 0; + int i, j, nb_error = 0, len; u32 loop = 0, nb_loop; + int argc_test; + char *argv_test[4]; + char loop_string[] = "1"; + char pattern_string[] = PATTERN_DEFAULT; + u32 *addr; if (get_nb_loop(string, argc, argv, 0, &nb_loop, 1)) return TEST_ERROR; + if (get_addr(string, argc, argv, 2, (u32 *)&addr)) + return TEST_ERROR; + while (!nb_error) { /* execute all the test except the lasts which are infinite */ for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { + argc_test = 0; + j = 0; + len = strlen(test[i].usage); + if (argc > 1 && j < len && + !strncmp("[size]", &test[i].usage[j], 6)) { + argv_test[argc_test++] = argv[1]; + j += 7; + } + if (argc > 2) { + if (j < len && + !strncmp("[loop]", &test[i].usage[j], 6)) { + argv_test[argc_test++] = loop_string; + j += 7; + } + if (j < len && + !strncmp("[pattern]", &test[i].usage[j], + 9)) { + argv_test[argc_test++] = pattern_string; + j += 10; + } + if (j < len && + !strncmp("[addr]", &test[i].usage[j], 6)) { + argv_test[argc_test++] = argv[2]; + j += 7; + } + } printf("execute %d:%s\n", (int)i, test[i].name); - result = test[i].fct(ctl, phy, string, 0, NULL); + result = test[i].fct(ctl, phy, string, + argc_test, argv_test); printf("result %d:%s = ", (int)i, test[i].name); if (result != TEST_PASSED) { nb_error++; @@ -1384,7 +1425,7 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, ****************************************************************/ const struct test_desc test[] = { - {test_all, "All", "[loop]", "Execute all tests", 1 }, + {test_all, "All", "[loop] [size] [addr]", "Execute all tests", 3 }, {test_databus, "Simple DataBus", "[addr]", "Verifies each data line by walking 1 on fixed address", 1