diff --git a/arch/arm/dts/stm32mp151.dtsi b/arch/arm/dts/stm32mp151.dtsi index 8bbb1aef2e..5d178b5d3c 100644 --- a/arch/arm/dts/stm32mp151.dtsi +++ b/arch/arm/dts/stm32mp151.dtsi @@ -145,6 +145,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40000000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM2_K>; clock-names = "int"; dmas = <&dmamux1 18 0x400 0x1>, @@ -178,6 +180,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40001000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM3_K>; clock-names = "int"; dmas = <&dmamux1 23 0x400 0x1>, @@ -212,6 +216,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40002000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM4_K>; clock-names = "int"; dmas = <&dmamux1 29 0x400 0x1>, @@ -244,6 +250,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40003000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM5_K>; clock-names = "int"; dmas = <&dmamux1 55 0x400 0x1>, @@ -278,6 +286,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40004000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM6_K>; clock-names = "int"; dmas = <&dmamux1 69 0x400 0x1>; @@ -296,6 +306,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40005000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM7_K>; clock-names = "int"; dmas = <&dmamux1 70 0x400 0x1>; @@ -314,6 +326,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40006000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM12_K>; clock-names = "int"; status = "disabled"; @@ -336,6 +350,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40007000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM13_K>; clock-names = "int"; status = "disabled"; @@ -358,6 +374,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40008000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM14_K>; clock-names = "int"; status = "disabled"; @@ -641,6 +659,11 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44000000 0x400>; + interrupts = , + , + , + ; + interrupt-names = "brk", "up", "trg-com", "cc"; clocks = <&rcc TIM1_K>; clock-names = "int"; dmas = <&dmamux1 11 0x400 0x1>, @@ -677,6 +700,11 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44001000 0x400>; + interrupts = , + , + , + ; + interrupt-names = "brk", "up", "trg-com", "cc"; clocks = <&rcc TIM8_K>; clock-names = "int"; dmas = <&dmamux1 47 0x400 0x1>, @@ -764,6 +792,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44006000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM15_K>; clock-names = "int"; dmas = <&dmamux1 105 0x400 0x1>, @@ -791,6 +821,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44007000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM16_K>; clock-names = "int"; dmas = <&dmamux1 109 0x400 0x1>, @@ -815,6 +847,8 @@ #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44008000 0x400>; + interrupts = ; + interrupt-names = "global"; clocks = <&rcc TIM17_K>; clock-names = "int"; dmas = <&dmamux1 111 0x400 0x1>, diff --git a/arch/arm/dts/stm32mp157a-dk1-scmi-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-scmi-u-boot.dtsi index 1209dfe009..92fdf09872 100644 --- a/arch/arm/dts/stm32mp157a-dk1-scmi-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-scmi-u-boot.dtsi @@ -3,7 +3,6 @@ * Copyright : STMicroelectronics 2022 */ -#include #include "stm32mp15-scmi-u-boot.dtsi" / { diff --git a/arch/arm/dts/stm32mp157c-ed1-scmi-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-scmi-u-boot.dtsi index c265745ff1..63948ef493 100644 --- a/arch/arm/dts/stm32mp157c-ed1-scmi-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-scmi-u-boot.dtsi @@ -3,7 +3,6 @@ * Copyright : STMicroelectronics 2022 */ -#include #include "stm32mp15-scmi-u-boot.dtsi" / { diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index d142dd30e1..2d5db41ed6 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -362,6 +362,14 @@ &usbh_ehci { phys = <&usbphyc_port0>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + /* onboard HUB */ + hub@1 { + compatible = "usb424,2514"; + reg = <1>; + vdd-supply = <&v3v3>; + }; }; &usbotg_hs { @@ -385,6 +393,10 @@ st,tune-squelch-level = <3>; st,tune-hs-rx-offset = <2>; st,no-lsfs-sc; + connector { + compatible = "usb-a-connector"; + vbus-supply = <&vbus_sw>; + }; }; &usbphyc_port1 { diff --git a/arch/arm/dts/stm32mp15xx-dkx.dtsi b/arch/arm/dts/stm32mp15xx-dkx.dtsi index 5a045d7156..34af90195d 100644 --- a/arch/arm/dts/stm32mp15xx-dkx.dtsi +++ b/arch/arm/dts/stm32mp15xx-dkx.dtsi @@ -390,21 +390,21 @@ regulator-always-on; }; - bst_out: boost { + bst_out: boost { regulator-name = "bst_out"; interrupts = ; - }; + }; vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - }; + }; - vbus_sw: pwr_sw2 { + vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; regulator-active-discharge = <1>; - }; + }; }; onkey { diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 1db9057e04..a19b2797c8 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -11,10 +11,10 @@ obj-y += bsec.o obj-$(CONFIG_STM32MP13x) += stm32mp13x.o obj-$(CONFIG_STM32MP15x) += stm32mp15x.o +obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o ifdef CONFIG_SPL_BUILD obj-y += spl.o obj-y += tzc400.o -obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o else obj-y += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o diff --git a/arch/arm/mach-stm32mp/boot_params.c b/arch/arm/mach-stm32mp/boot_params.c index e91ef1b2fc..24d04dcf0f 100644 --- a/arch/arm/mach-stm32mp/boot_params.c +++ b/arch/arm/mach-stm32mp/boot_params.c @@ -8,33 +8,18 @@ #include #include #include +#include #include #include -/* - * Force data-section, as .bss will not be valid - * when save_boot_params is invoked. - */ -static unsigned long nt_fw_dtb __section(".data"); - -/* - * Save the FDT address provided by TF-A in r2 at boot time - * This function is called from start.S - */ -void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2, - unsigned long r3) -{ - nt_fw_dtb = r2; - - save_boot_params_ret(); -} - /* * Use the saved FDT address provided by TF-A at boot time (NT_FW_CONFIG = * Non Trusted Firmware configuration file) when the pointer is valid */ void *board_fdt_blob_setup(int *err) { + unsigned long nt_fw_dtb = get_stm32mp_bl2_dtb(); + log_debug("%s: nt_fw_dtb=%lx\n", __func__, nt_fw_dtb); *err = 0; diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index c00130b08b..f5f4b20d47 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -10,9 +10,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -63,10 +65,43 @@ */ #define BSEC_LOCK_PROGRAM 0x04 +#define PTA_BSEC_UUID { 0x94cf71ad, 0x80e6, 0x40b5, \ + { 0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03 } } + /* - * OTP status: bit 0 permanent lock + * Read OTP memory + * + * [in] value[0].a OTP start offset in byte + * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock) + * [out] memref[1].buffer Output buffer to store read values + * [out] memref[1].size Size of OTP to be read + * + * Return codes: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller */ -#define BSEC_LOCK_PERM BIT(0) +#define PTA_BSEC_READ_MEM 0x0 + +/* + * Write OTP memory + * + * [in] value[0].a OTP start offset in byte + * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock) + * [in] memref[1].buffer Input buffer to read values + * [in] memref[1].size Size of OTP to be written + * + * Return codes: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller + */ +#define PTA_BSEC_WRITE_MEM 0x1 + +/* value of PTA_BSEC access type = value[in] b */ +#define SHADOW_ACCESS 0 +#define FUSE_ACCESS 1 +#define LOCK_ACCESS 2 /** * bsec_lock() - manage lock for each type SR/SP/SW @@ -359,6 +394,10 @@ struct stm32mp_bsec_plat { u32 base; }; +struct stm32mp_bsec_priv { + struct udevice *tee; +}; + static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat; @@ -468,18 +507,111 @@ static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) plat = dev_get_plat(dev); return bsec_permanent_lock_otp(dev, plat->base, otp); +} - return -EINVAL; +static int bsec_pta_open_session(struct udevice *tee, u32 *tee_session) +{ + const struct tee_optee_ta_uuid uuid = PTA_BSEC_UUID; + struct tee_open_session_arg arg; + int rc; + + memset(&arg, 0, sizeof(arg)); + tee_optee_ta_uuid_to_octets(arg.uuid, &uuid); + arg.clnt_login = TEE_LOGIN_REE_KERNEL; + rc = tee_open_session(tee, &arg, 0, NULL); + if (rc < 0) + return -ENODEV; + + *tee_session = arg.session; + + return 0; +} + +static int bsec_optee_open(struct udevice *dev) +{ + struct stm32mp_bsec_priv *priv = dev_get_priv(dev); + struct udevice *tee; + u32 tee_session; + int rc; + + tee = tee_find_device(NULL, NULL, NULL, NULL); + if (!tee) + return -ENODEV; + + /* try to open the STM32 BSEC TA */ + rc = bsec_pta_open_session(tee, &tee_session); + if (rc) + return rc; + + tee_close_session(tee, tee_session); + + priv->tee = tee; + + return 0; +} + +static int bsec_optee_pta(struct udevice *dev, int cmd, int type, int offset, + void *buff, ulong size) +{ + struct stm32mp_bsec_priv *priv = dev_get_priv(dev); + u32 tee_session; + struct tee_invoke_arg arg; + struct tee_param param[2]; + struct tee_shm *fw_shm; + int rc; + + rc = bsec_pta_open_session(priv->tee, &tee_session); + if (rc) + return rc; + + rc = tee_shm_register(priv->tee, buff, size, 0, &fw_shm); + if (rc) + goto close_session; + + memset(&arg, 0, sizeof(arg)); + arg.func = cmd; + arg.session = tee_session; + + memset(param, 0, sizeof(param)); + + param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = offset; + param[0].u.value.b = type; + + if (cmd == PTA_BSEC_WRITE_MEM) + param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT; + else + param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + + param[1].u.memref.shm = fw_shm; + param[1].u.memref.size = size; + + rc = tee_invoke_func(priv->tee, &arg, 2, param); + if (rc < 0 || arg.ret != 0) { + dev_err(priv->tee, + "PTA_BSEC invoke failed TEE err: %x, err:%x\n", + arg.ret, rc); + if (!rc) + rc = -EIO; + } + + tee_shm_free(fw_shm); + +close_session: + tee_close_session(priv->tee, tee_session); + + return rc; } static int stm32mp_bsec_read(struct udevice *dev, int offset, void *buf, int size) { + struct stm32mp_bsec_priv *priv = dev_get_priv(dev); int ret; int i; bool shadow = true, lock = false; int nb_otp = size / sizeof(u32); - int otp; + int otp, cmd; unsigned int offs = offset; if (offs >= STM32_BSEC_LOCK_OFFSET) { @@ -493,6 +625,19 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset, if ((offs % 4) || (size % 4)) return -EINVAL; + if (IS_ENABLED(CONFIG_OPTEE) && priv->tee) { + cmd = FUSE_ACCESS; + if (shadow) + cmd = SHADOW_ACCESS; + if (lock) + cmd = LOCK_ACCESS; + ret = bsec_optee_pta(dev, PTA_BSEC_READ_MEM, cmd, offs, buf, size); + if (ret) + return ret; + + return size; + } + otp = offs / sizeof(u32); for (i = otp; i < (otp + nb_otp) && i <= BSEC_OTP_MAX_VALUE; i++) { @@ -517,11 +662,12 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset, static int stm32mp_bsec_write(struct udevice *dev, int offset, const void *buf, int size) { + struct stm32mp_bsec_priv *priv = dev_get_priv(dev); int ret = 0; int i; bool shadow = true, lock = false; int nb_otp = size / sizeof(u32); - int otp; + int otp, cmd; unsigned int offs = offset; if (offs >= STM32_BSEC_LOCK_OFFSET) { @@ -535,6 +681,19 @@ static int stm32mp_bsec_write(struct udevice *dev, int offset, if ((offs % 4) || (size % 4)) return -EINVAL; + if (IS_ENABLED(CONFIG_OPTEE) && priv->tee) { + cmd = FUSE_ACCESS; + if (shadow) + cmd = SHADOW_ACCESS; + if (lock) + cmd = LOCK_ACCESS; + ret = bsec_optee_pta(dev, PTA_BSEC_WRITE_MEM, cmd, offs, (void *)buf, size); + if (ret) + return ret; + + return size; + } + otp = offs / sizeof(u32); for (i = otp; i < otp + nb_otp && i <= BSEC_OTP_MAX_VALUE; i++) { @@ -583,6 +742,9 @@ static int stm32mp_bsec_probe(struct udevice *dev) return ret; } + if (IS_ENABLED(CONFIG_OPTEE)) + bsec_optee_open(dev); + /* * update unlocked shadow for OTP cleared by the rom code * only executed in SPL, it is done in TF-A for TFABOOT @@ -599,6 +761,7 @@ static int stm32mp_bsec_probe(struct udevice *dev) } static const struct udevice_id stm32mp_bsec_ids[] = { + { .compatible = "st,stm32mp13-bsec" }, { .compatible = "st,stm32mp15-bsec" }, {} }; @@ -608,7 +771,8 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .id = UCLASS_MISC, .of_match = stm32mp_bsec_ids, .of_to_plat = stm32mp_bsec_of_to_plat, - .plat_auto = sizeof(struct stm32mp_bsec_plat), + .plat_auto = sizeof(struct stm32mp_bsec_plat), + .priv_auto = sizeof(struct stm32mp_bsec_priv), .ops = &stm32mp_bsec_ops, .probe = stm32mp_bsec_probe, }; diff --git a/arch/arm/mach-stm32mp/cmd_stm32key.c b/arch/arm/mach-stm32mp/cmd_stm32key.c index 278253e472..85be8e23bd 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32key.c +++ b/arch/arm/mach-stm32mp/cmd_stm32key.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -84,9 +85,6 @@ static u32 get_otp_close_mask(void) return STM32_OTP_STM32MP15x_CLOSE_MASK; } -#define BSEC_LOCK_ERROR (-1) -#define BSEC_LOCK_PERM BIT(0) - static int get_misc_dev(struct udevice **dev) { int ret; diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 855fc755fe..dc4112d5e6 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -22,6 +22,7 @@ #include #include #include +#include /* * early TLB into the .data section so that it not get cleared @@ -378,3 +379,52 @@ int arch_misc_init(void) return 0; } + +/* + * Without forcing the ".data" section, this would get saved in ".bss". BSS + * will be cleared soon after, so it's not suitable. + */ +static uintptr_t rom_api_table __section(".data"); +static uintptr_t nt_fw_dtb __section(".data"); + +/* + * The ROM gives us the API location in r0 when starting. This is only available + * during SPL, as there isn't (yet) a mechanism to pass this on to u-boot. Save + * the FDT address provided by TF-A in r2 at boot time. This function is called + * from start.S + */ +void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3) +{ + if (IS_ENABLED(CONFIG_STM32_ECDSA_VERIFY)) + rom_api_table = r0; + + if (IS_ENABLED(CONFIG_TFABOOT)) + nt_fw_dtb = r2; + + save_boot_params_ret(); +} + +uintptr_t get_stm32mp_rom_api_table(void) +{ + return rom_api_table; +} + +uintptr_t get_stm32mp_bl2_dtb(void) +{ + return nt_fw_dtb; +} + +#ifdef CONFIG_SPL_BUILD +void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{ + typedef void __noreturn (*image_entry_stm32_t)(u32 romapi); + uintptr_t romapi = get_stm32mp_rom_api_table(); + + image_entry_stm32_t image_entry = + (image_entry_stm32_t)spl_image->entry_point; + + printf("image entry point: 0x%lx\n", spl_image->entry_point); + image_entry(romapi); +} +#endif diff --git a/arch/arm/mach-stm32mp/ecdsa_romapi.c b/arch/arm/mach-stm32mp/ecdsa_romapi.c index a2f63ff879..12b42b9d59 100644 --- a/arch/arm/mach-stm32mp/ecdsa_romapi.c +++ b/arch/arm/mach-stm32mp/ecdsa_romapi.c @@ -24,26 +24,10 @@ struct ecdsa_rom_api { uint32_t ecc_algo); }; -/* - * Without forcing the ".data" section, this would get saved in ".bss". BSS - * will be cleared soon after, so it's not suitable. - */ -static uintptr_t rom_api_loc __section(".data"); - -/* - * The ROM gives us the API location in r0 when starting. This is only available - * during SPL, as there isn't (yet) a mechanism to pass this on to u-boot. - */ -void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2, - unsigned long r3) -{ - rom_api_loc = r0; - save_boot_params_ret(); -} - static void stm32mp_rom_get_ecdsa_functions(struct ecdsa_rom_api *rom) { - uintptr_t verify_ptr = rom_api_loc + ROM_API_OFFSET_ECDSA_VERIFY; + uintptr_t verify_ptr = get_stm32mp_rom_api_table() + + ROM_API_OFFSET_ECDSA_VERIFY; rom->ecdsa_verify_signature = *(void **)verify_ptr; } @@ -81,6 +65,10 @@ static int romapi_ecdsa_verify(struct udevice *dev, memcpy(raw_key + 32, pubkey->y, 32); stm32mp_rom_get_ecdsa_functions(&rom); + + /* Mark BootROM region as executable. */ + mmu_set_region_dcache_behaviour(0, SZ_2M, DCACHE_DEFAULT_OPTION); + rom_ret = rom.ecdsa_verify_signature(hash, raw_key, signature, algo); return rom_ret == ROM_API_SUCCESS ? 0 : -EPERM; diff --git a/arch/arm/mach-stm32mp/include/mach/bsec.h b/arch/arm/mach-stm32mp/include/mach/bsec.h index 252eac3946..10ebc535c4 100644 --- a/arch/arm/mach-stm32mp/include/mach/bsec.h +++ b/arch/arm/mach-stm32mp/include/mach/bsec.h @@ -5,3 +5,10 @@ /* check self hosted debug status = BSEC_DENABLE.DBGSWENABLE */ bool bsec_dbgswenable(void); + +/* Bitfield definition for LOCK status */ +#define BSEC_LOCK_PERM BIT(30) +#define BSEC_LOCK_SHADOW_R BIT(29) +#define BSEC_LOCK_SHADOW_W BIT(28) +#define BSEC_LOCK_SHADOW_P BIT(27) +#define BSEC_LOCK_ERROR BIT(26) diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index f19a70e53e..0d39b67178 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -77,3 +77,6 @@ void stm32mp_misc_init(void); /* helper function: read data from OTP */ u32 get_otp(int index, int shift, int mask); + +uintptr_t get_stm32mp_rom_api_table(void); +uintptr_t get_stm32mp_bl2_dtb(void); diff --git a/board/st/common/Kconfig b/board/st/common/Kconfig index 2f57118bb2..aba3590866 100644 --- a/board/st/common/Kconfig +++ b/board/st/common/Kconfig @@ -1,7 +1,7 @@ config CMD_STBOARD bool "stboard - command for OTP board information" depends on ARCH_STM32MP - default y if TARGET_ST_STM32MP15x + default y if TARGET_ST_STM32MP15x || TARGET_ST_STM32MP13x help This compile the stboard command to read and write the board in the OTP. diff --git a/board/st/common/cmd_stboard.c b/board/st/common/cmd_stboard.c index e12669b862..853ab78bbf 100644 --- a/board/st/common/cmd_stboard.c +++ b/board/st/common/cmd_stboard.c @@ -2,8 +2,8 @@ /* * Copyright (C) 2019, STMicroelectronics - All Rights Reserved * - * the st command stboard supports the STMicroelectronics board identification - * saved in OTP 59. + * the command stboard supports the STMicroelectronics board identification + * saved in OTP_BOARD. * * The ST product codification have several element * - "Commercial Product Name" (CPN): type of product board (DKX, EVX) @@ -18,7 +18,7 @@ * - Finished Good = EVA32MP157A1$AU1 * * Both information are written on board and these information are also saved - * in OTP59, with: + * in OTP_BOARD (59 for STM32MP15x or 60 for STM32MP13x), with: * bit [31:16] (hex) => Board id, MBxxxx * bit [15:12] (dec) => Variant CPN (1....15) * bit [11:8] (dec) => Revision board (index with A = 1, Z = 26) @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ static bool check_stboard(u16 board) 0x1298, 0x1341, 0x1497, + 0x1635, }; for (i = 0; i < ARRAY_SIZE(st_board_id); i++) @@ -109,7 +111,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc, else display_stboard(otp); printf(" OTP %d %s locked !\n", BSEC_OTP_BOARD, - lock == 1 ? "" : "NOT"); + lock & BSEC_LOCK_PERM ? "" : "NOT"); return CMD_RET_SUCCESS; } @@ -178,7 +180,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc, } /* write persistent lock */ - otp = 1; + otp = BSEC_LOCK_PERM; ret = misc_write(dev, STM32_BSEC_LOCK(BSEC_OTP_BOARD), &otp, sizeof(otp)); if (ret != sizeof(otp)) { diff --git a/common/Makefile b/common/Makefile index 20addfb244..7789aab484 100644 --- a/common/Makefile +++ b/common/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PHYLIB) += miiphyutil.o obj-$(CONFIG_USB_HOST) += usb.o usb_hub.o obj-$(CONFIG_USB_GADGET) += usb.o usb_hub.o obj-$(CONFIG_USB_STORAGE) += usb_storage.o +obj-$(CONFIG_USB_ONBOARD_HUB) += usb_onboard_hub.o # others obj-$(CONFIG_CONSOLE_MUX) += iomux.o diff --git a/common/usb_onboard_hub.c b/common/usb_onboard_hub.c new file mode 100644 index 0000000000..89e18a2dda --- /dev/null +++ b/common/usb_onboard_hub.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for onboard USB hubs + * + * Copyright (C) 2022, STMicroelectronics - All Rights Reserved + * + * Mostly inspired by Linux kernel v6.1 onboard_usb_hub driver + */ + +#include +#include +#include +#include + +struct onboard_hub { + struct udevice *vdd; +}; + +static int usb_onboard_hub_probe(struct udevice *dev) +{ + struct onboard_hub *hub = dev_get_priv(dev); + int ret; + + ret = device_get_supply_regulator(dev, "vdd-supply", &hub->vdd); + if (ret) { + dev_err(dev, "can't get vdd-supply: %d\n", ret); + return ret; + } + + ret = regulator_set_enable_if_allowed(hub->vdd, true); + if (ret) + dev_err(dev, "can't enable vdd-supply: %d\n", ret); + + return ret; +} + +static int usb_onboard_hub_remove(struct udevice *dev) +{ + struct onboard_hub *hub = dev_get_priv(dev); + int ret; + + ret = regulator_set_enable_if_allowed(hub->vdd, false); + if (ret) + dev_err(dev, "can't disable vdd-supply: %d\n", ret); + + return ret; +} + +static const struct udevice_id usb_onboard_hub_ids[] = { + /* Use generic usbVID,PID dt-bindings (usb-device.yaml) */ + { .compatible = "usb424,2514" }, /* USB2514B USB 2.0 */ + { } +}; + +U_BOOT_DRIVER(usb_onboard_hub) = { + .name = "usb_onboard_hub", + .id = UCLASS_USB_HUB, + .probe = usb_onboard_hub_probe, + .remove = usb_onboard_hub_remove, + .of_match = usb_onboard_hub_ids, + .priv_auto = sizeof(struct onboard_hub), +}; diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 4cab076473..ab824808f9 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -7,6 +7,7 @@ CONFIG_DEFAULT_DEVICE_TREE="stm32mp135f-dk" CONFIG_SYS_PROMPT="STM32MP> " CONFIG_STM32MP13x=y CONFIG_DDR_CACHEABLE_SIZE=0x10000000 +CONFIG_CMD_STM32KEY=y CONFIG_TARGET_ST_STM32MP13x=y CONFIG_ENV_OFFSET_REDUND=0x940000 # CONFIG_ARMV7_NONSEC is not set @@ -26,6 +27,7 @@ CONFIG_CMD_MEMINFO=y CONFIG_CMD_MEMTEST=y CONFIG_CMD_UNZIP=y CONFIG_CMD_CLK=y +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_LSBLK=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 449d078120..87e3b49604 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -167,6 +167,7 @@ CONFIG_USB=y CONFIG_DM_USB_GADGET=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_ONBOARD_HUB=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 diff --git a/configs/stm32mp15_defconfig b/configs/stm32mp15_defconfig index d12e15df6c..5dc00213a8 100644 --- a/configs/stm32mp15_defconfig +++ b/configs/stm32mp15_defconfig @@ -143,6 +143,7 @@ CONFIG_USB=y CONFIG_DM_USB_GADGET=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_ONBOARD_HUB=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 8f99ee2e93..c1ad4dd521 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -143,6 +143,7 @@ CONFIG_USB=y CONFIG_DM_USB_GADGET=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_ONBOARD_HUB=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 diff --git a/doc/board/st/stm32mp1.rst b/doc/board/st/stm32mp1.rst index 3759df353e..9780ac9768 100644 --- a/doc/board/st/stm32mp1.rst +++ b/doc/board/st/stm32mp1.rst @@ -620,7 +620,7 @@ Prerequisite: check if a MAC address isn't yet programmed in OTP STM32MP> env print ethaddr ## Error: "ethaddr" not defined -3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 1=locked):: +3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 0x40000000=locked):: STM32MP> fuse sense 0 0x10000039 2 Sensing bank 0: @@ -640,11 +640,11 @@ Example to set mac address "12:34:56:78:9a:bc" 3) Lock OTP:: - STM32MP> fuse prog 0 0x10000039 1 1 + STM32MP> fuse prog 0 0x10000039 0x40000000 0x40000000 STM32MP> fuse sense 0 0x10000039 2 Sensing bank 0: - Word 0x10000039: 00000001 00000001 + Word 0x10000039: 40000000 40000000 4) next REBOOT, in the trace:: diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index 85efc119db..1fba707c6f 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -33,8 +33,11 @@ #define STM32H7_ADRDY BIT(0) /* STM32H7_ADC_CR - bit fields */ +#define STM32H7_ADCAL BIT(31) +#define STM32H7_ADCALDIF BIT(30) #define STM32H7_DEEPPWD BIT(29) #define STM32H7_ADVREGEN BIT(28) +#define STM32H7_ADCALLIN BIT(16) #define STM32H7_BOOST BIT(8) #define STM32H7_ADSTART BIT(2) #define STM32H7_ADDIS BIT(1) @@ -65,14 +68,56 @@ struct stm32_adc { const struct stm32_adc_cfg *cfg; }; +static void stm32_adc_enter_pwr_down(struct udevice *dev) +{ + struct stm32_adc *adc = dev_get_priv(dev); + + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); +} + +static int stm32_adc_exit_pwr_down(struct udevice *dev) +{ + struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev)); + struct stm32_adc *adc = dev_get_priv(dev); + int ret; + u32 val; + + /* return immediately if ADC is not in deep power down mode */ + if (!(readl(adc->regs + STM32H7_ADC_CR) & STM32H7_DEEPPWD)) + return 0; + + /* Exit deep power down, then enable ADC voltage regulator */ + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); + + if (common->rate > STM32H7_BOOST_CLKRATE) + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + + /* Wait for startup time */ + if (!adc->cfg->has_vregready) { + udelay(20); + return 0; + } + + ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, + val & STM32MP1_VREGREADY, + STM32_ADC_TIMEOUT_US); + if (ret < 0) { + stm32_adc_enter_pwr_down(dev); + dev_err(dev, "Failed to enable vreg: %d\n", ret); + } + + return ret; +} + static int stm32_adc_stop(struct udevice *dev) { struct stm32_adc *adc = dev_get_priv(dev); setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS); - clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); - /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ - setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); + stm32_adc_enter_pwr_down(dev); adc->active_channel = -1; return 0; @@ -81,30 +126,13 @@ static int stm32_adc_stop(struct udevice *dev) static int stm32_adc_start_channel(struct udevice *dev, int channel) { struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); - struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev)); struct stm32_adc *adc = dev_get_priv(dev); int ret; u32 val; - /* Exit deep power down, then enable ADC voltage regulator */ - clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); - setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); - if (common->rate > STM32H7_BOOST_CLKRATE) - setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); - - /* Wait for startup time */ - if (!adc->cfg->has_vregready) { - udelay(20); - } else { - ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, - val & STM32MP1_VREGREADY, - STM32_ADC_TIMEOUT_US); - if (ret < 0) { - stm32_adc_stop(dev); - dev_err(dev, "Failed to enable vreg: %d\n", ret); - return ret; - } - } + ret = stm32_adc_exit_pwr_down(dev); + if (ret < 0) + return ret; /* Only use single ended channels */ writel(0, adc->regs + STM32H7_ADC_DIFSEL); @@ -162,6 +190,64 @@ static int stm32_adc_channel_data(struct udevice *dev, int channel, return 0; } +/** + * Fixed timeout value for ADC calibration. + * worst cases: + * - low clock frequency (0.12 MHz min) + * - maximum prescalers + * Calibration requires: + * - 16384 ADC clock cycle for the linear calibration + * - 20 ADC clock cycle for the offset calibration + * + * Set to 100ms for now + */ +#define STM32H7_ADC_CALIB_TIMEOUT_US 100000 + +static int stm32_adc_selfcalib(struct udevice *dev) +{ + struct stm32_adc *adc = dev_get_priv(dev); + int ret; + u32 val; + + /* + * Select calibration mode: + * - Offset calibration for single ended inputs + * - No linearity calibration. Done in next step. + */ + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); + + /* Start calibration, then wait for completion */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); + ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val, + !(val & STM32H7_ADCAL), 100, + STM32H7_ADC_CALIB_TIMEOUT_US); + if (ret) { + dev_err(dev, "calibration failed\n"); + goto out; + } + + /* + * Select calibration mode, then start calibration: + * - Offset calibration for differential input + * - Linearity calibration (needs to be done only once for single/diff) + * will run simultaneously with offset calibration. + */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); + + /* Start calibration, then wait for completion */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); + ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val, + !(val & STM32H7_ADCAL), 100, + STM32H7_ADC_CALIB_TIMEOUT_US); + if (ret) + dev_err(dev, "calibration failed\n"); + +out: + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); + + return ret; +} + static int stm32_adc_get_legacy_chan_count(struct udevice *dev) { int ret; @@ -272,7 +358,7 @@ static int stm32_adc_probe(struct udevice *dev) struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev)); struct stm32_adc *adc = dev_get_priv(dev); - int offset; + int offset, ret; offset = dev_read_u32_default(dev, "reg", -ENODATA); if (offset < 0) { @@ -287,7 +373,19 @@ static int stm32_adc_probe(struct udevice *dev) uc_pdata->vdd_microvolts = common->vref_uv; uc_pdata->vss_microvolts = 0; - return stm32_adc_chan_of_init(dev); + ret = stm32_adc_chan_of_init(dev); + if (ret < 0) + return ret; + + ret = stm32_adc_exit_pwr_down(dev); + if (ret < 0) + return ret; + + ret = stm32_adc_selfcalib(dev); + if (ret) + stm32_adc_enter_pwr_down(dev); + + return ret; } static const struct adc_ops stm32_adc_ops = { diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8efd461457..ebe6bf9498 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -105,6 +105,16 @@ config USB_KEYBOARD Say Y here if you want to use a USB keyboard for U-Boot command line input. +config USB_ONBOARD_HUB + bool "Onboard USB hub support" + depends on DM_USB + ---help--- + Say Y here if you want to support discrete onboard USB hubs that + don't require an additional control bus for initialization, but + need some non-trivial form of initialization, such as enabling a + power regulator. An example for such a hub is the Microchip + USB2514B. + if USB_KEYBOARD config USB_KEYBOARD_FN_KEYS diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 956e2a4e8e..93c318c3d1 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -271,19 +271,23 @@ int usb_init(void) /* init low_level USB */ printf("Bus %s: ", bus->name); -#ifdef CONFIG_SANDBOX /* * For Sandbox, we need scan the device tree each time when we * start the USB stack, in order to re-create the emulated USB * devices and bind drivers for them before we actually do the * driver probe. + * + * For USB onboard HUB, we need to do some non-trivial init + * like enabling a power regulator, before enumeration. */ - ret = dm_scan_fdt_dev(bus); - if (ret) { - printf("Sandbox USB device scan failed (%d)\n", ret); - continue; + if (IS_ENABLED(CONFIG_SANDBOX) || + IS_ENABLED(CONFIG_USB_ONBOARD_HUB)) { + ret = dm_scan_fdt_dev(bus); + if (ret) { + printf("USB device scan from fdt failed (%d)", ret); + continue; + } } -#endif ret = device_probe(bus); if (ret == -ENODEV) { /* No such device. */