From 79da4074ddf0f76b3c2ec26d58c9a33ac7884222 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 12 Dec 2022 11:32:42 +0100 Subject: [PATCH 01/18] ARM: dts: stm32: update vbus-supply of usbphyc_port0 on stm32mp157c-ev1 phy-stm32-usbphyc bindings uses a connector node with vbus-supply property. [backport from linux 43e55d778a6b] Signed-off-by: Fabrice Gasnier Reviewed-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157c-ev1.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index d142dd30e1..26654729ec 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -385,6 +385,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 { From ba1fa2abde88257c29ee4d8f3884ab6657a3193a Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 12 Dec 2022 11:44:35 +0100 Subject: [PATCH 02/18] usb: onboard-hub: add driver to manage onboard hub supplies The main issue the driver addresses is that a USB hub needs to be powered before it can be discovered. This is often solved by using "regulator-always-on". This driver is inspired by the Linux v6.1 driver. It only enables (or disables) the hub vdd (3v3) supply, so it can be enumerated. Scanning of the device tree is done in a similar manner to the sandbox, by the usb-uclass. DT part looks like: &usbh_ehci { ... #address-cells = <1>; #size-cells = <0>; hub@1 { compatible = "usb424,2514"; reg = <1>; vdd-supply = <&v3v3>; }; }; When the bus gets probed, the driver is automatically probed/removed from the bus tree, as an example on stm32: STM32MP> usb start starting USB... STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- usb 0 [ + ] ehci_generic | |-- usb@5800d000 usb_hub 0 [ + ] usb_onboard_hub | | `-- hub@1 usb_hub 1 [ + ] usb_hub | | `-- usb_hub STM32MP> usb tree USB device tree: 1 Hub (480 Mb/s, 0mA) | u-boot EHCI Host Controller | +-2 Hub (480 Mb/s, 2mA) Signed-off-by: Fabrice Gasnier Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay --- common/Makefile | 1 + common/usb_onboard_hub.c | 62 +++++++++++++++++++++++++++++++++++ drivers/usb/Kconfig | 10 ++++++ drivers/usb/host/usb-uclass.c | 16 +++++---- 4 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 common/usb_onboard_hub.c 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/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. */ From 5f74d97c454bb708e5f4b64e24ebdd4a30c1298e Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 12 Dec 2022 11:44:36 +0100 Subject: [PATCH 03/18] configs: stm32: enable USB onboard HUB driver Activate the USB onboard HUB driver, that is used to enable the HUB supply on STM32MP15 EVAL, DK1 and DK2 boards. This avoids marking the 3v3 corresponding regulator as always-on. Signed-off-by: Fabrice Gasnier Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + 3 files changed, 3 insertions(+) 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 From 214d6e7e68ce77cc57e63d6d1b23987003306bf5 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 12 Dec 2022 11:44:37 +0100 Subject: [PATCH 04/18] ARM: dts: stm32: add support for USB2514B onboard hub on stm32mp157c-ev1 Add support for USB2514B onboard hub on stm32mp157c EV1 board. The HUB is supplied by a 3v3 PMIC regulator. [backport from linux ad9591b01d24] Signed-off-by: Fabrice Gasnier Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- arch/arm/dts/stm32mp157c-ev1.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 26654729ec..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 { From 17bae7766c84a9aaf78c3efa235bc67c14cea56d Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 15 Dec 2022 13:51:10 +0100 Subject: [PATCH 05/18] adc: stm32mp15: add calibration support Add support of offset and linear calibration for STM32MP15. The calibration is performed once at probe. The ADC is set in power on state for calibration. It remains in this state after calibration, to give to the kernel the opportunity to retrieve calibration data, directly from the ADC. Signed-off-by: Olivier Moysan Reviewed-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/adc/stm32-adc.c | 148 +++++++++++++++++++++++++++++++++------- 1 file changed, 123 insertions(+), 25 deletions(-) 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 = { From d1d56638c4e84395c6be13666034890e3c9c64c7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 14 Dec 2022 16:24:59 +0100 Subject: [PATCH 06/18] ARM: dts: stm32mp15: remove clksrc include in SCMI dtsi file The include file stm32mp1-clksrc.h is not necessary for the SCMI STM32MP15 dtsi files as the clock tree is not defined in the U-Boot SCMI device tree; these SCMI device tree only support TFABOOT with stm32mp15_defconfig, SPL with the basic boot defconfig is not supported. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157a-dk1-scmi-u-boot.dtsi | 1 - arch/arm/dts/stm32mp157c-ed1-scmi-u-boot.dtsi | 1 - 2 files changed, 2 deletions(-) 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" / { From 126aa470d68b85d12d508948dd2e4e476e03085e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 14 Dec 2022 16:25:00 +0100 Subject: [PATCH 07/18] ARM: dts: stm32mp15: fix typo in stm32mp15xx-dkx.dtsi Remove unnecessary space in device tree stm32mp15xx-dkx.dtsi. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15xx-dkx.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 { From 6e391c7d5f36086b0babb555f38ac1848e188e13 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 14 Dec 2022 16:25:01 +0100 Subject: [PATCH 08/18] ARM: dts: stm32: Add timer interrupts on stm32mp15 The timer units in the stm32mp15x CPUs have interrupts, depending on the timer flavour either one "global" or four dedicated ones. Add the irqs to the timer units on stm32mp15x. Sync the DT Files with linux kernel v6.1 and with commit a9b70102253ce ("ARM: dts: stm32: Add timer interrupts on stm32mp15") Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp151.dtsi | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) 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>, From 27bad4e7fcb143c80a0e9337bb7e0ee95799c9f6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:14 +0100 Subject: [PATCH 09/18] stm32mp: cosmetic: Update of bsec driver Remove unnecessary return in stm32mp_bsec_write_lock and replace tab by space for plat_auto opts. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index c00130b08b..51ccff9aa5 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -468,8 +468,6 @@ 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 stm32mp_bsec_read(struct udevice *dev, int offset, @@ -608,7 +606,7 @@ 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), .ops = &stm32mp_bsec_ops, .probe = stm32mp_bsec_probe, }; From 33a909a42a07b35c78782fc4c9dbb36f066641fd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:15 +0100 Subject: [PATCH 10/18] stm32mp: Add OP-TEE support in bsec driver When OP-TEE is used, the SMC for BSEC management are not available and the STM32MP BSEC pseudo TA must be used (it is mandatory for STM32MP13 and it is a new feature for STM32MP15x). The BSEC driver try to open a session to this PTA BSEC at probe and use it for OTP read or write access to fuse or to shadow. This patch also adapts the commands stm32key and stboard to handle the BSEC_LOCK_PERM lock value instead of 1. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 173 +++++++++++++++++++++- arch/arm/mach-stm32mp/cmd_stm32key.c | 4 +- arch/arm/mach-stm32mp/include/mach/bsec.h | 7 + board/st/common/cmd_stboard.c | 5 +- doc/board/st/stm32mp1.rst | 6 +- 5 files changed, 183 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 51ccff9aa5..fe79c986f9 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; @@ -470,14 +509,109 @@ static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) return bsec_permanent_lock_otp(dev, plat->base, otp); } +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) { @@ -491,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++) { @@ -515,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) { @@ -533,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++) { @@ -581,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 @@ -607,6 +771,7 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .of_match = stm32mp_bsec_ids, .of_to_plat = stm32mp_bsec_of_to_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/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/board/st/common/cmd_stboard.c b/board/st/common/cmd_stboard.c index e12669b862..213fb5d302 100644 --- a/board/st/common/cmd_stboard.c +++ b/board/st/common/cmd_stboard.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -109,7 +110,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 +179,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/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:: From a33885ff496ccd867ee9a83f09c1bd521207b096 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:16 +0100 Subject: [PATCH 11/18] stm32mp: Add support of STM32MP13x in bsec driver Add support for "st,stm32mp13-bsec" for STM32MP13x in the bsec driver based on OP-TEE pseudo TA STM32MP BSEC. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fe79c986f9..f5f4b20d47 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -761,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" }, {} }; From 7de0d10ca7167d0b0ac2d28a98b3a4e725c2d3b8 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:17 +0100 Subject: [PATCH 12/18] configs: stm32mp13: Activate CONFIG_CMD_FUSE Activate the command fuse to access on STM32MP13x OTP with the BSEC driver. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 4cab076473..012882ff91 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -26,6 +26,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 From 4b002d962850d07ee640fbfa8d699202ac9edd15 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:18 +0100 Subject: [PATCH 13/18] board: st: Add support of STM32MP13x boards in stm32board cmd Add board identifiers for STMicroelectronics STM32MP13x boards: - DISCO board: MB1635 Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/common/Kconfig | 2 +- board/st/common/cmd_stboard.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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 213fb5d302..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) @@ -49,6 +49,7 @@ static bool check_stboard(u16 board) 0x1298, 0x1341, 0x1497, + 0x1635, }; for (i = 0; i < ARRAY_SIZE(st_board_id); i++) From d3a87e32dd0841463c2d5ea0778aecf0fc03a93a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 6 Jan 2023 13:20:19 +0100 Subject: [PATCH 14/18] configs: stm32mp13: Activate command stm32key Activate the command stm32key with CONFIG_CMD_STM32KEY. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 012882ff91..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 From bbafbc044dcab06eccba0dc6a7235a0c6e782484 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Jan 2023 18:58:39 +0100 Subject: [PATCH 15/18] ARM: stm32: Fix ECDSA authentication with Dcache enabled In case Dcache is enabled while the ECDSA authentication function is called via BootROM ROM API, the MMU tables are set up and the BootROM region is not marked as executable, so an attempt to run code from it results in a hang. Mark the BootROM region as executable as suggested by Patrick to prevent the hang. Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut --- arch/arm/mach-stm32mp/ecdsa_romapi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-stm32mp/ecdsa_romapi.c b/arch/arm/mach-stm32mp/ecdsa_romapi.c index a2f63ff879..6156526253 100644 --- a/arch/arm/mach-stm32mp/ecdsa_romapi.c +++ b/arch/arm/mach-stm32mp/ecdsa_romapi.c @@ -81,6 +81,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; From dbeaca79b7924d46a51228fa0b1db3462036b5e0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Jan 2023 18:58:40 +0100 Subject: [PATCH 16/18] ARM: stm32: Factor out save_boot_params The STM32MP15xx platform currently comes with two incompatible implementations of save_boot_params() weak function override. Factor the save_boot_params() implementation into common cpu.c code and provide accessors to read out both ROM API table address and DT address from any place in the code instead. Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut --- arch/arm/mach-stm32mp/boot_params.c | 21 ++--------- arch/arm/mach-stm32mp/cpu.c | 35 +++++++++++++++++++ arch/arm/mach-stm32mp/ecdsa_romapi.c | 20 ++--------- .../arm/mach-stm32mp/include/mach/sys_proto.h | 3 ++ 4 files changed, 43 insertions(+), 36 deletions(-) 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/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 855fc755fe..ee59866bb7 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -378,3 +378,38 @@ 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; +} diff --git a/arch/arm/mach-stm32mp/ecdsa_romapi.c b/arch/arm/mach-stm32mp/ecdsa_romapi.c index 6156526253..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; } 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); From 6eea541514461b073be89919bca2e322a2fd1bc8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Jan 2023 18:58:41 +0100 Subject: [PATCH 17/18] ARM: stm32: Pass ROM API table pointer to U-Boot proper The ROM API table pointer is no longer accessible from U-Boot, fix this by passing the ROM API pointer through. This makes it possible for U-Boot to call ROM API functions to authenticate payload like signed fitImages. Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut --- arch/arm/mach-stm32mp/cpu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index ee59866bb7..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 @@ -413,3 +414,17 @@ 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 From 0e86f813f474ea6f46c6055b579eba10930dffd6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Jan 2023 18:58:42 +0100 Subject: [PATCH 18/18] ARM: stm32: Make ECDSA authentication available to U-Boot With U-Boot having access to ROM API call table, it is possible to use the ROM API call it authenticate e.g. signed kernel fitImages using the BootROM ECDSA support. Make this available by pulling the ECDSA BootROM call support from SPL-only guard. Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut --- arch/arm/mach-stm32mp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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