From 8b71b20e0e5431f0243a5a8078ac62be0af2189e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 8 Jul 2021 10:53:56 +0200 Subject: 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(-) (limited to 'arch') 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; } -- cgit v1.2.3 From 2a7034c77d628627c9462e27865e2d9258aeadd0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 9 Jul 2021 09:53:37 +0200 Subject: 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(-) (limited to 'arch') 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; -- cgit v1.2.3 From 59000ebe0b121619116c5081e0af7a8a41c2fcfe Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 20 Jul 2021 23:46:07 +0200 Subject: 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(-) (limited to 'arch') 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; -- cgit v1.2.3 From 8d7f5edd869e1763babbd1005c4e06023ff10e3b Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:25 -0500 Subject: 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 (limited to 'arch') 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); + } +} -- cgit v1.2.3 From 8533263c8512d059e546dd1d0032cfecd7b1a0cf Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:26 -0500 Subject: 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(+) (limited to 'arch') 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; -- cgit v1.2.3 From 65b3f56d42e5ddc9183843723cf735950f062410 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 15 Jul 2021 14:19:27 -0500 Subject: 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(+) (limited to 'arch') 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; }; }; -- cgit v1.2.3