diff options
39 files changed, 1166 insertions, 460 deletions
diff --git a/arch/arm/dts/stm32mp15-u-boot.dtsi b/arch/arm/dts/stm32mp15-u-boot.dtsi index 1279589a56..66be7df9ae 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 { @@ -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/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/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/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-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"; 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>; diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 6c995ed8d8..4003c2e38b 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 @@ -46,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/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..0c56b440f5 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -8,6 +8,7 @@ #include <log.h> #include <misc.h> #include <asm/io.h> +#include <asm/arch/bsec.h> #include <asm/arch/stm32mp1_smc.h> #include <linux/arm-smccc.h> #include <linux/iopoll.h> @@ -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 @@ -474,20 +479,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 +509,25 @@ 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 }; + +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/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) { 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 <misc.h> #include <net.h> #include <asm/io.h> +#include <asm/arch/bsec.h> #include <asm/arch/stm32.h> #include <asm/arch/sys_proto.h> #include <dm/device.h> @@ -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); 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/board/dhelectronics/dh_stm32mp1/Makefile b/board/dhelectronics/dh_stm32mp1/Makefile index e8f218da08..b368b396a4 100644 --- a/board/dhelectronics/dh_stm32mp1/Makefile +++ b/board/dhelectronics/dh_stm32mp1/Makefile @@ -3,11 +3,7 @@ # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # -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/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c index 26e827bc38..b8625f25d3 100644 --- a/board/dhelectronics/dh_stm32mp1/board.c +++ b/board/dhelectronics/dh_stm32mp1/board.c @@ -41,6 +41,7 @@ #include <usb.h> #include <usb/dwc2_udc.h> #include <watchdog.h> +#include "../../st/common/stpmic1.h" /* SYSCFG registers */ #define SYSCFG_BOOTR 0x00 @@ -139,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) { @@ -196,8 +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(opp_voltage_mv); board_get_coding_straps(); return 0; @@ -513,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(); diff --git a/board/st/common/Kconfig b/board/st/common/Kconfig index 015ba40939..ddcf33a122 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 @@ -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 aa030bacd8..65bbebd6ab 100644 --- a/board/st/common/Makefile +++ b/board/st/common/Makefile @@ -4,8 +4,11 @@ # 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 obj-$(CONFIG_SET_DFU_ALT_INFO) += stm32mp_dfu.o endif + +obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o diff --git a/board/st/common/stpmic1.c b/board/st/common/stpmic1.c new file mode 100644 index 0000000000..3aa379e8a5 --- /dev/null +++ b/board/st/common/stpmic1.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/ddr.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <power/pmic.h> +#include <power/stpmic1.h> + +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; +} + +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(u32 voltage_mv) +{ + struct udevice *dev; + + if (uclass_get_device_by_driver(UCLASS_PMIC, + 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, + 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..b17d6f1633 --- /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(u32 voltage_mv); 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 <common.h> +#include <dm.h> +#include <i2c.h> + +/* 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/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/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 <common.h> -#include <dm.h> #include <asm/io.h> -#include <asm/arch/ddr.h> #include <linux/bitops.h> #include <linux/delay.h> -#include <power/pmic.h> -#include <power/stpmic1.h> #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 diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index e65ff288ea..a6a41780c9 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -5,41 +5,51 @@ #include <config.h> #include <common.h> -#include <spl.h> -#include <dm.h> -#include <ram.h> +#include <init.h> #include <asm/io.h> -#include <power/pmic.h> -#include <power/stpmic1.h> -#include <asm/arch/ddr.h> +#include <asm/arch/sys_proto.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include "../common/stpmic1.h" -void spl_board_init(void) +/* 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(opp_voltage_mv); + + return 0; +} + +#ifdef CONFIG_DEBUG_UART_BOARD_INIT +void board_debug_uart_init(void) { - /* Keep vdd on during the reset cycle */ -#if defined(CONFIG_PMIC_STPMIC1) && defined(CONFIG_SPL_POWER_SUPPORT) - struct udevice *dev; - int ret; - - 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); - } +#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 diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 4553329b25..71daf18034 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -41,6 +41,8 @@ #include <power/regulator.h> #include <usb/dwc2_udc.h> +#include "../../st/common/stusb160x.h" + /* SYSCFG registers */ #define SYSCFG_BOOTR 0x00 #define SYSCFG_PMCSETR 0x04 @@ -84,6 +86,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; @@ -175,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 <usb/dwc2_udc.h> 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), @@ -664,17 +624,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(); 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 diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index ecdbac65ff..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 @@ -18,6 +19,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 @@ -29,6 +31,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 @@ -75,6 +78,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 @@ -142,5 +146,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 ca4a10813b..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 @@ -14,6 +15,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 @@ -59,6 +61,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 @@ -127,5 +130,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/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..c8840b9e5f 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -17,6 +17,7 @@ #include <linux/bitops.h> #include <linux/io.h> #include <linux/iopoll.h> +#include <asm/arch/sys_proto.h> #include <dt-bindings/clock/stm32mp1-clks.h> #include <dt-bindings/clock/stm32mp1-clksrc.h> @@ -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,213 @@ 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; + } +} + +__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. + * 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; + board_vddcore_init(voltage); + + 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 +1879,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 +1904,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 +2026,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 +2287,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 diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 4f710b6b6a..5bff27f75b 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -18,9 +18,65 @@ #include <linux/errno.h> #include <linux/io.h> -#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 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) +{ + int bits; + + bits = OTYPE_BITS(idx); + 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) +{ + int bits; + + bits = PUPD_BITS(idx); + 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 @@ -47,18 +103,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 +119,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 +187,87 @@ 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 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, .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, + .get_dir_flags = stm32_gpio_get_dir_flags, }; static int gpio_stm32_probe(struct udevice *dev) 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 }, { diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index a3240ccd5a..c2ea82770e 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -74,17 +74,61 @@ 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_gpio_get(struct udevice *dev, unsigned int offset) +static int stmfx_read_reg(struct udevice *dev, u8 reg_base, uint 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_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); +} + static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value) { u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR; @@ -95,50 +139,103 @@ 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; + return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 0); +} - ret = stmfx_read(dev, reg); +static int stmfx_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + int ret = stmfx_gpio_set(dev, offset, value); if (ret < 0) return ret; - ret &= ~mask; + return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1); +} - return stmfx_write(dev, reg, ret & ~mask); +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_direction_output(struct udevice *dev, - unsigned int offset, int value) +static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, + ulong *flags) { - u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); - u32 mask = get_mask(offset); + ulong dir_flags = 0; int ret; - ret = stmfx_gpio_set(dev, offset, value); - if (ret < 0) - return ret; - - ret = stmfx_read(dev, reg); - if (ret < 0) - return 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 stmfx_write(dev, reg, ret | mask); + return 0; } static int stmfx_gpio_probe(struct udevice *dev) @@ -169,6 +266,8 @@ 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, + .get_dir_flags = stmfx_gpio_get_dir_flags, }; U_BOOT_DRIVER(stmfx_gpio) = { @@ -190,36 +289,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) { @@ -235,22 +304,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); @@ -289,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) @@ -300,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; } 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; } 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; diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index bacdd74705..952006aa14 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -14,10 +14,12 @@ #define ADDR_INVALID 0xFFFFFFFF +#define PATTERN_DEFAULT "-" + 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 +29,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; @@ -102,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]); @@ -441,7 +448,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, STM32_DDR_SIZE, 4)) return TEST_ERROR; if (!is_power_of_2(bufsize)) { sprintf(string, "size 0x%x is not a power of 2", @@ -451,6 +458,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", @@ -470,7 +478,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 +520,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 +592,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 +752,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; @@ -918,9 +926,11 @@ 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)) + 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) { @@ -934,15 +944,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; @@ -1007,7 +1016,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 +1051,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 +1085,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 +1123,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 +1165,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 +1212,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; @@ -1340,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++; @@ -1381,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 @@ -1418,9 +1462,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", diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index f271b84a59..ed20b842ac 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" @@ -155,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" |