Merge tag 'u-boot-stm32-20230113' of https://source.denx.de/u-boot/custodians/u-boot-stm

Add driver to manage onboard hub supplies
Add calibration support for stm32-adc
Linux kernel v6.1 DT synchronization for stm32mp151.dtsi
stm32mp157a-dk1-scmi-u-boot.dtsi update
Add support of OP-TEE and STM32MP13x in bsec driver
ECDSA various fixes for stm32mp
diff --git a/arch/arm/dts/stm32mp151.dtsi b/arch/arm/dts/stm32mp151.dtsi
index 8bbb1ae..5d178b5 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 = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+			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 = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+			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 1209dfe..92fdf09 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 <dt-bindings/clock/stm32mp1-clksrc.h>
 #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 c265745..63948ef 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 <dt-bindings/clock/stm32mp1-clksrc.h>
 #include "stm32mp15-scmi-u-boot.dtsi"
 
 / {
diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts
index d142dd3..2d5db41 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 5a045d7..34af901 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 = <IT_OCP_BOOST 0>;
-			 };
+			};
 
 			vbus_otg: pwr_sw1 {
 				regulator-name = "vbus_otg";
 				interrupts = <IT_OCP_OTG 0>;
-			 };
+			};
 
-			 vbus_sw: pwr_sw2 {
+			vbus_sw: pwr_sw2 {
 				regulator-name = "vbus_sw";
 				interrupts = <IT_OCP_SWOUT 0>;
 				regulator-active-discharge = <1>;
-			 };
+			};
 		};
 
 		onkey {
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index 1db9057..a19b279 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -11,10 +11,10 @@
 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 e91ef1b..24d04dc 100644
--- a/arch/arm/mach-stm32mp/boot_params.c
+++ b/arch/arm/mach-stm32mp/boot_params.c
@@ -8,33 +8,18 @@
 #include <common.h>
 #include <log.h>
 #include <linux/libfdt.h>
+#include <asm/arch/sys_proto.h>
 #include <asm/sections.h>
 #include <asm/system.h>
 
 /*
- * 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 c00130b..f5f4b20 100644
--- a/arch/arm/mach-stm32mp/bsec.c
+++ b/arch/arm/mach-stm32mp/bsec.c
@@ -10,9 +10,11 @@
 #include <dm.h>
 #include <log.h>
 #include <misc.h>
+#include <tee.h>
 #include <asm/io.h>
 #include <asm/arch/bsec.h>
 #include <asm/arch/stm32mp1_smc.h>
+#include <dm/device.h>
 #include <dm/device_compat.h>
 #include <linux/arm-smccc.h>
 #include <linux/iopoll.h>
@@ -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 @@
 	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 @@
 	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 @@
 	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_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 @@
 	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 @@
 			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 const struct udevice_id stm32mp_bsec_ids[] = {
+	{ .compatible = "st,stm32mp13-bsec" },
 	{ .compatible = "st,stm32mp15-bsec" },
 	{}
 };
@@ -608,7 +771,8 @@
 	.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 278253e..85be8e2 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32key.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32key.c
@@ -8,6 +8,7 @@
 #include <console.h>
 #include <log.h>
 #include <misc.h>
+#include <asm/arch/bsec.h>
 #include <dm/device.h>
 #include <dm/uclass.h>
 
@@ -84,9 +85,6 @@
 		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 855fc75..dc4112d 100644
--- a/arch/arm/mach-stm32mp/cpu.c
+++ b/arch/arm/mach-stm32mp/cpu.c
@@ -22,6 +22,7 @@
 #include <dm/device.h>
 #include <dm/uclass.h>
 #include <linux/bitops.h>
+#include <spl.h>
 
 /*
  * early TLB into the .data section so that it not get cleared
@@ -378,3 +379,52 @@
 
 	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 a2f63ff..12b42b9 100644
--- a/arch/arm/mach-stm32mp/ecdsa_romapi.c
+++ b/arch/arm/mach-stm32mp/ecdsa_romapi.c
@@ -24,26 +24,10 @@
 					   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 @@
 	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 252eac3..10ebc53 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 f19a70e..0d39b67 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 @@
 
 /* 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 2f57118..aba3590 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 e12669b..853ab78 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 <command.h>
 #include <console.h>
 #include <misc.h>
+#include <asm/arch/bsec.h>
 #include <dm/device.h>
 #include <dm/uclass.h>
 
@@ -48,6 +49,7 @@
 		0x1298,
 		0x1341,
 		0x1497,
+		0x1635,
 	};
 
 	for (i = 0; i < ARRAY_SIZE(st_board_id); i++)
@@ -109,7 +111,7 @@
 		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 @@
 	}
 
 	/* 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 20addfb..7789aab 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -26,6 +26,7 @@
 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 0000000..89e18a2
--- /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 <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <power/regulator.h>
+
+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 4cab076..ab82480 100644
--- a/configs/stm32mp13_defconfig
+++ b/configs/stm32mp13_defconfig
@@ -7,6 +7,7 @@
 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_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 449d078..87e3b49 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -167,6 +167,7 @@
 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 d12e15d..5dc0021 100644
--- a/configs/stm32mp15_defconfig
+++ b/configs/stm32mp15_defconfig
@@ -143,6 +143,7 @@
 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 8f99ee2..c1ad4dd 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -143,6 +143,7 @@
 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 3759df3..9780ac9 100644
--- a/doc/board/st/stm32mp1.rst
+++ b/doc/board/st/stm32mp1.rst
@@ -620,7 +620,7 @@
     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 @@
 
 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 85efc11..1fba707 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 @@
 	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_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 @@
 	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 @@
 	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 @@
 	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 8efd461..ebe6bf9 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -105,6 +105,16 @@
 	  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 956e2a4..93c318c 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -271,19 +271,23 @@
 		/* 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. */