From 8b71b20e0e5431f0243a5a8078ac62be0af2189e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 8 Jul 2021 10:53:56 +0200 Subject: [PATCH 1/9] arm: stm32mp1: force boot_device variable for invalid TAMP register value When the TAMP register 20 have an invalid value (0x0 for example after TAMPER error) the "boot_device" U-Boot env variable have no value and no error is displayed in U-Boot log. The STM32MP boot command bootcmd_stm32mp failed with strange trace: "Boot over !" and the next command in bootcmd_stm32mp failed with few indication: if test ${boot_device} = serial || test ${boot_device} = usb; then stm32prog ${boot_device} ${boot_instance}; As it is difficult to investigate, the current patch avoids this issue: - change the debug message to error: "unexpected boot mode" is displayed - display trace "Boot over invalid!" in bootcmd_stm32mp - execute "run distro_bootcmd" to try all the possible target Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index f6ed2ce0e4..eb79f3ffd2 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -556,7 +556,9 @@ static void setup_boot_mode(void) env_set("boot_instance", "0"); break; default: - log_debug("unexpected boot mode = %x\n", boot_mode); + env_set("boot_device", "invalid"); + env_set("boot_instance", ""); + log_err("unexpected boot mode = %x\n", boot_mode); break; } From 2a7034c77d628627c9462e27865e2d9258aeadd0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 9 Jul 2021 09:53:37 +0200 Subject: [PATCH 2/9] stm32mp1: add pull-up for gpio button PA13 and PA14 When a push-button is released and PA13/PA14 are defined as input (high-Z) the LED should not be active as the circuit is open but a small current leak through PCB or push-button close the circuit and allows a small LED bias giving erroneous level voltage. So it is recommended to activate an internal pull-up in order to clearly fix the voltage at PA13/PA14 when button is released and to wait a short delay before to read the GPIO value only when the pull-up is correctly configured. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 4 ++-- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 4 ++-- board/st/stm32mp1/stm32mp1.c | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 7dcc96c19c..4b37797f21 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -17,8 +17,8 @@ u-boot,error-led = "error"; u-boot,mmc-env-partition = "ssbl"; st,adc_usb_pd = <&adc1 18>, <&adc1 19>; - st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; - st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; + st,fastboot-gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + st,stm32prog-gpios = <&gpioa 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; }; firmware { diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 46a43371bd..fc6066aab2 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -16,8 +16,8 @@ u-boot,boot-led = "heartbeat"; u-boot,error-led = "error"; u-boot,mmc-env-partition = "ssbl"; - st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; - st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; + st,fastboot-gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + st,stm32prog-gpios = <&gpioa 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; }; firmware { diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 2faf5c81b4..59fb6e548c 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -155,6 +155,7 @@ static void board_key_check(void) &gpio, GPIOD_IS_IN)) { log_debug("could not find a /config/st,fastboot-gpios\n"); } else { + udelay(20); if (dm_gpio_get_value(&gpio)) { log_notice("Fastboot key pressed, "); boot_mode = BOOT_FASTBOOT; @@ -168,6 +169,7 @@ static void board_key_check(void) &gpio, GPIOD_IS_IN)) { log_debug("could not find a /config/st,stm32prog-gpios\n"); } else { + udelay(20); if (dm_gpio_get_value(&gpio)) { log_notice("STM32Programmer key pressed, "); boot_mode = BOOT_STM32PROG; From d974afe6861ae93c653ad91e3c0a93f9d40f7d29 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 9 Jul 2021 14:24:34 +0200 Subject: [PATCH 3/9] clk: stm32mp1: add support of missing SPI clocks Add the missing SPI clock even if these instances are not available on STMicroelectronics boards: SPI2_K, SPI3_K, SPI4_K, SPI6_K. With this patch, the SPI2 / SPI3 / SPI4 / SPI6 instances can be used on customer design without the clock driver error: stm32mp1_clk_get_id: clk id 131 not found Reviewed-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- drivers/clk/clk_stm32mp1.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 48c9514ba0..da95b1ac2f 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -73,6 +73,7 @@ DECLARE_GLOBAL_DATA_PTR; #define RCC_PLL2FRACR 0xA0 #define RCC_PLL2CSGR 0xA4 #define RCC_I2C46CKSELR 0xC0 +#define RCC_SPI6CKSELR 0xC4 #define RCC_CPERCKSELR 0xD0 #define RCC_STGENCKSELR 0xD4 #define RCC_DDRITFCR 0xD8 @@ -103,6 +104,7 @@ DECLARE_GLOBAL_DATA_PTR; #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 #define RCC_SPI2S1CKSELR 0x8D8 +#define RCC_SPI2S23CKSELR 0x8DC #define RCC_SPI45CKSELR 0x8E0 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 @@ -313,7 +315,9 @@ enum stm32mp1_parent_sel { _DSI_SEL, _ADC12_SEL, _SPI1_SEL, + _SPI23_SEL, _SPI45_SEL, + _SPI6_SEL, _RTC_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, @@ -524,6 +528,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL), STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 11, SPI2_K, _SPI23_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 12, SPI3_K, _SPI23_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), @@ -536,6 +542,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 9, SPI4_K, _SPI45_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 10, SPI5_K, _SPI45_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), @@ -549,6 +556,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), @@ -613,10 +621,13 @@ static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48}; static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER}; static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; +/* same parents for SPI1=RCC_SPI2S1CKSELR and SPI2&3 = RCC_SPI2S23CKSELR */ static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, _PLL3_R}; static const u8 spi45_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER}; +static const u8 spi6_parents[] = {_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, + _HSE_KER, _PLL3_Q}; static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { @@ -643,7 +654,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), + STM32MP1_CLK_PARENT(_SPI23_SEL, RCC_SPI2S23CKSELR, 0, 0x7, spi_parents), STM32MP1_CLK_PARENT(_SPI45_SEL, RCC_SPI45CKSELR, 0, 0x7, spi45_parents), + STM32MP1_CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents), STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT, (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT), rtc_parents), From 59000ebe0b121619116c5081e0af7a8a41c2fcfe Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 20 Jul 2021 23:46:07 +0200 Subject: [PATCH 4/9] ARM: dts: stm32: Fix AV96 eMMC pinmux Commit 500327e2ea7 ("ARM: dts: stm32mp1: DT alignment with Linux kernel v5.8-rc1") renamed sdmmc2_d47_pins_b phandle to sdmmc2_d47_pins_c, but without updating the AV96 DT which uses that phandle. Linux missed similar update as well and it was only added in commit 1ad6e36ec266 ("ARM: dts: stm32: Fix sdmmc2 pins on AV96") . Update the AV96 DT pinmux phandle, otherwise eMMC 8bit mode does not work and access to eMMC takes a very long time to fall back to 4bit mode. Signed-off-by: Marek Vasut Cc: Patrick Delaunay Cc: Patrice Chotard Reviewed-by: Patrick Delaunay --- arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi | 2 +- arch/arm/dts/stm32mp15xx-dhcor-avenger96.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi index 1ae57e1854..8b275e4950 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi @@ -57,7 +57,7 @@ }; }; -&sdmmc2_d47_pins_b { +&sdmmc2_d47_pins_c { u-boot,dm-spl; pins { u-boot,dm-spl; diff --git a/arch/arm/dts/stm32mp15xx-dhcor-avenger96.dts b/arch/arm/dts/stm32mp15xx-dhcor-avenger96.dts index 9b5dda318e..0e860e5cf8 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-avenger96.dts +++ b/arch/arm/dts/stm32mp15xx-dhcor-avenger96.dts @@ -152,7 +152,7 @@ &sdmmc2 { pinctrl-names = "default"; - pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_b>; + pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_c>; non-removable; no-sd; no-sdio; From 5f6e5c37c67381b9790f55a34640415939a479a5 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:23 -0500 Subject: [PATCH 5/9] spl: mmc: Support OP-TEE payloads in Falcon mode In general, Falcon mode means we're booting a linux kernel directly. With FIT images, however, an OP-TEE secure kernel can be booted before linux. Thus, if the next stage is an IH_OS_TEE, this isn't necessarily a problem. Of course, a general solution would involve mmc_load_image_raw_os() only loading the binary, and leaving the decision of suitability to someone else. However, a rework of the boot flow is beyond the scope of this patch. Accept IH_OS_TEE as a valid OS value. Signed-off-by: Alexandru Gagniuc Reviewed-by: Tom Rini Reviewed-by: Patrick Delaunay --- common/spl/spl_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 2377d0937d..4dff9bfd6e 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -230,8 +230,8 @@ static int mmc_load_image_raw_os(struct spl_image_info *spl_image, if (ret) return ret; - if (spl_image->os != IH_OS_LINUX) { - puts("Expected Linux image is not found. Trying to start U-boot\n"); + if (spl_image->os != IH_OS_LINUX && spl_image->os != IH_OS_TEE) { + puts("Expected image is not found. Trying to start U-boot\n"); return -ENOENT; } From a25d6b65c21b1298712c75604ff606025cb40267 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:24 -0500 Subject: [PATCH 6/9] spl: Introduce spl_board_prepare_for_optee() hook OP-TEE requires some particular setup, which is not needed for linux or other payloads. Add a hook for platform-specific code to perform any OP-TEE related configuration and initialization. A weak function is used because it is symmetrical to other spl_board_prepare_for_*() implementations. A solution to avoid the use of weak functions would trivially apply to all these implementations. However, re-designing this is beyond the scope of this patch. Signed-off-by: Alexandru Gagniuc Reviewed-by: Tom Rini Reviewed-by: Simon Glass Reviewed-by: Patrick Delaunay --- common/spl/spl.c | 5 +++++ include/spl.h | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/common/spl/spl.c b/common/spl/spl.c index 3ec16d0de6..d1b072d82c 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -167,6 +167,10 @@ __weak void spl_board_prepare_for_linux(void) /* Nothing to do! */ } +__weak void spl_board_prepare_for_optee(void *fdt) +{ +} + __weak void spl_board_prepare_for_boot(void) { /* Nothing to do! */ @@ -763,6 +767,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) #if CONFIG_IS_ENABLED(OPTEE) case IH_OS_TEE: debug("Jumping to U-Boot via OP-TEE\n"); + spl_board_prepare_for_optee(spl_image.fdt_addr); spl_optee_entry(NULL, NULL, spl_image.fdt_addr, (void *)spl_image.entry_point); break; diff --git a/include/spl.h b/include/spl.h index 74a1939452..925b6f0cc6 100644 --- a/include/spl.h +++ b/include/spl.h @@ -432,6 +432,20 @@ int spl_parse_image_header(struct spl_image_info *spl_image, const struct image_header *header); void spl_board_prepare_for_linux(void); + +/** + * spl_board_prepare_for_optee() - Prepare board for an OPTEE payload + * + * Prepares the board for booting an OP-TEE payload. Initialization is platform + * specific, and may include configuring the TrustZone memory, and other + * initialization steps required by OP-TEE. + * Note that @fdt is not used directly by OP-TEE. OP-TEE passes this @fdt to + * its normal world target. This target is not guaranteed to be u-boot, so @fdt + * changes that would normally be done by u-boot should be done in this step. + * + * @fdt: Devicetree that will be passed on, or NULL + */ +void spl_board_prepare_for_optee(void *fdt); void spl_board_prepare_for_boot(void); int spl_board_ubi_load_image(u32 boot_device); int spl_board_boot_device(u32 boot_device); From 8d7f5edd869e1763babbd1005c4e06023ff10e3b Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:25 -0500 Subject: [PATCH 7/9] arm: stm32mp: Implement support for TZC 400 controller The purpose of this change is to allow configuring TrustZone (TZC) memory permissions. For example, OP-TEE expects TZC regions to be configured in a very particular way. The API presented here is intended to allow exactly that. UCLASS support is not implemented, because it would not be too useful. Changing TZC permissions needs to be done with care, so as not to cut off access to memory we are currently using. One place where we can use this is at the end of SPL, right before jumping to OP-TEE. Signed-off-by: Alexandru Gagniuc Reviewed-by: Patrick Delaunay --- arch/arm/mach-stm32mp/Makefile | 1 + arch/arm/mach-stm32mp/include/mach/tzc.h | 33 ++++++ arch/arm/mach-stm32mp/tzc400.c | 136 +++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 arch/arm/mach-stm32mp/include/mach/tzc.h create mode 100644 arch/arm/mach-stm32mp/tzc400.c diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index aa39867080..879c1961fe 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -10,6 +10,7 @@ obj-y += bsec.o ifdef CONFIG_SPL_BUILD obj-y += spl.o +obj-y += tzc400.o else obj-y += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o diff --git a/arch/arm/mach-stm32mp/include/mach/tzc.h b/arch/arm/mach-stm32mp/include/mach/tzc.h new file mode 100644 index 0000000000..16db55c464 --- /dev/null +++ b/arch/arm/mach-stm32mp/include/mach/tzc.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Simple API for configuring TrustZone memory regions + * + * The premise is that the desired TZC layout is known beforehand, and it can + * be configured in one step. tzc_configure() provides this functionality. + */ +#ifndef MACH_TZC_H +#define MACH_TZC_H + +#include + +enum tzc_sec_mode { + TZC_ATTR_SEC_NONE = 0, + TZC_ATTR_SEC_R = 1, + TZC_ATTR_SEC_W = 2, + TZC_ATTR_SEC_RW = 3 +}; + +struct tzc_region { + uintptr_t base; + uintptr_t top; + enum tzc_sec_mode sec_mode; + uint16_t nsec_id; + uint16_t filters_mask; +}; + +int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg); +int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask); +int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask); +void tzc_dump_config(uintptr_t tzc); + +#endif /* MACH_TZC_H */ diff --git a/arch/arm/mach-stm32mp/tzc400.c b/arch/arm/mach-stm32mp/tzc400.c new file mode 100644 index 0000000000..cdc4a40eda --- /dev/null +++ b/arch/arm/mach-stm32mp/tzc400.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Simple API for configuring TrustZone memory restrictions for TZC400 + */ + +#define LOG_CATEGORY LOGC_ARCH + +#include +#include + +#define TZC_TIMEOUT_US 100 + +#define TZC_BUILD_CONFIG 0x00 +#define TZC_ACTION 0x04 +#define TZC_ACTION_NONE 0 +#define TZC_ACTION_ERR 1 +#define TZC_ACTION_INT 2 +#define TZC_ACTION_INT_ERR 3 +#define TZC_GATE_KEEPER 0x08 + +#define TZC_REGION0_OFFSET 0x100 +#define TZC_REGION_CFG_SIZE 0x20 +#define TZC_REGION1_OFFSET 0x120 +#define TZC_REGION_BASE 0x00 +#define TZC_REGION_TOP 0x08 +#define TZC_REGION_ATTRIBUTE 0x10 +#define TZC_REGION_ACCESS 0x14 + +static uint32_t tzc_read(uintptr_t tzc, size_t reg) +{ + return readl(tzc + reg); +} + +static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val) +{ + writel(val, tzc + reg); +} + +static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg) +{ + uint16_t active_filters = 0; + + for ( ; cfg->top != 0; cfg++) + active_filters |= cfg->filters_mask; + + return active_filters; +} + +int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg) +{ + uintptr_t region = tzc + TZC_REGION1_OFFSET; + uint32_t nsid, attr_reg, active_filters; + int ret; + + active_filters = tzc_config_get_active_filters(cfg); + if (active_filters == 0) + return -EINVAL; + + ret = tzc_disable_filters(tzc, active_filters); + if (ret < 0) + return ret; + + for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) { + attr_reg = (cfg->sec_mode & 0x03) << 30; + attr_reg |= (cfg->filters_mask & 0x03) << 0; + nsid = cfg->nsec_id & 0xffff; + nsid |= nsid << 16; + + tzc_write(region, TZC_REGION_BASE, cfg->base); + tzc_write(region, TZC_REGION_TOP, cfg->top); + tzc_write(region, TZC_REGION_ACCESS, nsid); + tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg); + } + + tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR); + return tzc_enable_filters(tzc, active_filters); +} + +int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask) +{ + uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER); + uint32_t filter_status = filters_mask << 16; + + gate &= ~filters_mask; + tzc_write(tzc, TZC_GATE_KEEPER, gate); + + return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate, + (gate & filter_status) == 0, TZC_TIMEOUT_US); +} + +int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask) +{ + uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER); + uint32_t filter_status = filters_mask << 16; + + gate |= filters_mask; + tzc_write(tzc, TZC_GATE_KEEPER, gate); + + return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate, + (gate & filter_status) == filter_status, + TZC_TIMEOUT_US); +} + +static const char *sec_access_str_from_attr(uint32_t attr) +{ + const char *const sec_mode[] = { "none", "RO ", "WO ", "RW " }; + + return sec_mode[(attr >> 30) & 0x03]; +} + +void tzc_dump_config(uintptr_t tzc) +{ + uint32_t build_config, base, top, attr, nsaid; + int num_regions, i; + uintptr_t region; + + build_config = tzc_read(tzc, TZC_BUILD_CONFIG); + num_regions = ((build_config >> 0) & 0x1f) + 1; + + for (i = 0; i < num_regions; i++) { + region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE; + + base = tzc_read(region, TZC_REGION_BASE); + top = tzc_read(region, TZC_REGION_TOP); + attr = tzc_read(region, TZC_REGION_ATTRIBUTE); + nsaid = tzc_read(region, TZC_REGION_ACCESS); + + if (attr == 0 && nsaid == 0) + continue; + + log_info("TZC region %u: %08x->%08x - filters 0x%x\n", + i, base, top, (attr >> 0) & 0xf); + log_info("\t Secure access %s NSAID %08x\n", + sec_access_str_from_attr(attr), nsaid); + } +} From 8533263c8512d059e546dd1d0032cfecd7b1a0cf Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:26 -0500 Subject: [PATCH 8/9] stm32mp1: spl: Configure TrustZone controller for OP-TEE OP-TEE is very particular about how the TZC should be configured. When booting an OP-TEE payload, an incorrect TZC configuration will result in a panic. Most information can be derived from the SPL devicetree. The only information we don't have is the split between TZDRAM and shared memory. This has to be hardcoded. The rest of the configuration is fairly easy, and only requires 3 TZC regions. Configure them. Signed-off-by: Alexandru Gagniuc --- arch/arm/mach-stm32mp/spl.c | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index b53659a698..405eff68a3 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -11,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include u32 spl_boot_device(void) @@ -92,6 +94,96 @@ __weak int board_early_init_f(void) return 0; } +uint32_t stm32mp_get_dram_size(void) +{ + struct ram_info ram; + struct udevice *dev; + int ret; + + if (uclass_get_device(UCLASS_RAM, 0, &dev)) + return 0; + + ret = ram_get_info(dev, &ram); + if (ret) + return 0; + + return ram.size; +} + +static int optee_get_reserved_memory(uint32_t *start, uint32_t *size) +{ + phys_size_t fdt_mem_size; + fdt_addr_t fdt_start; + ofnode node; + + node = ofnode_path("/reserved-memory/optee"); + if (!ofnode_valid(node)) + return 0; + + fdt_start = ofnode_get_addr_size(node, "reg", &fdt_mem_size); + *start = fdt_start; + *size = fdt_mem_size; + return (fdt_start < 0) ? fdt_start : 0; +} + +#define CFG_SHMEM_SIZE 0x200000 +#define STM32_TZC_NSID_ALL 0xffff +#define STM32_TZC_FILTER_ALL 3 + +void stm32_init_tzc_for_optee(void) +{ + const uint32_t dram_size = stm32mp_get_dram_size(); + const uintptr_t dram_top = STM32_DDR_BASE + (dram_size - 1); + uint32_t optee_base, optee_size, tee_shmem_base; + const uintptr_t tzc = STM32_TZC_BASE; + int ret; + + if (dram_size == 0) + panic("Cannot determine DRAM size from devicetree\n"); + + ret = optee_get_reserved_memory(&optee_base, &optee_size); + if (ret < 0 || optee_size <= CFG_SHMEM_SIZE) + panic("Invalid OPTEE reserved memory in devicetree\n"); + + tee_shmem_base = optee_base + optee_size - CFG_SHMEM_SIZE; + + const struct tzc_region optee_config[] = { + { + .base = STM32_DDR_BASE, + .top = optee_base - 1, + .sec_mode = TZC_ATTR_SEC_NONE, + .nsec_id = STM32_TZC_NSID_ALL, + .filters_mask = STM32_TZC_FILTER_ALL, + }, { + .base = optee_base, + .top = tee_shmem_base - 1, + .sec_mode = TZC_ATTR_SEC_RW, + .nsec_id = 0, + .filters_mask = STM32_TZC_FILTER_ALL, + }, { + .base = tee_shmem_base, + .top = dram_top, + .sec_mode = TZC_ATTR_SEC_NONE, + .nsec_id = STM32_TZC_NSID_ALL, + .filters_mask = STM32_TZC_FILTER_ALL, + }, { + .top = 0, + } + }; + + flush_dcache_all(); + + tzc_configure(tzc, optee_config); + tzc_dump_config(tzc); + + dcache_disable(); +} + +void spl_board_prepare_for_optee(void *fdt) +{ + stm32_init_tzc_for_optee(); +} + void board_init_f(ulong dummy) { struct udevice *dev; From 65b3f56d42e5ddc9183843723cf735950f062410 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:27 -0500 Subject: [PATCH 9/9] ARM: dts: stm32mp: Add OP-TEE reserved memory to SPL dtb Add the "/reserved-memory/optee" node to the SPL devicetree. The purpose is to allow configuring TZC regions when booting OP-TEE. Signed-off-by: Alexandru Gagniuc Reviewed-by: Simon Glass --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 4b37797f21..a8e15ad09a 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -29,9 +29,12 @@ }; reserved-memory { + u-boot,dm-spl; + optee@de000000 { reg = <0xde000000 0x02000000>; no-map; + u-boot,dm-spl; }; };