diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc index 9e3fc1b..a8a9377 100644 --- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc @@ -35,8 +35,11 @@ DEPENDS_append = " ${@bb.utils.contains('TF_A_ENABLE_DEBUG_WRAPPER', '1', 'stm32 # Default log level ST_TF_A_DEBUG_LOG_LEVEL ??= "40" -# Extra make settings -EXTRA_OEMAKE = 'CROSS_COMPILE=${TARGET_PREFIX}' +# Configure make settings +EXTRA_OEMAKE += 'PLAT=${TFA_PLATFORM}' +EXTRA_OEMAKE += 'ARCH=${TFA_ARM_ARCH}' +EXTRA_OEMAKE += 'ARM_ARCH_MAJOR=${TFA_ARM_MAJOR}' +EXTRA_OEMAKE += 'CROSS_COMPILE=${TARGET_PREFIX}' # Debug support EXTRA_OEMAKE += '${@bb.utils.contains('ST_TF_A_DEBUG_TRACE', '1', 'DEBUG=1', '', d)}' EXTRA_OEMAKE += '${@bb.utils.contains('ST_TF_A_DEBUG_TRACE', '1', 'LOG_LEVEL=${ST_TF_A_DEBUG_LOG_LEVEL}', '', d)}' diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0002-v2.4-stm32mp-r1.1-rc1.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0002-v2.4-stm32mp-r1.1-rc1.patch new file mode 100644 index 0000000..f95af48 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0002-v2.4-stm32mp-r1.1-rc1.patch @@ -0,0 +1,157 @@ +From 903a55e874e91ccd1fb435bea3a675e2eb4257fa Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Wed, 2 Jun 2021 16:45:18 +0200 +Subject: [PATCH 2/3] v2.4-stm32mp-r1.1-rc1 + +--- + docs/plat/stm32mp1.rst | 9 ++++++--- + drivers/st/clk/stm32mp1_clk.c | 4 ++-- + include/drivers/st/stm32mp1_rcc.h | 16 ++++++++++++++++ + plat/st/common/stm32mp_crypto_lib.c | 5 ++++- + plat/st/stm32mp1/stm32mp1_def.h | 2 ++ + plat/st/stm32mp1/stm32mp1_helper.S | 13 +++++++++++++ + 6 files changed, 43 insertions(+), 6 deletions(-) + +diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst +index fb7afdbbb0..95f4a186f5 100644 +--- a/docs/plat/stm32mp1.rst ++++ b/docs/plat/stm32mp1.rst +@@ -153,7 +153,10 @@ To build TF-A BL2 with its STM32 header for SD-card boot: + .. code:: bash + + make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \ +- DTB_FILE_NAME=stm32mp157c-ev1.dtb ++ DTB_FILE_NAME=stm32mp157c-ev1.dtb STM32MP_SDMMC=1 ++ ++For other boot devices, you have to replace STM32MP_SDMMC in the previous command ++with the desired devive flag. + + This BL2 is independent of the BL32 used (SP_min or OP-TEE) + +@@ -204,14 +207,14 @@ __________________ + --nt-fw /u-boot-nodtb.bin \ + --nt-fw-cert build/stm32mp1/cert_images/u-boot.bin.crt \ + --nt-fw-key-cert build/stm32mp1/cert_images/u-boot.bin.key-crt \ +- --hw-config /u-boot.dtb ++ --hw-config /u-boot.dtb \ + --fw-config build/stm32mp1/debug/fdts/fw-config.dtb + + tools/fiptool/fiptool create --tos-fw /tee-header_v2.bin \ + --tos-fw-extra1 /tee-pager_v2.bin \ + --tos-fw-extra2 /tee-pageable_v2.bin \ + --nt-fw /u-boot-nodtb.bin \ +- --hw-config /uboot-nodtb.dtb \ ++ --hw-config /u-boot.dtb \ + --tos-fw-cert build/stm32mp1/cert_images/tee-header_v2.bin.crt \ + --tos-fw-key-cert build/stm32mp1/cert_images/tee-header_v2.bin.key-crt \ + --nt-fw-cert build/stm32mp1/cert_images/u-boot.bin.crt \ +diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c +index 00954cb2e8..d074a1568c 100644 +--- a/drivers/st/clk/stm32mp1_clk.c ++++ b/drivers/st/clk/stm32mp1_clk.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -1853,7 +1853,7 @@ static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) + (clksrc != (uint32_t)CLK_RTC_DISABLED)) { + mmio_clrsetbits_32(address, + RCC_BDCR_RTCSRC_MASK, +- clksrc << RCC_BDCR_RTCSRC_SHIFT); ++ (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); + + mmio_setbits_32(address, RCC_BDCR_RTCCKEN); + } +diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h +index feaac43a13..616051e772 100644 +--- a/include/drivers/st/stm32mp1_rcc.h ++++ b/include/drivers/st/stm32mp1_rcc.h +@@ -576,6 +576,22 @@ + #define RCC_FMCCKSELR_FMCSRC_MASK GENMASK(1, 0) + #define RCC_FMCCKSELR_FMCSRC_SHIFT 0 + ++/* RCC_APB1RSTSETR register fields */ ++#define RCC_APB1RSTSETR_USART2RST BIT(14) ++#define RCC_APB1RSTSETR_USART3RST BIT(15) ++#define RCC_APB1RSTSETR_UART4RST BIT(16) ++#define RCC_APB1RSTSETR_UART5RST BIT(17) ++#define RCC_APB1RSTSETR_UART7RST BIT(18) ++#define RCC_APB1RSTSETR_UART8RST BIT(19) ++ ++/* RCC_APB1RSTCLRR register fields */ ++#define RCC_APB1RSTCLRR_USART2RST BIT(14) ++#define RCC_APB1RSTCLRR_USART3RST BIT(15) ++#define RCC_APB1RSTCLRR_UART4RST BIT(16) ++#define RCC_APB1RSTCLRR_UART5RST BIT(17) ++#define RCC_APB1RSTCLRR_UART7RST BIT(18) ++#define RCC_APB1RSTCLRR_UART8RST BIT(19) ++ + /* RCC_USBCKSELR register fields */ + #define RCC_USBCKSELR_USBPHYSRC_MASK GENMASK(1, 0) + #define RCC_USBCKSELR_USBPHYSRC_SHIFT 0 +diff --git a/plat/st/common/stm32mp_crypto_lib.c b/plat/st/common/stm32mp_crypto_lib.c +index de9601d2b8..9582162813 100644 +--- a/plat/st/common/stm32mp_crypto_lib.c ++++ b/plat/st/common/stm32mp_crypto_lib.c +@@ -40,6 +40,7 @@ static void crypto_lib_init(void) + { + boot_api_context_t *boot_context = + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); ++ int ret; + + if (!stm32mp_is_auth_supported()) { + return; +@@ -48,7 +49,9 @@ static void crypto_lib_init(void) + auth_ops.verify_signature = + boot_context->bootrom_ecdsa_verify_signature; + +- if (stm32_hash_register() != 0) { ++ ret = stm32_hash_register(); ++ if (ret != 0) { ++ ERROR("HASH init (%d)\n", ret); + panic(); + } + } +diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h +index 027dba1bde..326b227842 100644 +--- a/plat/st/stm32mp1/stm32mp1_def.h ++++ b/plat/st/stm32mp1/stm32mp1_def.h +@@ -433,6 +433,8 @@ enum ddr_type { + #define DEBUG_UART_TX_CLKSRC RCC_UART24CKSELR_HSI + #define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR + #define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN ++#define DEBUG_UART_RST_REG RCC_APB1RSTSETR ++#define DEBUG_UART_RST_BIT RCC_APB1RSTSETR_UART4RST + + /******************************************************************************* + * STM32MP1 ETZPC +diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S +index bc2d73cebb..315a67f2cf 100644 +--- a/plat/st/stm32mp1/stm32mp1_helper.S ++++ b/plat/st/stm32mp1/stm32mp1_helper.S +@@ -245,6 +245,19 @@ endfunc plat_my_core_pos + * --------------------------------------------- + */ + func plat_crash_console_init ++ /* Reset UART peripheral */ ++ ldr r1, =(RCC_BASE + DEBUG_UART_RST_REG) ++ ldr r2, =DEBUG_UART_RST_BIT ++ str r2, [r1] ++1: ++ ldr r0, [r1] ++ ands r0, r2 ++ beq 1b ++ str r2, [r1, #4] /* RSTCLR register */ ++2: ++ ldr r0, [r1] ++ ands r0, r2 ++ bne 2b + /* Enable GPIOs for UART TX */ + ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) + ldr r2, [r1] +-- +2.17.1 + diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-v2.4-stm32mp-r2.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-v2.4-stm32mp-r2.patch new file mode 100644 index 0000000..29fbae7 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-v2.4-stm32mp-r2.patch @@ -0,0 +1,8216 @@ +From 1fe2b03c3d3ef5e550fefe361f69bff86bddf698 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Thu, 28 Oct 2021 15:51:21 +0200 +Subject: [PATCH] v2.4-stm32mp-r2 + +--- + bl32/tsp/aarch64/tsp_entrypoint.S | 22 +- + docs/license.rst | 10 + + drivers/mtd/nand/spi_nand.c | 8 +- + drivers/regulator/regulator_core.c | 1142 +++++++++++++++++ + drivers/st/clk/stm32mp1_clk.c | 29 +- + drivers/st/ddr/stm32mp1_ddr.c | 11 +- + drivers/st/ddr/stm32mp1_ram.c | 169 +-- + drivers/st/ddr/stm32mp_ddr_test.c | 148 +++ + drivers/st/fmc/stm32_fmc2_nand.c | 11 +- + drivers/st/gpio/stm32_gpio.c | 9 +- + drivers/st/mmc/stm32_sdmmc2.c | 16 +- + drivers/st/pmic/stm32mp_pmic.c | 718 +++++------ + drivers/st/pmic/stpmic1.c | 158 ++- + drivers/st/regulator/regulator_fixed.c | 91 ++ + .../st/regulator/stm32mp_dummy_regulator.c | 27 - + drivers/st/regulator/stm32mp_regulator.c | 38 - + drivers/st/tamper/stm32_tamp.c | 691 +++++++--- + drivers/st/uart/aarch32/stm32_console.S | 11 +- + fdts/stm32mp15-ddr-512m-fw-config.dts | 63 - + fdts/stm32mp15-ddr.dtsi | 266 ++-- + fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 6 +- + fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 6 +- + ...-fw-config.dts => stm32mp15-fw-config.dts} | 25 +- + fdts/stm32mp151.dtsi | 18 + + fdts/stm32mp157a-avenger96-fw-config.dts | 3 +- + fdts/stm32mp157a-dk1-fw-config.dts | 3 +- + fdts/stm32mp157a-ed1-fw-config.dts | 3 +- + fdts/stm32mp157a-ev1-fw-config.dts | 3 +- + fdts/stm32mp157c-dk2-fw-config.dts | 3 +- + fdts/stm32mp157c-ed1-fw-config.dts | 3 +- + fdts/stm32mp157c-ev1-fw-config.dts | 3 +- + fdts/stm32mp157d-dk1-fw-config.dts | 3 +- + fdts/stm32mp157d-ed1-fw-config.dts | 3 +- + fdts/stm32mp157d-ev1-fw-config.dts | 3 +- + fdts/stm32mp157f-dk2-fw-config.dts | 3 +- + fdts/stm32mp157f-ed1-fw-config.dts | 3 +- + fdts/stm32mp157f-ev1-fw-config.dts | 3 +- + fdts/stm32mp15xx-dkx.dtsi | 8 +- + fdts/stm32mp15xx-edx.dtsi | 8 +- + include/arch/aarch32/el3_common_macros.S | 13 +- + include/arch/aarch64/el3_common_macros.S | 15 +- + include/drivers/regulator.h | 160 +++ + include/drivers/st/regulator_fixed.h | 12 + + include/drivers/st/stm32_gpio.h | 3 +- + include/drivers/st/stm32_sdmmc2.h | 4 +- + include/drivers/st/stm32_tamp.h | 311 +++-- + include/drivers/st/stm32mp1_ddr_regs.h | 1 + + include/drivers/st/stm32mp1_rcc.h | 2 + + include/drivers/st/stm32mp_ddr_test.h | 15 + + include/drivers/st/stm32mp_dummy_regulator.h | 14 - + include/drivers/st/stm32mp_pmic.h | 46 +- + include/drivers/st/stm32mp_regulator.h | 31 - + include/drivers/st/stpmic1.h | 28 + + .../interrupt-controller/arm-gic.h | 19 +- + .../dt-bindings/interrupt-controller/irq.h | 23 + + lib/aarch32/misc_helpers.S | 4 +- + licenses/LICENSE.MIT | 21 + + plat/st/common/bl2_io_storage.c | 10 +- + plat/st/common/include/stm32cubeprogrammer.h | 3 - + plat/st/common/include/stm32mp_common.h | 15 +- + plat/st/common/include/stm32mp_dt.h | 6 +- + plat/st/common/stm32cubeprogrammer_uart.c | 21 +- + plat/st/common/stm32mp_common.c | 94 +- + plat/st/common/stm32mp_dt.c | 86 +- + plat/st/common/stm32mp_trusted_boot.c | 2 +- + plat/st/stm32mp1/bl2_plat_setup.c | 49 +- + .../stm32mp1/include/stm32mp1_critic_power.h | 8 +- + plat/st/stm32mp1/include/stm32mp1_private.h | 4 +- + plat/st/stm32mp1/plat_bl2_mem_params_desc.c | 61 +- + plat/st/stm32mp1/platform.mk | 23 +- + plat/st/stm32mp1/services/bsec_svc.c | 11 +- + plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk | 1 + + plat/st/stm32mp1/sp_min/sp_min_setup.c | 157 +-- + plat/st/stm32mp1/stm32mp1_context.c | 16 +- + plat/st/stm32mp1/stm32mp1_critic_power.c | 49 +- + .../stm32mp1/stm32mp1_critic_power_wrapper.S | 16 +- + plat/st/stm32mp1/stm32mp1_def.h | 23 +- + plat/st/stm32mp1/stm32mp1_helper.S | 4 +- + plat/st/stm32mp1/stm32mp1_low_power.c | 51 +- + plat/st/stm32mp1/stm32mp1_pm.c | 7 +- + plat/st/stm32mp1/stm32mp1_private.c | 234 ++-- + plat/st/stm32mp1/stm32mp1_ssp.c | 23 +- + plat/st/stm32mp1/stm32mp1_syscfg.c | 130 +- + plat/st/stm32mp1/stm32mp1_usb.c | 4 +- + 84 files changed, 3675 insertions(+), 1903 deletions(-) + create mode 100644 drivers/regulator/regulator_core.c + create mode 100644 drivers/st/ddr/stm32mp_ddr_test.c + create mode 100644 drivers/st/regulator/regulator_fixed.c + delete mode 100644 drivers/st/regulator/stm32mp_dummy_regulator.c + delete mode 100644 drivers/st/regulator/stm32mp_regulator.c + delete mode 100644 fdts/stm32mp15-ddr-512m-fw-config.dts + rename fdts/{stm32mp15-ddr-1g-fw-config.dts => stm32mp15-fw-config.dts} (60%) + create mode 100644 include/drivers/regulator.h + create mode 100644 include/drivers/st/regulator_fixed.h + create mode 100644 include/drivers/st/stm32mp_ddr_test.h + delete mode 100644 include/drivers/st/stm32mp_dummy_regulator.h + delete mode 100644 include/drivers/st/stm32mp_regulator.h + create mode 100644 include/dt-bindings/interrupt-controller/irq.h + create mode 100644 licenses/LICENSE.MIT + +diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S +index a007bab302..a9d03c379e 100644 +--- a/bl32/tsp/aarch64/tsp_entrypoint.S ++++ b/bl32/tsp/aarch64/tsp_entrypoint.S +@@ -100,11 +100,27 @@ func tsp_entrypoint _align=3 + * sections. This is done to safeguard against + * possible corruption of this memory by dirty + * cache lines in a system cache as a result of +- * use by an earlier boot loader stage. ++ * use by an earlier boot loader stage. If PIE ++ * is enabled however, RO sections including the ++ * GOT may be modified during pie fixup. ++ * Therefore, to be on the safe side, invalidate ++ * the entire image region if PIE is enabled. + * --------------------------------------------- + */ +- adr x0, __RW_START__ +- adr x1, __RW_END__ ++#if ENABLE_PIE ++#if SEPARATE_CODE_AND_RODATA ++ adrp x0, __TEXT_START__ ++ add x0, x0, :lo12:__TEXT_START__ ++#else ++ adrp x0, __RO_START__ ++ add x0, x0, :lo12:__RO_START__ ++#endif /* SEPARATE_CODE_AND_RODATA */ ++#else ++ adrp x0, __RW_START__ ++ add x0, x0, :lo12:__RW_START__ ++#endif /* ENABLE_PIE */ ++ adrp x1, __RW_END__ ++ add x1, x1, :lo12:__RW_END__ + sub x1, x1, x0 + bl inv_dcache_range + +diff --git a/docs/license.rst b/docs/license.rst +index 2f9704335f..80f1118609 100644 +--- a/docs/license.rst ++++ b/docs/license.rst +@@ -76,5 +76,15 @@ license text is included in those source files. + BSD-3-Clause license. Any contributions to this code must be made under the + terms of both licenses. + ++- Some source files originating from the Linux source tree, which are ++ disjunctively dual licensed (GPL-2.0 OR MIT), are redistributed under the ++ terms of the MIT license. These files are: ++ ++ - ``include/dt-bindings/interrupt-controller/arm-gic.h`` ++ - ``include/dt-bindings/interrupt-controller/irq.h`` ++ ++ See the original `Linux MIT license`_. ++ + .. _FreeBSD: http://www.freebsd.org ++.. _Linux MIT license: https://raw.githubusercontent.com/torvalds/linux/master/LICENSES/preferred/MIT + .. _SCC: http://www.simple-cc.org/ +diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c +index d01a11963f..18913a57db 100644 +--- a/drivers/mtd/nand/spi_nand.c ++++ b/drivers/mtd/nand/spi_nand.c +@@ -286,6 +286,10 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size) + return -EINVAL; + } + ++ assert((spinand_dev.nand_dev->page_size != 0U) && ++ (spinand_dev.nand_dev->block_size != 0U) && ++ (spinand_dev.nand_dev->size != 0U)); ++ + ret = spi_nand_reset(); + if (ret != 0) { + return ret; +@@ -301,12 +305,12 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size) + return ret; + } + +- ret = spi_nand_quad_enable(id[0]); ++ ret = spi_nand_quad_enable(id[1]); + if (ret != 0) { + return ret; + } + +- VERBOSE("SPI_NAND Detected ID 0x%x 0x%x\n", id[0], id[1]); ++ VERBOSE("SPI_NAND Detected ID 0x%x\n", id[1]); + + VERBOSE("Page size %i, Block size %i, size %lli\n", + spinand_dev.nand_dev->page_size, +diff --git a/drivers/regulator/regulator_core.c b/drivers/regulator/regulator_core.c +new file mode 100644 +index 0000000000..67da7d2920 +--- /dev/null ++++ b/drivers/regulator/regulator_core.c +@@ -0,0 +1,1142 @@ ++/* ++ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#define MAX_PROPERTY_LEN 64 ++ ++static struct rdev rdev_array[PLAT_NB_RDEVS]; ++ ++#pragma weak plat_get_lp_mode_name ++const char *plat_get_lp_mode_name(int mode) ++{ ++ return NULL; ++} ++ ++#define for_each_rdev(rdev) \ ++ for (rdev = rdev_array; rdev < (rdev_array + PLAT_NB_RDEVS); rdev++) ++ ++#define for_each_registered_rdev(rdev) \ ++ for (rdev = rdev_array; \ ++ (rdev < (rdev_array + PLAT_NB_RDEVS)) && (rdev->desc != NULL); rdev++) ++ ++#if defined(IMAGE_BL32) ++static void lock_driver(const struct rdev *rdev) ++{ ++ if (rdev->desc->ops->lock != NULL) { ++ rdev->desc->ops->lock(rdev->desc); ++ } ++} ++ ++static void unlock_driver(const struct rdev *rdev) ++{ ++ if (rdev->desc->ops->unlock != NULL) { ++ rdev->desc->ops->unlock(rdev->desc); ++ } ++} ++#else ++#define lock_driver(desc) {} ++#define unlock_driver(desc) {} ++#endif ++ ++static struct rdev *regulator_get_by_phandle(int32_t phandle) ++{ ++ struct rdev *rdev; ++ ++ for_each_registered_rdev(rdev) { ++ if (rdev->phandle == phandle) { ++ return rdev; ++ } ++ } ++ ++ WARN("%s: phandle %d not found\n", __func__, phandle); ++ return NULL; ++} ++ ++/* ++ * Get a regulator from its node name ++ * ++ * @fdt - pointer to device tree memory ++ * @node_name - name of the node "ldo1" ++ * Return pointer to rdev if succeed, NULL else. ++ */ ++struct rdev *regulator_get_by_name(const char *node_name) ++{ ++ struct rdev *rdev; ++ ++ assert(node_name != NULL); ++ VERBOSE("get %s\n", node_name); ++ ++ for_each_registered_rdev(rdev) { ++ if (strcmp(rdev->desc->node_name, node_name) == 0) { ++ return rdev; ++ } ++ } ++ ++ WARN("%s: %s not found\n", __func__, node_name); ++ return NULL; ++} ++ ++#if defined(IMAGE_BL32) ++/* ++ * Get a regulator from its regulator name property value ++ * ++ * @reg_name - target value of regulator-name property ++ * Return pointer to rdev if succeed, NULL else. ++ */ ++struct rdev *regulator_get_by_regulator_name(const char *reg_name) ++{ ++ struct rdev *rdev; ++ ++ assert(reg_name != NULL); ++ VERBOSE("get %s\n", reg_name); ++ ++ for_each_registered_rdev(rdev) { ++ if ((rdev->reg_name != NULL) && (strcmp(rdev->reg_name, reg_name) == 0)) { ++ return rdev; ++ } ++ } ++ ++ WARN("%s: %s not found\n", __func__, reg_name); ++ return NULL; ++} ++#endif ++ ++static int32_t get_supply_phandle(const void *fdt, int node, const char *name) ++{ ++ const fdt32_t *cuint; ++ int len __unused; ++ int supply_phandle = -FDT_ERR_NOTFOUND; ++ char prop_name[MAX_PROPERTY_LEN]; ++ ++ len = snprintf(prop_name, MAX_PROPERTY_LEN - 1, "%s-supply", name); ++ assert((len >= 0) && (len < MAX_PROPERTY_LEN - 1)); ++ ++ cuint = fdt_getprop(fdt, node, prop_name, NULL); ++ if (cuint != NULL) { ++ supply_phandle = fdt32_to_cpu(*cuint); ++ VERBOSE("%s: supplied by %d\n", name, supply_phandle); ++ } ++ ++ return supply_phandle; ++} ++ ++/* ++ * Get a regulator from a supply name ++ * ++ * @fdt - pointer to device tree memory ++ * @node - offset of the node that contains the supply description ++ * @name - name of the supply "vdd" for "vdd-supply' ++ * Return pointer to rdev if succeed, NULL else. ++ */ ++struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name) ++{ ++ const int p = get_supply_phandle(fdt, node, name); ++ ++ if (p < 0) { ++ return NULL; ++ } ++ ++ return regulator_get_by_phandle(p); ++} ++ ++static int __regulator_set_state(struct rdev *rdev, bool state) ++{ ++ if (rdev->desc->ops->set_state == NULL) { ++ return -ENODEV; ++ } ++ ++ return rdev->desc->ops->set_state(rdev->desc, state); ++} ++ ++#if defined(IMAGE_BL32) ++/* ++ * Enable regulator supply ++ * Enable regulator if use_count == 0 ++ * Apply ramp delay ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++static int __regulator_enable(struct rdev *rdev) ++{ ++ VERBOSE("%s: en\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->set_state == NULL) { ++ return -ENODEV; ++ } ++ ++ if (rdev->supply_dev != NULL) ++ regulator_enable(rdev->supply_dev); ++ ++ lock_driver(rdev); ++ ++ if (rdev->use_count == 0) { ++ int ret; ++ ++ ret = __regulator_set_state(rdev, STATE_ENABLE); ++ if (ret != 0) { ++ ERROR("regul %s set state failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ unlock_driver(rdev); ++ return ret; ++ } ++ ++ udelay(rdev->enable_ramp_delay); ++ } ++ ++ rdev->use_count++; ++ ++ assert(rdev->use_count != UINT8_MAX); ++ ++ VERBOSE("%s: en count:%u\n", rdev->desc->node_name, rdev->use_count); ++ ++ unlock_driver(rdev); ++ ++ return 0; ++} ++ ++/* ++ * Enable regulator ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_enable(struct rdev *rdev) ++{ ++ assert(rdev != NULL); ++ ++ if (rdev->flags & REGUL_ALWAYS_ON) { ++ return 0; ++ } ++ ++ return __regulator_enable(rdev); ++} ++ ++/* ++ * Disable regulator if use_count fall to zero ++ * Warn if count is < 0 because too many disable were requested ++ * Disable regulator supply ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++static int __regulator_disable(struct rdev *rdev) ++{ ++ VERBOSE("%s: dis\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->set_state == NULL) { ++ return -ENODEV; ++ } ++ ++ lock_driver(rdev); ++ ++ if (rdev->use_count == 1) { ++ int ret; ++ ++ ret = __regulator_set_state(rdev, STATE_DISABLE); ++ if (ret != 0) { ++ ERROR("regul %s set state failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ unlock_driver(rdev); ++ return ret; ++ } ++ } ++ ++ if (rdev->use_count == 0) { ++ WARN("regulator %s unbalanced disable\n", rdev->desc->node_name); ++ } else { ++ rdev->use_count--; ++ } ++ ++ VERBOSE("%s: dis count:%u\n", rdev->desc->node_name, rdev->use_count); ++ ++ unlock_driver(rdev); ++ ++ if (rdev->supply_dev != NULL) { ++ regulator_disable(rdev->supply_dev); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Disable regulator ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_disable(struct rdev *rdev) ++{ ++ assert(rdev != NULL); ++ ++ if (rdev->flags & REGUL_ALWAYS_ON) { ++ return 0; ++ } ++ ++ return __regulator_disable(rdev); ++} ++#else ++/* ++ * Enable regulator ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_enable(struct rdev *rdev) ++{ ++ int ret; ++ ++ assert(rdev != NULL); ++ ++ ret = __regulator_set_state(rdev, STATE_ENABLE); ++ ++ udelay(rdev->enable_ramp_delay); ++ ++ return ret; ++} ++ ++/* ++ * Disable regulator ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_disable(struct rdev *rdev) ++{ ++ int ret; ++ ++ assert(rdev != NULL); ++ ++ ret = __regulator_set_state(rdev, STATE_DISABLE); ++ ++ udelay(rdev->enable_ramp_delay); ++ ++ return ret; ++} ++#endif ++ ++/* ++ * Regulator enabled query ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if disabled, 1 if enabled, <0 else. ++ */ ++int regulator_is_enabled(const struct rdev *rdev) ++{ ++ int ret = 0; ++ ++ assert(rdev != NULL); ++ ++ VERBOSE("%s: is en\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->get_state == NULL) { ++ return -ENODEV; ++ } ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->get_state(rdev->desc); ++ if (ret < 0) { ++ ERROR("regul %s get state failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ } ++ ++ unlock_driver(rdev); ++ ++ return ret; ++} ++ ++/* ++ * Set regulator voltage ++ * ++ * @rdev - pointer to rdev struct ++ * @mvolt - Target voltage level in millivolt ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_set_voltage(struct rdev *rdev, uint16_t mvolt) ++{ ++ int ret = 0; ++ ++ assert(rdev != NULL); ++ ++ VERBOSE("%s: set mvolt\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->set_voltage == NULL) { ++ return -ENODEV; ++ } ++ ++ if ((mvolt < rdev->min_mv) || (mvolt > rdev->max_mv)) { ++ return -EPERM; ++ } ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->set_voltage(rdev->desc, mvolt); ++ if (ret < 0) { ++ ERROR("regul %s set volt failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ } ++ ++ unlock_driver(rdev); ++ ++ return ret; ++} ++ ++/* ++ * Set regulator min voltage ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_set_min_voltage(struct rdev *rdev) ++{ ++ return regulator_set_voltage(rdev, rdev->min_mv); ++} ++ ++/* ++ * Get regulator voltage ++ * ++ * @rdev - pointer to rdev struct ++ * Return milli volts if succeed, <0 else. ++ */ ++int regulator_get_voltage(const struct rdev *rdev) ++{ ++ int ret = 0; ++ ++ assert(rdev != NULL); ++ ++ VERBOSE("%s: get volt\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->get_voltage == NULL) { ++ return rdev->min_mv; ++ } ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->get_voltage(rdev->desc); ++ if (ret < 0) { ++ ERROR("regul %s get voltage failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ } ++ ++ unlock_driver(rdev); ++ ++ return ret; ++} ++ ++/* ++ * List regulator voltages ++ * ++ * @rdev - pointer to rdev struct ++ * @levels - out: array of supported millitvolt levels from min to max value ++ * @count - out: number of possible millivolt values ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count) ++{ ++ int ret; ++ size_t n; ++ ++ assert(rdev != NULL); ++ assert(levels != NULL); ++ assert(count != NULL); ++ ++ VERBOSE("%s: list volt\n", rdev->desc->node_name); ++ ++ if (rdev->desc->ops->list_voltages == NULL) { ++ return -ENODEV; ++ } ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->list_voltages(rdev->desc, levels, count); ++ ++ unlock_driver(rdev); ++ ++ if (ret < 0) { ++ ERROR("regul %s list_voltages failed: err: %d\n", ++ rdev->desc->node_name, ret); ++ return ret; ++ } ++ ++ /* ++ * Reduce the possible values depending on min and max from device-tree ++ */ ++ n = *count; ++ while (((*levels)[n - 1U] > rdev->max_mv) && (n > 1U)) { ++ n--; ++ } ++ ++ /* Verify that max val is a valid value */ ++ if (rdev->max_mv != (*levels)[n - 1]) { ++ ERROR("regul %s: max value %u is invalid\n", ++ rdev->desc->node_name, rdev->max_mv); ++ return -EINVAL; ++ } ++ ++ while (((*levels[0U]) < rdev->min_mv) && (n > 1U)) { ++ (*levels)++; ++ n--; ++ } ++ ++ /* Verify that min is not too high */ ++ if (n == 0U) { ++ ERROR("regul %s set min voltage is too high\n", ++ rdev->desc->node_name); ++ return -EINVAL; ++ } ++ ++ /* Verify that min val is a valid vlue */ ++ if (rdev->min_mv != (*levels)[0U]) { ++ ERROR("regul %s: min value %u is invalid\n", ++ rdev->desc->node_name, rdev->min_mv); ++ return -EINVAL; ++ } ++ ++ *count = n; ++ ++ VERBOSE("rdev->min_mv=%u rdev->max_mv=%u\n", rdev->min_mv, rdev->max_mv); ++ ++ return 0; ++} ++ ++/* ++ * Get regulator voltages range ++ * ++ * @rdev - pointer to rdev struct ++ * @min_mv - out: min possible millivolt value ++ * @max_mv - out: max possible millivolt value ++ * Return 0 if succeed, non 0 else. ++ */ ++void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv) ++{ ++ assert(rdev != NULL); ++ ++ if (min_mv != NULL) { ++ *min_mv = rdev->min_mv; ++ } ++ if (max_mv != NULL) { ++ *max_mv = rdev->max_mv; ++ } ++} ++ ++/* ++ * Set regulator flag ++ * ++ * @rdev - pointer to rdev struct ++ * @flag - flag value to set (eg: REGUL_OCP) ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_set_flag(struct rdev *rdev, uint16_t flag) ++{ ++ int ret; ++ ++ /* check that only one bit is set on flag */ ++ if (__builtin_popcount(flag) != 1) { ++ return -EINVAL; ++ } ++ ++ /* REGUL_ALWAYS_ON and REGUL_BOOT_ON are internal properties of the core */ ++ if ((flag == REGUL_ALWAYS_ON) || (flag == REGUL_BOOT_ON)) { ++ rdev->flags |= flag; ++ return 0; ++ } ++ ++ if (rdev->desc->ops->set_flag == NULL) { ++ ERROR("%s can not set any flag\n", rdev->desc->node_name); ++ return -ENODEV; ++ } ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->set_flag(rdev->desc, flag); ++ ++ unlock_driver(rdev); ++ ++ if (ret != 0) { ++ ERROR("%s: could not set flag %d ret=%d\n", ++ rdev->desc->node_name, flag, ret); ++ return ret; ++ } ++ ++ rdev->flags |= flag; ++ ++ return 0; ++} ++ ++#if defined(IMAGE_BL32) ++ ++struct regul_property { ++ char *name; ++ uint16_t flag; ++}; ++ ++static struct regul_property flag_prop[] = { ++ { ++ .name = "regulator-always-on", ++ .flag = REGUL_ALWAYS_ON, ++ }, ++ { ++ .name = "regulator-boot-on", ++ .flag = REGUL_BOOT_ON, ++ }, ++ { ++ .name = "regulator-active-discharge", ++ .flag = REGUL_ACTIVE_DISCHARGE, ++ }, ++ { ++ .name = "regulator-over-current-protection", ++ .flag = REGUL_OCP, ++ }, ++ { ++ .name = "regulator-pull-down", ++ .flag = REGUL_PULL_DOWN, ++ }, ++ { ++ .name = "st,mask-reset", ++ .flag = REGUL_MASK_RESET, ++ }, ++ { ++ .name = "st,regulator-sink-source", ++ .flag = REGUL_SINK_SOURCE, ++ }, ++ { ++ .name = "st,regulator-bypass", ++ .flag = REGUL_ENABLE_BYPASS, ++ }, ++}; ++ ++static int parse_properties(const void *fdt, struct rdev *rdev, int node) ++{ ++ const fdt32_t *cuint; ++ int ret = 0; ++ struct regul_property *prop; ++ ++ for (prop = flag_prop; prop < (flag_prop + ARRAY_SIZE(flag_prop)); prop++) { ++ if (fdt_getprop(fdt, node, prop->name, NULL) != NULL) { ++ VERBOSE("%s: prop 0x%x\n", rdev->desc->node_name, prop->flag); ++ ret = regulator_set_flag(rdev, prop->flag); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, node, "regulator-enable-ramp-delay", NULL); ++ if (cuint != NULL) { ++ rdev->enable_ramp_delay = (uint32_t)(fdt32_to_cpu(*cuint)); ++ VERBOSE("%s: enable_ramp_delay=%u\n", rdev->desc->node_name, ++ rdev->enable_ramp_delay); ++ } ++ ++ rdev->reg_name = fdt_getprop(fdt, node, "regulator-name", NULL); ++ ++ return 0; ++} ++ ++static void parse_supply(const void *fdt, struct rdev *rdev, int node) ++{ ++ const char *name = rdev->desc->supply_name; ++ ++ if (name == NULL) { ++ name = rdev->desc->node_name; ++ } ++ ++ rdev->supply_phandle = get_supply_phandle(fdt, node, name); ++ if (rdev->supply_phandle < 0) { ++ node = fdt_parent_offset(fdt, node); ++ rdev->supply_phandle = get_supply_phandle(fdt, node, name); ++ } ++} ++ ++static void parse_low_power_mode(const void *fdt, struct rdev *rdev, int node, int mode) ++{ ++ const fdt32_t *cuint; ++ ++ rdev->lp_state[mode] = 0; ++ ++ if (fdt_getprop(fdt, node, "regulator-off-in-suspend", NULL) != NULL) { ++ VERBOSE("%s: mode:%d OFF\n", rdev->desc->node_name, mode); ++ rdev->lp_state[mode] |= LP_STATE_OFF; ++ } else if (fdt_getprop(fdt, node, "regulator-on-in-suspend", NULL) != NULL) { ++ VERBOSE("%s: mode:%d ON\n", rdev->desc->node_name, mode); ++ rdev->lp_state[mode] |= LP_STATE_ON; ++ } else { ++ rdev->lp_state[mode] |= LP_STATE_UNCHANGED; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "regulator-suspend-microvolt", NULL); ++ if (cuint != NULL) { ++ uint16_t mv; ++ ++ mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ VERBOSE("%s: mode:%d suspend mv=%u\n", rdev->desc->node_name, ++ mode, mv); ++ ++ rdev->lp_state[mode] |= LP_STATE_SET_VOLT; ++ rdev->lp_mv[mode] = mv; ++ } ++} ++ ++static void parse_low_power_modes(const void *fdt, struct rdev *rdev, int node) ++{ ++ int i; ++ ++ for (i = 0; i < PLAT_NB_SUSPEND_MODES; i++) { ++ const char *lp_mode_name = plat_get_lp_mode_name(i); ++ int n; ++ ++ if (lp_mode_name == NULL) { ++ continue; ++ } ++ ++ /* Get the configs from regulator_state_node subnode */ ++ n = fdt_subnode_offset(fdt, node, lp_mode_name); ++ if (n >= 0) { ++ parse_low_power_mode(fdt, rdev, n, i); ++ } ++ } ++} ++#endif ++ ++/* ++ * Parse the device-tree for a regulator ++ * ++ * Read min/max voltage from dt and check its validity ++ * Read the properties, and call the driver to set flags ++ * Read power supply phandle ++ * Read and store low power mode states ++ * ++ * @rdev - pointer to rdev struct ++ * @node - device-tree node offset of the regulator ++ * Return 0 if disabled, 1 if enabled, <0 else. ++ */ ++static int parse_dt(struct rdev *rdev, int node) ++{ ++ void *fdt; ++ const fdt32_t *cuint; ++ const uint16_t *levels; ++ size_t size; ++ int ret = 0; ++ ++ VERBOSE("%s: parse dt\n", rdev->desc->node_name); ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ rdev->phandle = fdt_get_phandle(fdt, node); ++ ++ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); ++ if (cuint != NULL) { ++ uint16_t min_mv; ++ ++ min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ VERBOSE("%s: min_mv=%d\n", rdev->desc->node_name, (int)min_mv); ++ if (min_mv <= rdev->max_mv) { ++ rdev->min_mv = min_mv; ++ } else { ++ ERROR("%s: min_mv=%d is too high\n", ++ rdev->desc->node_name, (int)min_mv); ++ return -EINVAL; ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); ++ if (cuint != NULL) { ++ uint16_t max_mv; ++ ++ max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ VERBOSE("%s: max_mv=%d\n", rdev->desc->node_name, (int)max_mv); ++ if (max_mv >= rdev->min_mv) { ++ rdev->max_mv = max_mv; ++ } else { ++ ERROR("%s: max_mv=%d is too low\n", ++ rdev->desc->node_name, (int)max_mv); ++ return -EINVAL; ++ } ++ } ++ ++ /* validate that min and max values can be used */ ++ ret = regulator_list_voltages(rdev, &levels, &size); ++ if ((ret != 0) && (ret != -ENODEV)) { ++ return ret; ++ } ++ ++#if defined(IMAGE_BL32) ++ ret = parse_properties(fdt, rdev, node); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ parse_supply(fdt, rdev, node); ++ ++ parse_low_power_modes(fdt, rdev, node); ++#endif ++ ++ return 0; ++} ++ ++/* ++ * Register a regulator driver in regulator framework. ++ * Initialize voltage range from driver description ++ * ++ * @desc - pointer to the regulator description ++ * @node - device-tree node offset of the regulator ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_register(const struct regul_description *desc, int node) ++{ ++ struct rdev *rdev; ++ ++ assert(desc != NULL); ++ ++ VERBOSE("register %s\n", desc->node_name); ++ ++ for_each_rdev(rdev) { ++ if (rdev->desc == NULL) { ++ break; ++ } ++ } ++ ++ if (rdev == rdev_array + PLAT_NB_RDEVS) { ++ WARN("out of memory\n"); ++ return -ENOMEM; ++ } ++ ++ rdev->desc = desc; ++ rdev->enable_ramp_delay = rdev->desc->enable_ramp_delay; ++ ++ if (rdev->desc->ops->list_voltages != NULL) { ++ int ret = 0; ++ const uint16_t *levels; ++ size_t count; ++ ++ lock_driver(rdev); ++ ++ ret = rdev->desc->ops->list_voltages(rdev->desc, &levels, &count); ++ ++ unlock_driver(rdev); ++ ++ if (ret < 0) { ++ ERROR("regul %s set state failed: err:%d\n", ++ rdev->desc->node_name, ret); ++ return ret; ++ } ++ ++ rdev->min_mv = levels[0]; ++ rdev->max_mv = levels[count - 1U]; ++ } else { ++ rdev->max_mv = UINT16_MAX; ++ } ++ ++ return parse_dt(rdev, node); ++} ++ ++#if defined(IMAGE_BL32) ++/* ++ * Suspend a single regulator before low power entry ++ * Call regulator suspend call back, ++ * Enable the regulator if boot_on flag is set as regulator is needed during ++ * boot/resume from suspend sequences. ++ * ++ * @rdev - pointer to rdev struct ++ * @mode - low power mode index ++ * Return 0 if succeed, non 0 else. ++ */ ++static int suspend_regulator(struct rdev *rdev, int mode) ++{ ++ int ret = 0; ++ ++ if (rdev->desc->ops->suspend != NULL) { ++ lock_driver(rdev); ++ ret = rdev->desc->ops->suspend(rdev->desc, ++ rdev->lp_state[mode], ++ rdev->lp_mv[mode]); ++ unlock_driver(rdev); ++ if (ret != 0) { ++ ERROR("%s failed to suspend: %d\n", rdev->desc->node_name, ret); ++ return ret; ++ } ++ } ++ ++ if (rdev->flags & REGUL_BOOT_ON) { ++ ret = regulator_enable(rdev); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Resume a single regulator after low power ++ * ++ * @rdev - pointer to rdev struct ++ * Return 0 if succeed, non 0 else. ++ */ ++static int resume_regulator(struct rdev *rdev) ++{ ++ int ret = 0; ++ ++ if (rdev->flags & REGUL_BOOT_ON) { ++ /* Revert to the state it was before suspend */ ++ ret = regulator_disable(rdev); ++ if (ret != 0) { ++ ERROR("%s failed to resume: %d\n", rdev->desc->node_name, ret); ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * Suspend regulators before entering low power ++ * ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_core_suspend(int mode) ++{ ++ struct rdev *rdev; ++ ++ VERBOSE("Regulator core suspend\n"); ++ ++ if (mode >= PLAT_NB_SUSPEND_MODES) { ++ return -EINVAL; ++ } ++ ++ /* Suspend each regulator */ ++ for_each_registered_rdev(rdev) { ++ if (suspend_regulator(rdev, mode) != 0) { ++ panic(); ++ } ++ } ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ regulator_core_dump(); ++#endif ++ ++ return 0; ++} ++ ++/* ++ * Resume regulators from low power ++ * ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_core_resume(void) ++{ ++ struct rdev *rdev; ++ ++ VERBOSE("Regulator core resume\n"); ++ ++ /* Resume each regulator */ ++ for_each_registered_rdev(rdev) { ++ if (resume_regulator(rdev) != 0) { ++ panic(); ++ } ++ } ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ regulator_core_dump(); ++#endif ++ ++ return 0; ++} ++ ++/* ++ * save regulators data ++ * ++ * @backup_area - pointer to save data ++ * @backup_size - size of the backup area ++ */ ++void regulator_core_backup_context(void *backup_area, size_t backup_size) ++{ ++ int8_t *data = (int8_t *)backup_area; ++ struct rdev *rdev; ++ ++ assert(data != NULL); ++ assert(backup_size == PLAT_BACKUP_REGULATOR_SIZE); ++ ++ for_each_rdev(rdev) { ++ *data = rdev->use_count; ++ data++; ++ } ++} ++ ++/* ++ * restore regulators data ++ * ++ * @backup_area - pointer to retrieve saved data ++ * @backup_size - size of the backup area ++ */ ++void regulator_core_restore_context(void *backup_area, size_t backup_size) ++{ ++ int8_t *data = (int8_t *)backup_area; ++ struct rdev *rdev; ++ ++ assert(data != NULL); ++ assert(backup_size == PLAT_BACKUP_REGULATOR_SIZE); ++ ++ for_each_rdev(rdev) { ++ rdev->use_count = *data; ++ data++; ++ } ++} ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++static void sprint_name(char *dest, const char *src, int len) ++{ ++ int l; ++ ++ if (src == NULL) { ++ src = ""; ++ } ++ ++ l = strlen(src); ++ if (l > len) { ++ l = len; ++ } ++ ++ memset(dest, ' ', len); ++ memcpy(dest, src, l); ++ dest[len] = 0; ++} ++ ++/* ++ * Log regulators state ++ */ ++void regulator_core_dump(void) ++{ ++ struct rdev *rdev; ++ ++ VERBOSE("Dump Regulators\n"); ++ ++ INFO("reg name use\ten\tmV\tmin\tmax\tflags\tsupply\n"); ++ ++ for_each_registered_rdev(rdev) { ++ uint16_t min_mv, max_mv; ++ char reg[9] = ""; ++ char name[9]; ++ const char *supply = ""; ++ ++ sprint_name(name, rdev->desc->node_name, 8); ++ sprint_name(reg, rdev->reg_name, 8); ++ ++ regulator_get_range(rdev, &min_mv, &max_mv); ++ if (rdev->supply_dev != NULL) ++ supply = rdev->supply_dev->desc->node_name; ++ ++ INFO("%s %s %d\t%d\t%d\t%d\t%d\t0x%x\t%s\n", ++ reg, name, ++ rdev->use_count, ++ regulator_is_enabled(rdev), ++ regulator_get_voltage(rdev), min_mv, max_mv, ++ rdev->flags, supply); ++ } ++} ++#endif ++ ++/* ++ * Connect each regulator to its supply ++ * Apply min voltage if the voltage is outside the authorized range ++ * Enable always-on regulators ++ * ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_core_config(void) ++{ ++ int ret; ++ struct rdev *rdev; ++ ++ VERBOSE("Regul Core config\n"); ++ ++ for_each_registered_rdev(rdev) { ++ if (rdev->supply_phandle >= 0) { ++ struct rdev *s; ++ ++ VERBOSE("%s: connect supply\n", rdev->desc->node_name); ++ ++ s = regulator_get_by_phandle(rdev->supply_phandle); ++ if (s == NULL) { ++ return -EINVAL; ++ } ++ ++ rdev->supply_dev = s; ++ } ++ } ++ ++ for_each_registered_rdev(rdev) { ++ uint16_t mv, min_mv, max_mv; ++ ++ regulator_get_range(rdev, &min_mv, &max_mv); ++ ++ ret = regulator_get_voltage(rdev); ++ if (ret >= 0) { ++ mv = ret; ++ if ((mv < min_mv) || (mv > max_mv)) { ++ ret = regulator_set_voltage(rdev, min_mv); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ } else { ++ return ret; ++ } ++ ++ /* ++ * Enable always-on regulator and increment its use_count so that ++ * the regulator is not being disabled during clean-up sequence. ++ */ ++ if (rdev->flags & REGUL_ALWAYS_ON) { ++ ret = __regulator_enable(rdev); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Sync hardware regulator state with use refcount ++ * ++ * Return 0 if succeed, non 0 else. ++ */ ++int regulator_core_cleanup(void) ++{ ++ struct rdev *rdev; ++ ++ VERBOSE("Regul Core cleanup\n"); ++ ++ for_each_registered_rdev(rdev) { ++ if (!(rdev->flags & REGUL_BOOT_ON)) { ++ if ((rdev->use_count == 0) && (regulator_is_enabled(rdev) == 1)) { ++ VERBOSE("disable %s during cleanup\n", rdev->desc->node_name); ++ /* force disable to synchronize the framework */ ++ __regulator_set_state(rdev, STATE_DISABLE); ++ } ++ } ++ } ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ regulator_core_dump(); ++#endif ++ ++ return 0; ++} ++ ++#endif +diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c +index d074a1568c..73c9b147b7 100644 +--- a/drivers/st/clk/stm32mp1_clk.c ++++ b/drivers/st/clk/stm32mp1_clk.c +@@ -71,6 +71,7 @@ enum stm32mp1_parent_id { + _HSI_KER = NB_OSC, + _HSE_KER, + _HSE_KER_DIV2, ++ _HSE_RTC, + _CSI_KER, + _PLL1_P, + _PLL1_Q, +@@ -140,6 +141,7 @@ static const uint8_t parent_id_clock_id[_PARENT_NB] = { + [_HSI_KER] = CK_HSI, + [_HSE_KER] = CK_HSE, + [_HSE_KER_DIV2] = CK_HSE_DIV2, ++ [_HSE_RTC] = _UNKNOWN_ID, + [_CSI_KER] = CK_CSI, + [_PLL1_P] = PLL1_P, + [_PLL1_Q] = PLL1_Q, +@@ -384,21 +386,17 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { + #if defined(IMAGE_BL32) + _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), + #endif +-#if defined(IMAGE_BL2) + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), +-#endif + + #if defined(IMAGE_BL32) + _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), + #endif +-#if defined(IMAGE_BL2) + _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), +-#endif + + _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), + +@@ -543,7 +541,7 @@ static const uint8_t per_parents[] = { + }; + + static const uint8_t rtc_parents[] = { +- _UNKNOWN_ID, _LSE, _LSI, _HSE ++ _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC + }; + + static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { +@@ -639,6 +637,7 @@ static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { + [_HSI_KER] = "HSI_KER", + [_HSE_KER] = "HSE_KER", + [_HSE_KER_DIV2] = "HSE_KER_DIV2", ++ [_HSE_RTC] = "HSE_RTC", + [_CSI_KER] = "CSI_KER", + [_PLL1_P] = "PLL1_P", + [_PLL1_Q] = "PLL1_Q", +@@ -696,6 +695,7 @@ static unsigned int gate_refcounts[NB_GATES]; + static struct spinlock refcount_lock; + static struct stm32mp1_pll_settings pll1_settings; + static uint32_t current_opp_khz; ++static uint32_t save_current_opp_khz; + static uint32_t pll3cr; + static uint32_t pll4cr; + static uint32_t mssckselr; +@@ -1063,6 +1063,10 @@ static unsigned long get_clock_rate(int p) + case _HSE_KER_DIV2: + clock = stm32mp1_clk_get_fixed(_HSE) >> 1; + break; ++ case _HSE_RTC: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; ++ break; + case _LSI: + clock = stm32mp1_clk_get_fixed(_LSI); + break; +@@ -2951,6 +2955,7 @@ static void secure_parent_clocks(unsigned long parent_id) + case _HSE: + case _HSE_KER: + case _HSE_KER_DIV2: ++ case _HSE_RTC: + case _LSE: + break; + +@@ -3238,6 +3243,13 @@ void save_clock_pm_context(void) + stm32mp1_pm_save_clock_cfg(offset, + (uint8_t *)gate_refcounts, + sizeof(gate_refcounts)); ++ offset += sizeof(gate_refcounts); ++ ++ save_current_opp_khz = current_opp_khz; ++ ++ stm32mp1_pm_save_clock_cfg(offset, ++ (uint8_t *)&save_current_opp_khz, ++ sizeof(save_current_opp_khz)); + } + + void restore_clock_pm_context(void) +@@ -3267,6 +3279,13 @@ void restore_clock_pm_context(void) + stm32mp1_pm_restore_clock_cfg(offset, + (uint8_t *)gate_refcounts, + sizeof(gate_refcounts)); ++ offset += sizeof(gate_refcounts); ++ ++ stm32mp1_pm_restore_clock_cfg(offset, ++ (uint8_t *)&save_current_opp_khz, ++ sizeof(save_current_opp_khz)); ++ ++ stm32mp1_set_opp_khz(save_current_opp_khz); + } + + void stm32mp1_clock_suspend(void) +diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c +index 7e8041743e..fb0c7d782f 100644 +--- a/drivers/st/ddr/stm32mp1_ddr.c ++++ b/drivers/st/ddr/stm32mp1_ddr.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -1017,9 +1017,14 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + /* + * 10. configure PUBL PIR register to specify which training + * step to run +- * Warning : RVTRN is not supported by this PUBL ++ * RVTRN is executed only on LPDDR2/LPDDR3 + */ +- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN); ++ pir = DDRPHYC_PIR_QSTRN; ++ if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) == 0U) { ++ pir |= DDRPHYC_PIR_RVTRN; ++ } ++ ++ stm32mp1_ddrphy_init(priv->phy, pir); + + /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training + * sequence +diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c +index 3918eb7be5..d7ee35fec9 100644 +--- a/drivers/st/ddr/stm32mp1_ram.c ++++ b/drivers/st/ddr/stm32mp1_ram.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -14,14 +14,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + +-#define DDR_PATTERN 0xAAAAAAAAU +-#define DDR_ANTIPATTERN 0x55555555U +- + static struct ddr_info ddr_priv_data; + static bool ddr_self_refresh; + +@@ -52,139 +50,6 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) + return 0; + } + +-/******************************************************************************* +- * This function tests a simple read/write access to the DDR. +- * Note that the previous content is restored after test. +- * Returns 0 if success, and address value else. +- ******************************************************************************/ +-static uint32_t ddr_test_rw_access(void) +-{ +- uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); +- +- mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); +- +- if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { +- return (uint32_t)STM32MP_DDR_BASE; +- } +- +- mmio_write_32(STM32MP_DDR_BASE, saved_value); +- +- return 0; +-} +- +-/******************************************************************************* +- * This function tests the DDR data bus wiring. +- * This is inspired from the Data Bus Test algorithm written by Michael Barr +- * in "Programming Embedded Systems in C and C++" book. +- * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ +- * File: memtest.c - This source code belongs to Public Domain. +- * Returns 0 if success, and address value else. +- ******************************************************************************/ +-static uint32_t ddr_test_data_bus(void) +-{ +- uint32_t pattern; +- +- for (pattern = 1U; pattern != 0U; pattern <<= 1) { +- mmio_write_32(STM32MP_DDR_BASE, pattern); +- +- if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { +- return (uint32_t)STM32MP_DDR_BASE; +- } +- } +- +- return 0; +-} +- +-/******************************************************************************* +- * This function tests the DDR address bus wiring. +- * This is inspired from the Data Bus Test algorithm written by Michael Barr +- * in "Programming Embedded Systems in C and C++" book. +- * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ +- * File: memtest.c - This source code belongs to Public Domain. +- * Returns 0 if success, and address value else. +- ******************************************************************************/ +-static uint32_t ddr_test_addr_bus(void) +-{ +- uint64_t addressmask = (ddr_priv_data.info.size - 1U); +- uint64_t offset; +- uint64_t testoffset = 0; +- +- /* Write the default pattern at each of the power-of-two offsets. */ +- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +- offset <<= 1) { +- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, +- DDR_PATTERN); +- } +- +- /* Check for address bits stuck high. */ +- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, +- DDR_ANTIPATTERN); +- +- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +- offset <<= 1) { +- if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != +- DDR_PATTERN) { +- return (uint32_t)(STM32MP_DDR_BASE + offset); +- } +- } +- +- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); +- +- /* Check for address bits stuck low or shorted. */ +- for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; +- testoffset <<= 1) { +- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, +- DDR_ANTIPATTERN); +- +- if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { +- return STM32MP_DDR_BASE; +- } +- +- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; +- offset <<= 1) { +- if ((mmio_read_32(STM32MP_DDR_BASE + +- (uint32_t)offset) != DDR_PATTERN) && +- (offset != testoffset)) { +- return (uint32_t)(STM32MP_DDR_BASE + offset); +- } +- } +- +- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, +- DDR_PATTERN); +- } +- +- return 0; +-} +- +-/******************************************************************************* +- * This function checks the DDR size. It has to be run with Data Cache off. +- * This test is run before data have been put in DDR, and is only done for +- * cold boot. The DDR data can then be overwritten, and it is not useful to +- * restore its content. +- * Returns DDR computed size. +- ******************************************************************************/ +-static uint32_t ddr_check_size(void) +-{ +- uint32_t offset = sizeof(uint32_t); +- +- mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); +- +- while (offset < STM32MP_DDR_MAX_SIZE) { +- mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); +- dsb(); +- +- if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { +- break; +- } +- +- offset <<= 1; +- } +- +- INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); +- +- return offset; +-} +- + static int stm32mp1_ddr_setup(void) + { + struct ddr_info *priv = &ddr_priv_data; +@@ -249,6 +114,17 @@ static int stm32mp1_ddr_setup(void) + INFO("RAM: %s\n", config.info.name); + + for (idx = 0; idx < ARRAY_SIZE(param); idx++) { ++ /* Check present field to avoid warning for optional properties */ ++ if (param[idx].present != NULL) { ++ if (fdt_getprop(fdt, node, param[idx].name, NULL) == NULL) { ++ *(param[idx].present) = false; ++ VERBOSE("%s: %s[0x%x] = absent\n", __func__, ++ param[idx].name, param[idx].size); ++ continue; ++ } ++ /* Save presence of optional parameters */ ++ *(param[idx].present) = true; ++ } + ret = fdt_read_uint32_array(fdt, node, param[idx].name, + param[idx].size, + (void *)((uintptr_t)&config + +@@ -256,20 +132,11 @@ static int stm32mp1_ddr_setup(void) + + VERBOSE("%s: %s[0x%x] = %d\n", __func__, + param[idx].name, param[idx].size, ret); +- if ((ret != 0) && +- ((ret != -FDT_ERR_NOTFOUND) || +- (param[idx].present == NULL))) { ++ if (ret != 0) { + ERROR("%s: Cannot read %s, error=%d\n", + __func__, param[idx].name, ret); + return -EINVAL; + } +- if (param[idx].present != NULL) { +- /* save presence of optional parameters */ +- *(param[idx].present) = true; +- if (ret == -FDT_ERR_NOTFOUND) { +- *(param[idx].present) = false; +- } +- } + } + + config.self_refresh = false; +@@ -297,7 +164,7 @@ static int stm32mp1_ddr_setup(void) + } + + if (config.self_refresh) { +- uret = ddr_test_rw_access(); ++ uret = stm32mp_ddr_test_rw_access(); + if (uret != 0U) { + ERROR("DDR rw test: Can't access memory @ 0x%x\n", + uret); +@@ -307,21 +174,21 @@ static int stm32mp1_ddr_setup(void) + /* Restore area overwritten by training */ + stm32_restore_ddr_training_area(); + } else { +- uret = ddr_test_data_bus(); ++ uret = stm32mp_ddr_test_data_bus(); + if (uret != 0U) { + ERROR("DDR data bus test: can't access memory @ 0x%x\n", + uret); + panic(); + } + +- uret = ddr_test_addr_bus(); ++ uret = stm32mp_ddr_test_addr_bus(config.info.size); + if (uret != 0U) { + ERROR("DDR addr bus test: can't access memory @ 0x%x\n", + uret); + panic(); + } + +- uret = ddr_check_size(); ++ uret = stm32mp_ddr_check_size(); + if (uret < config.info.size) { + ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", + uret, config.info.size); +diff --git a/drivers/st/ddr/stm32mp_ddr_test.c b/drivers/st/ddr/stm32mp_ddr_test.c +new file mode 100644 +index 0000000000..45920b7f80 +--- /dev/null ++++ b/drivers/st/ddr/stm32mp_ddr_test.c +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2021, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++ ++#include ++ ++#include ++ ++#define DDR_PATTERN 0xAAAAAAAAU ++#define DDR_ANTIPATTERN 0x55555555U ++ ++/******************************************************************************* ++ * This function tests a simple read/write access to the DDR. ++ * Note that the previous content is restored after test. ++ * Returns 0 if success, and address value else. ++ ******************************************************************************/ ++uint32_t stm32mp_ddr_test_rw_access(void) ++{ ++ uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); ++ ++ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); ++ ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { ++ return (uint32_t)STM32MP_DDR_BASE; ++ } ++ ++ mmio_write_32(STM32MP_DDR_BASE, saved_value); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function tests the DDR data bus wiring. ++ * This is inspired from the Data Bus Test algorithm written by Michael Barr ++ * in "Programming Embedded Systems in C and C++" book. ++ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ ++ * File: memtest.c - This source code belongs to Public Domain. ++ * Returns 0 if success, and address value else. ++ ******************************************************************************/ ++uint32_t stm32mp_ddr_test_data_bus(void) ++{ ++ uint32_t pattern; ++ ++ for (pattern = 1U; pattern != 0U; pattern <<= 1) { ++ mmio_write_32(STM32MP_DDR_BASE, pattern); ++ ++ if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { ++ return (uint32_t)STM32MP_DDR_BASE; ++ } ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function tests the DDR address bus wiring. ++ * This is inspired from the Data Bus Test algorithm written by Michael Barr ++ * in "Programming Embedded Systems in C and C++" book. ++ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ ++ * File: memtest.c - This source code belongs to Public Domain. ++ * size: size in bytes of the DDR memory device. ++ * Returns 0 if success, and address value else. ++ ******************************************************************************/ ++uint32_t stm32mp_ddr_test_addr_bus(uint64_t size) ++{ ++ uint64_t addressmask = size - 1U; ++ uint64_t offset; ++ uint64_t testoffset = 0; ++ ++ /* Write the default pattern at each of the power-of-two offsets. */ ++ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; ++ offset <<= 1) { ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, ++ DDR_PATTERN); ++ } ++ ++ /* Check for address bits stuck high. */ ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, ++ DDR_ANTIPATTERN); ++ ++ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; ++ offset <<= 1) { ++ if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != ++ DDR_PATTERN) { ++ return (uint32_t)(STM32MP_DDR_BASE + offset); ++ } ++ } ++ ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); ++ ++ /* Check for address bits stuck low or shorted. */ ++ for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; ++ testoffset <<= 1) { ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, ++ DDR_ANTIPATTERN); ++ ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { ++ return STM32MP_DDR_BASE; ++ } ++ ++ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; ++ offset <<= 1) { ++ if ((mmio_read_32(STM32MP_DDR_BASE + ++ (uint32_t)offset) != DDR_PATTERN) && ++ (offset != testoffset)) { ++ return (uint32_t)(STM32MP_DDR_BASE + offset); ++ } ++ } ++ ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, ++ DDR_PATTERN); ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function checks the DDR size. It has to be run with Data Cache off. ++ * This test is run before data have been put in DDR, and is only done for ++ * cold boot. The DDR data can then be overwritten, and it is not useful to ++ * restore its content. ++ * Returns DDR computed size. ++ ******************************************************************************/ ++uint32_t stm32mp_ddr_check_size(void) ++{ ++ uint32_t offset = sizeof(uint32_t); ++ ++ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); ++ ++ while (offset < STM32MP_DDR_MAX_SIZE) { ++ mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); ++ dsb(); ++ ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { ++ break; ++ } ++ ++ offset <<= 1; ++ } ++ ++ INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); ++ ++ return offset; ++} +diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c +index 503e259876..e9ab6dafd8 100644 +--- a/drivers/st/fmc/stm32_fmc2_nand.c ++++ b/drivers/st/fmc/stm32_fmc2_nand.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -201,9 +201,6 @@ static void stm32_fmc2_nand_setup_timing(void) + if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) { + tset_mem = NAND_TCS_MIN - twait; + } +- if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) { +- tset_mem = NAND_TALS_MIN - twait; +- } + if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) && + (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) { + tset_mem = NAND_TDS_MIN - (twait - thiz); +@@ -245,12 +242,6 @@ static void stm32_fmc2_nand_setup_timing(void) + if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) { + tset_att = NAND_TCS_MIN - twait; + } +- if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) { +- tset_att = NAND_TCLS_MIN - twait; +- } +- if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) { +- tset_att = NAND_TALS_MIN - twait; +- } + if ((thold_mem < NAND_TRHW_MIN) && + (tset_att < (NAND_TRHW_MIN - thold_mem))) { + tset_att = NAND_TRHW_MIN - thold_mem; +diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c +index 75707e63a1..5c54762ecc 100644 +--- a/drivers/st/gpio/stm32_gpio.c ++++ b/drivers/st/gpio/stm32_gpio.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -284,3 +284,10 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) + + clk_disable(clock); + } ++ ++void set_gpio_reset_cfg(uint32_t bank, uint32_t pin) ++{ ++ set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_SPEED_LOW, ++ GPIO_NO_PULL, GPIO_ALTERNATE_(0), DT_DISABLED); ++ set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank)); ++} +diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c +index 8c203a4c03..c516bdb3d4 100644 +--- a/drivers/st/mmc/stm32_sdmmc2.c ++++ b/drivers/st/mmc/stm32_sdmmc2.c +@@ -186,9 +186,8 @@ static void stm32_sdmmc2_init(void) + freq = MIN(sdmmc2_params.max_freq, freq); + } + +- if (sdmmc2_params.vmmc_regu.id != -1) { +- stm32mp_regulator_register(&sdmmc2_params.vmmc_regu); +- stm32mp_regulator_disable(&sdmmc2_params.vmmc_regu); ++ if (sdmmc2_params.vmmc_regu != NULL) { ++ regulator_disable(sdmmc2_params.vmmc_regu); + } + + mdelay(VCC_POWER_OFF_DELAY); +@@ -197,8 +196,8 @@ static void stm32_sdmmc2_init(void) + SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol); + mdelay(POWER_CYCLE_DELAY); + +- if (sdmmc2_params.vmmc_regu.id != -1) { +- stm32mp_regulator_enable(&sdmmc2_params.vmmc_regu); ++ if (sdmmc2_params.vmmc_regu != NULL) { ++ regulator_enable(sdmmc2_params.vmmc_regu); + } + + mdelay(VCC_POWER_ON_DELAY); +@@ -758,10 +757,7 @@ static int stm32_sdmmc2_dt_get_config(void) + sdmmc2_params.max_freq = fdt32_to_cpu(*cuint); + } + +- cuint = fdt_getprop(fdt, sdmmc_node, "vmmc-supply", NULL); +- if (cuint != NULL) { +- sdmmc2_params.vmmc_regu.id = fdt32_to_cpu(*cuint); +- } ++ sdmmc2_params.vmmc_regu = regulator_get_by_supply_name(fdt, sdmmc_node, "vmmc"); + + return 0; + } +@@ -783,7 +779,7 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) + + memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params)); + +- sdmmc2_params.vmmc_regu.id = -1; ++ sdmmc2_params.vmmc_regu = NULL; + + if (stm32_sdmmc2_dt_get_config() != 0) { + ERROR("%s: DT error\n", __func__); +diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c +index 4e505debdf..e8cadcda0a 100644 +--- a/drivers/st/pmic/stm32mp_pmic.c ++++ b/drivers/st/pmic/stm32mp_pmic.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,30 +13,21 @@ + + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + +-#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) +-#define STPMIC1_LDO12356_OUTPUT_SHIFT 2 +-#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) +-#define STPMIC1_LDO3_DDR_SEL 31U +- +-#define STPMIC1_BUCK_OUTPUT_SHIFT 2 +-#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT) +- +-#define REGULATOR_MODE_STANDBY 8U +- +-#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 +- +-#define CMD_GET_MIN_VOLTAGE 0U +-#define CMD_CONFIG_BOOT_ON 1U +-#define CMD_CONFIG_LP 2U +- + static struct i2c_handle_s i2c_handle; + static uint32_t pmic_i2c_addr; ++#if defined(IMAGE_BL32) ++static struct spinlock lock; ++#endif ++ ++static int register_pmic(void); + + static int dt_get_pmic_node(void *fdt) + { +@@ -84,235 +75,6 @@ static bool dt_pmic_is_secure(void) + (i2c_handle.dt_status == DT_SECURE); + } + +-static int dt_pmic_get_regulator_voltage(void *fdt, int node, +- uint16_t *min_mv, uint16_t *max_mv) +-{ +- const fdt32_t *cuint; +- +- cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- if (min_mv != NULL) { +- *min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); +- } +- +- cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- if (max_mv != NULL) { +- *max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); +- } +- +- return 0; +-} +- +-static int pmic_config_boot_on(void *fdt, int node, const char *regu_name) +-{ +- uint16_t voltage = 0U; +- uint16_t voltage_min; +- uint16_t voltage_max; +- int status; +- int pmic_voltage; +- +- if ((fdt_getprop(fdt, node, "regulator-boot-on", NULL) == NULL) && +- (fdt_getprop(fdt, node, "regulator-always-on", NULL) == NULL)) { +- return 0; +- } +- +- if (fdt_getprop(fdt, node, "regulator-pull-down", NULL) != NULL) { +- +- status = stpmic1_regulator_pull_down_set(regu_name); +- if (status < 0) { +- return status; +- } +- } +- +- if (fdt_getprop(fdt, node, "st,mask-reset", NULL) != NULL) { +- +- status = stpmic1_regulator_mask_reset_set(regu_name); +- if (status < 0) { +- return status; +- } +- } +- +- if (dt_pmic_get_regulator_voltage(fdt, node, &voltage_min, +- &voltage_max) < 0) { +- return 0; +- } +- +- pmic_voltage = stpmic1_regulator_voltage_get(regu_name); +- if (pmic_voltage < 0) { +- return pmic_voltage; +- } +- +- if ((uint16_t)pmic_voltage < voltage_min) { +- voltage = voltage_min; +- } +- +- if ((uint16_t)pmic_voltage > voltage_max) { +- voltage = voltage_max; +- } +- +- /* Only re-program voltage if not in the range provided in DT. */ +- if (voltage != 0U) { +- status = stpmic1_regulator_voltage_set(regu_name, voltage); +- if (status < 0) { +- return status; +- } +- } +- +- if (!stpmic1_is_regulator_enabled(regu_name)) { +- status = stpmic1_regulator_enable(regu_name); +- if (status < 0) { +- return status; +- } +- } +- +- return 0; +-} +- +-#if defined(IMAGE_BL32) +-static int pmic_config_lp(void *fdt, int node, const char *node_name, +- const char *regu_name) +-{ +- int status; +- const fdt32_t *cuint; +- int regulator_state_node; +- +- status = stpmic1_powerctrl_on(); +- if (status < 0) { +- return status; +- }; +- +- /* +- * First, copy active configuration (Control register) to +- * PWRCTRL Control register, even if regulator_state_node +- * does not exist. +- */ +- status = stpmic1_lp_copy_reg(regu_name); +- if (status < 0) { +- return status; +- } +- +- /* Then apply configs from regulator_state_node */ +- regulator_state_node = fdt_subnode_offset(fdt, node, node_name); +- if (regulator_state_node <= 0) { +- return 0; +- } +- +- if (fdt_getprop(fdt, regulator_state_node, "regulator-on-in-suspend", +- NULL) != NULL) { +- status = stpmic1_lp_reg_on_off(regu_name, 1); +- if (status < 0) { +- return status; +- } +- } +- +- if (fdt_getprop(fdt, regulator_state_node, "regulator-off-in-suspend", +- NULL) != NULL) { +- status = stpmic1_lp_reg_on_off(regu_name, 0); +- if (status < 0) { +- return status; +- } +- } +- +- cuint = fdt_getprop(fdt, regulator_state_node, +- "regulator-suspend-microvolt", NULL); +- if (cuint != NULL) { +- uint16_t voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); +- +- status = stpmic1_lp_set_voltage(regu_name, voltage); +- if (status < 0) { +- return status; +- } +- } +- +- cuint = fdt_getprop(fdt, regulator_state_node, "regulator-mode", NULL); +- if (cuint != NULL) { +- if (fdt32_to_cpu(*cuint) == REGULATOR_MODE_STANDBY) { +- status = stpmic1_lp_set_mode(regu_name, 1); +- if (status < 0) { +- return status; +- } +- } +- } +- +- return 0; +-} +-#endif +- +-static int pmic_operate(uint8_t command, const char *node_name, +- uint16_t *voltage_mv) +-{ +- int pmic_node, regulators_node, subnode; +- void *fdt; +- int ret = -EIO; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- pmic_node = dt_get_pmic_node(fdt); +- if (pmic_node < 0) { +- return -ENOENT; +- } +- +- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); +- if (regulators_node < 0) { +- return -ENOENT; +- } +- +- fdt_for_each_subnode(subnode, fdt, regulators_node) { +- const char *regu_name = fdt_get_name(fdt, subnode, NULL); +- +- switch (command) { +- case CMD_GET_MIN_VOLTAGE: +- assert(node_name != NULL); +- assert(voltage_mv != NULL); +- +- if (strcmp(regu_name, node_name) != 0) { +- continue; +- } +- +- ret = dt_pmic_get_regulator_voltage(fdt, subnode, +- voltage_mv, NULL); +- if (ret < 0) { +- return -ENXIO; +- } +- +- return ret; +- +- case CMD_CONFIG_BOOT_ON: +- ret = pmic_config_boot_on(fdt, subnode, regu_name); +- if (ret < 0) { +- return ret; +- } +- break; +- +-#if defined(IMAGE_BL32) +- case CMD_CONFIG_LP: +- assert(node_name != NULL); +- +- ret = pmic_config_lp(fdt, subnode, node_name, +- regu_name); +- if (ret < 0) { +- return ret; +- } +- break; +-#endif +- +- default: +- return -EINVAL; +- } +- } +- +- return ret; +-} +- + /* + * Get PMIC and its I2C bus configuration from the device tree. + * Return 0 on success, negative on error, 1 if no PMIC node is defined. +@@ -360,66 +122,6 @@ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, + return stm32_i2c_get_setup_from_fdt(i2c_node, init); + } + +-int pmic_configure_boot_on_regulators(void) +-{ +- return pmic_operate(CMD_CONFIG_BOOT_ON, NULL, NULL); +-} +- +-int pmic_set_lp_config(const char *node_name) +-{ +- return pmic_operate(CMD_CONFIG_LP, node_name, NULL); +-} +- +-int dt_pmic_find_supply(const char **supply_name, const char *regu_name) +-{ +- int pmic_node, regulators_node, subnode; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- pmic_node = dt_get_pmic_node(fdt); +- if (pmic_node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); +- if (regulators_node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- fdt_for_each_subnode(subnode, fdt, regulators_node) { +- const char *name; +- +- name = fdt_getprop(fdt, subnode, "regulator-name", NULL); +- if ((name != NULL) && +- (strcmp(name, regu_name) == 0)) { +- *supply_name = fdt_get_name(fdt, subnode, NULL); +- return 0; +- } +- } +- +- return -FDT_ERR_NOTFOUND; +-} +- +-int pmic_set_regulator_min_voltage(const char *regu_name) +-{ +- int rc = -ENOENT; +- const char *supply_name; +- +- if (dt_pmic_find_supply(&supply_name, regu_name) == 0) { +- uint16_t min_mv; +- +- rc = pmic_operate(CMD_GET_MIN_VOLTAGE, supply_name, &min_mv); +- if (rc == 0) { +- rc = stpmic1_regulator_voltage_set(supply_name, min_mv); +- } +- } +- +- return rc; +-} +- + bool initialize_pmic_i2c(void) + { + int ret; +@@ -483,62 +185,6 @@ static void register_pmic_shared_peripherals(void) + } + } + +-static int pmic_regulator_enable(struct stm32mp_regulator *regu) +-{ +- void *fdt; +- const char *node_name; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id), +- NULL); +- +- return stpmic1_regulator_enable(node_name); +-} +- +-static int pmic_regulator_disable(struct stm32mp_regulator *regu) +-{ +- void *fdt; +- const char *node_name; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id), +- NULL); +- +- return stpmic1_regulator_disable(node_name); +-} +- +-static const struct stm32mp_regulator_ops pmic_regu_ops = { +- .enable = pmic_regulator_enable, +- .disable = pmic_regulator_disable, +-}; +- +-bool is_pmic_regulator(struct stm32mp_regulator *regu) +-{ +- void *fdt; +- int parent_node; +- +- if (fdt_get_address(&fdt) == 0) { +- return false; +- } +- +- parent_node = fdt_parent_offset(fdt, +- fdt_node_offset_by_phandle(fdt, +- regu->id)); +- return (fdt_node_check_compatible(fdt, parent_node, +- "st,stpmic1-regulators") == 0); +-} +- +-void bind_pmic_regulator(struct stm32mp_regulator *regu) +-{ +- regu->ops = &pmic_regu_ops; +-} +- + void initialize_pmic(void) + { + if (!initialize_pmic_i2c()) { +@@ -547,13 +193,15 @@ void initialize_pmic(void) + } + + register_pmic_shared_peripherals(); +-} + +-void configure_pmic(void) +-{ +- if (pmic_configure_boot_on_regulators() < 0) { ++ if (register_pmic() < 0) { + panic(); +- }; ++ } ++ ++ if (stpmic1_powerctrl_on() < 0) { ++ panic(); ++ } ++ + } + + #if DEBUG +@@ -567,65 +215,61 @@ void print_pmic_info_and_debug(void) + } + + INFO("PMIC version = 0x%02lx\n", pmic_version); +- stpmic1_dump_regulators(); ++#if defined(IMAGE_BL32) ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ regulator_core_dump(); ++#endif ++#endif + } + #endif + + int pmic_ddr_power_init(enum ddr_type ddr_type) + { +- bool buck3_at_1v8 = false; +- uint8_t read_val; + int status; +- uint16_t buck2_mv; +- uint16_t ldo3_mv; ++ uint16_t buck3_min_mv; ++ struct rdev *buck2, *buck3, *ldo3, *vref; + +- if (pmic_operate(CMD_GET_MIN_VOLTAGE, "buck2", &buck2_mv) != 0) { +- return -EPERM; ++ buck2 = regulator_get_by_name("buck2"); ++ if (buck2 == NULL) { ++ return -ENOENT; + } + +- switch (ddr_type) { +- case STM32MP_DDR3: +- /* Set LDO3 to sync mode */ +- status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } ++ ldo3 = regulator_get_by_name("ldo3"); ++ if (ldo3 == NULL) { ++ return -ENOENT; ++ } + +- read_val &= ~STPMIC1_LDO3_MODE; +- read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; +- read_val |= STPMIC1_LDO3_DDR_SEL << +- STPMIC1_LDO12356_OUTPUT_SHIFT; ++ vref = regulator_get_by_name("vref_ddr"); ++ if (vref == NULL) { ++ return -ENOENT; ++ } + +- status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); ++ switch (ddr_type) { ++ case STM32MP_DDR3: ++ status = regulator_set_flag(ldo3, REGUL_SINK_SOURCE); + if (status != 0) { + return status; + } + +- status = stpmic1_regulator_voltage_set("buck2", buck2_mv); ++ status = regulator_set_min_voltage(buck2); + if (status != 0) { + return status; + } + +- status = stpmic1_regulator_enable("buck2"); ++ status = regulator_enable(buck2); + if (status != 0) { + return status; + } + +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmic1_regulator_enable("vref_ddr"); ++ status = regulator_enable(vref); + if (status != 0) { + return status; + } + +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmic1_regulator_enable("ldo3"); ++ status = regulator_enable(ldo3); + if (status != 0) { + return status; + } +- +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + break; + + case STM32MP_LPDDR2: +@@ -635,70 +279,280 @@ int pmic_ddr_power_init(enum ddr_type ddr_type) + * Set LDO3 to bypass mode if BUCK3 = 1.8V + * Set LDO3 to normal mode if BUCK3 != 1.8V + */ +- status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } +- +- if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) { +- buck3_at_1v8 = true; ++ buck3 = regulator_get_by_name("buck3"); ++ if (buck3 == NULL) { ++ return -ENOENT; + } + +- status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } ++ regulator_get_range(buck3, &buck3_min_mv, NULL); + +- read_val &= ~STPMIC1_LDO3_MODE; +- read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; +- if (buck3_at_1v8) { +- read_val |= STPMIC1_LDO3_MODE; ++ if (buck3_min_mv != 1800) { ++ status = regulator_set_min_voltage(ldo3); ++ if (status != 0) { ++ return status; ++ } ++ } else { ++ status = regulator_set_flag(ldo3, REGUL_ENABLE_BYPASS); ++ if (status != 0) { ++ return status; ++ } + } + +- status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); ++ status = regulator_set_min_voltage(buck2); + if (status != 0) { + return status; + } + +- if (pmic_operate(CMD_GET_MIN_VOLTAGE, "ldo3", &ldo3_mv) != 0) { +- return -EPERM; +- } +- +- status = stpmic1_regulator_voltage_set("ldo3", ldo3_mv); ++ status = regulator_enable(ldo3); + if (status != 0) { + return status; + } + +- status = stpmic1_regulator_voltage_set("buck2", buck2_mv); ++ status = regulator_enable(buck2); + if (status != 0) { + return status; + } + +- status = stpmic1_regulator_enable("ldo3"); ++ status = regulator_enable(vref); + if (status != 0) { + return status; + } ++ break; ++ ++ default: ++ break; ++ }; + +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ return 0; ++} + +- status = stpmic1_regulator_enable("buck2"); +- if (status != 0) { +- return status; ++void pmic_switch_off(void) ++{ ++ stpmic1_switch_off(); ++ udelay(100); ++ ++ /* Shouldn't be reached */ ++ panic(); ++} ++ ++enum { ++ STPMIC1_BUCK1 = 0, ++ STPMIC1_BUCK2, ++ STPMIC1_BUCK3, ++ STPMIC1_BUCK4, ++ STPMIC1_LDO1, ++ STPMIC1_LDO2, ++ STPMIC1_LDO3, ++ STPMIC1_LDO4, ++ STPMIC1_LDO5, ++ STPMIC1_LDO6, ++ STPMIC1_VREF_DDR, ++ STPMIC1_BOOST, ++ STPMIC1_VBUS_OTG, ++ STPMIC1_SW_OUT, ++}; ++ ++static int pmic_set_state(const struct regul_description *desc, bool enable) ++{ ++ VERBOSE("%s: set state to %u\n", desc->node_name, enable); ++ ++ if (enable == STATE_ENABLE) { ++ return stpmic1_regulator_enable(desc->node_name); ++ } else { ++ return stpmic1_regulator_disable(desc->node_name); ++ } ++} ++ ++static int pmic_get_state(const struct regul_description *desc) ++{ ++ VERBOSE("%s: get state\n", desc->node_name); ++ ++ return stpmic1_is_regulator_enabled(desc->node_name); ++} ++ ++static int pmic_get_voltage(const struct regul_description *desc) ++{ ++ VERBOSE("%s: get volt\n", desc->node_name); ++ ++ return stpmic1_regulator_voltage_get(desc->node_name); ++} ++ ++static int pmic_set_voltage(const struct regul_description *desc, uint16_t mv) ++{ ++ VERBOSE("%s: get volt\n", desc->node_name); ++ ++ return stpmic1_regulator_voltage_set(desc->node_name, mv); ++} ++ ++static int pmic_list_voltages(const struct regul_description *desc, ++ const uint16_t **levels, size_t *count) ++{ ++ VERBOSE("%s: list volt\n", desc->node_name); ++ ++ return stpmic1_regulator_levels_mv(desc->node_name, levels, count); ++} ++ ++static int pmic_set_flag(const struct regul_description *desc, uint16_t flag) ++{ ++ VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag); ++ ++ switch (flag) { ++ case REGUL_OCP: ++ return stpmic1_regulator_icc_set(desc->node_name); ++ ++ case REGUL_ACTIVE_DISCHARGE: ++ return stpmic1_active_discharge_mode_set(desc->node_name); ++ ++ case REGUL_PULL_DOWN: ++ return stpmic1_regulator_pull_down_set(desc->node_name); ++ ++ case REGUL_MASK_RESET: ++ return stpmic1_regulator_mask_reset_set(desc->node_name); ++ ++ case REGUL_SINK_SOURCE: ++ return stpmic1_regulator_sink_mode_set(desc->node_name); ++ ++ case REGUL_ENABLE_BYPASS: ++ return stpmic1_regulator_bypass_mode_set(desc->node_name); ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++#if defined(IMAGE_BL32) ++static int driver_suspend(const struct regul_description *desc, uint8_t state, uint16_t mv) ++{ ++ int ret; ++ ++ VERBOSE("%s: suspend state:%d volt:%d\n", desc->node_name, (int)state, mv); ++ ++ ret = stpmic1_lp_copy_reg(desc->node_name); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if ((state & LP_STATE_OFF) != 0U) { ++ ret = stpmic1_lp_reg_on_off(desc->node_name, 0); ++ if (ret != 0) { ++ return ret; + } ++ } + +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ if ((state & LP_STATE_ON) != 0U) { ++ ret = stpmic1_lp_reg_on_off(desc->node_name, 1); ++ if (ret != 0) { ++ return ret; ++ } ++ } + +- status = stpmic1_regulator_enable("vref_ddr"); +- if (status != 0) { +- return status; ++ if ((state & LP_STATE_SET_VOLT) != 0U) { ++ ret = stpmic1_lp_set_voltage(desc->node_name, mv); ++ if (ret != 0) { ++ return ret; + } ++ } + +- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); +- break; ++ return 0; ++} + +- default: +- break; +- }; ++static void driver_lock(const struct regul_description *desc) ++{ ++ if (stm32mp_lock_available()) { ++ spin_lock(&lock); ++ } ++} ++ ++static void driver_unlock(const struct regul_description *desc) ++{ ++ if (stm32mp_lock_available()) { ++ spin_unlock(&lock); ++ } ++} ++#endif ++ ++struct regul_ops pmic_ops = { ++ .set_state = pmic_set_state, ++ .get_state = pmic_get_state, ++ .set_voltage = pmic_set_voltage, ++ .get_voltage = pmic_get_voltage, ++ .list_voltages = pmic_list_voltages, ++ .set_flag = pmic_set_flag, ++#if defined(IMAGE_BL32) ++ .lock = driver_lock, ++ .unlock = driver_unlock, ++ .suspend = driver_suspend, ++#endif ++}; ++ ++#define DEFINE_REGU(name) { \ ++ .node_name = name, \ ++ .ops = &pmic_ops, \ ++ .driver_data = NULL, \ ++ .enable_ramp_delay = 1000, \ ++} ++ ++static const struct regul_description pmic_regs[] = { ++ [STPMIC1_BUCK1] = DEFINE_REGU("buck1"), ++ [STPMIC1_BUCK2] = DEFINE_REGU("buck2"), ++ [STPMIC1_BUCK3] = DEFINE_REGU("buck3"), ++ [STPMIC1_BUCK4] = DEFINE_REGU("buck4"), ++ [STPMIC1_LDO1] = DEFINE_REGU("ldo1"), ++ [STPMIC1_LDO2] = DEFINE_REGU("ldo2"), ++ [STPMIC1_LDO3] = DEFINE_REGU("ldo3"), ++ [STPMIC1_LDO4] = DEFINE_REGU("ldo4"), ++ [STPMIC1_LDO5] = DEFINE_REGU("ldo5"), ++ [STPMIC1_LDO6] = DEFINE_REGU("ldo6"), ++ [STPMIC1_VREF_DDR] = DEFINE_REGU("vref_ddr"), ++ [STPMIC1_BOOST] = DEFINE_REGU("boost"), ++ [STPMIC1_VBUS_OTG] = DEFINE_REGU("pwr_sw1"), ++ [STPMIC1_SW_OUT] = DEFINE_REGU("pwr_sw2"), ++}; ++ ++#define NB_REG ARRAY_SIZE(pmic_regs) ++ ++static int register_pmic(void) ++{ ++ void *fdt; ++ int pmic_node, regulators_node, subnode; ++ ++ VERBOSE("Register pmic\n"); ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ pmic_node = dt_get_pmic_node(fdt); ++ if (pmic_node < 0) { ++ return pmic_node; ++ } ++ ++ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); ++ if (regulators_node < 0) { ++ return -ENOENT; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, regulators_node) { ++ const char *reg_name = fdt_get_name(fdt, subnode, NULL); ++ const struct regul_description *desc; ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < NB_REG; i++) { ++ desc = &pmic_regs[i]; ++ if (strcmp(desc->node_name, reg_name) == 0) { ++ break; ++ } ++ } ++ assert(i < NB_REG); ++ ++ ret = regulator_register(desc, subnode); ++ if (ret != 0) { ++ WARN("%s:%d failed to register %s\n", __func__, ++ __LINE__, reg_name); ++ return ret; ++ } ++ } + + return 0; + } +diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c +index a1db120dc1..c33ef47944 100644 +--- a/drivers/st/pmic/stpmic1.c ++++ b/drivers/st/pmic/stpmic1.c +@@ -17,15 +17,23 @@ struct regul_struct { + const uint16_t *voltage_table; + uint8_t voltage_table_size; + uint8_t control_reg; ++ uint8_t enable_mask; + uint8_t low_power_reg; + uint8_t pull_down_reg; + uint8_t pull_down; + uint8_t mask_reset_reg; + uint8_t mask_reset; ++ uint8_t icc_reg; ++ uint8_t icc_mask; + }; + + static struct i2c_handle_s *pmic_i2c_handle; + static uint16_t pmic_i2c_addr; ++/* ++ * Special mode corresponds to LDO3 in sink source mode or in bypass mode. ++ * LDO3 doesn't switch back from special to normal mode. ++ */ ++static bool ldo3_special_mode; + + /* Voltage tables in mV */ + static const uint16_t buck1_voltage_table[] = { +@@ -346,8 +354,11 @@ static const uint16_t ldo3_voltage_table[] = { + 3300, + 3300, + 3300, +- 500, +- 0xFFFF, /* VREFDDR */ ++}; ++ ++/* Special mode table is used for sink source OR bypass mode */ ++static const uint16_t ldo3_special_mode_table[] = { ++ 0, + }; + + static const uint16_t ldo5_voltage_table[] = { +@@ -431,104 +442,135 @@ static const struct regul_struct regulators_table[] = { + .voltage_table = buck1_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck1_voltage_table), + .control_reg = BUCK1_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = BUCK1_PWRCTRL_REG, + .pull_down_reg = BUCK_PULL_DOWN_REG, + .pull_down = BUCK1_PULL_DOWN_SHIFT, + .mask_reset_reg = MASK_RESET_BUCK_REG, + .mask_reset = BUCK1_MASK_RESET, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = BUCK1_ICC_SHIFT, + }, + { + .dt_node_name = "buck2", + .voltage_table = buck2_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck2_voltage_table), + .control_reg = BUCK2_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = BUCK2_PWRCTRL_REG, + .pull_down_reg = BUCK_PULL_DOWN_REG, + .pull_down = BUCK2_PULL_DOWN_SHIFT, + .mask_reset_reg = MASK_RESET_BUCK_REG, + .mask_reset = BUCK2_MASK_RESET, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = BUCK2_ICC_SHIFT, + }, + { + .dt_node_name = "buck3", + .voltage_table = buck3_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck3_voltage_table), + .control_reg = BUCK3_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = BUCK3_PWRCTRL_REG, + .pull_down_reg = BUCK_PULL_DOWN_REG, + .pull_down = BUCK3_PULL_DOWN_SHIFT, + .mask_reset_reg = MASK_RESET_BUCK_REG, + .mask_reset = BUCK3_MASK_RESET, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = BUCK3_ICC_SHIFT, + }, + { + .dt_node_name = "buck4", + .voltage_table = buck4_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck4_voltage_table), + .control_reg = BUCK4_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = BUCK4_PWRCTRL_REG, + .pull_down_reg = BUCK_PULL_DOWN_REG, + .pull_down = BUCK4_PULL_DOWN_SHIFT, + .mask_reset_reg = MASK_RESET_BUCK_REG, + .mask_reset = BUCK4_MASK_RESET, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = BUCK4_ICC_SHIFT, + }, + { + .dt_node_name = "ldo1", + .voltage_table = ldo1_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), + .control_reg = LDO1_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO1_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO1_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO1_ICC_SHIFT, + }, + { + .dt_node_name = "ldo2", + .voltage_table = ldo2_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), + .control_reg = LDO2_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO2_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO2_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO2_ICC_SHIFT, + }, + { + .dt_node_name = "ldo3", + .voltage_table = ldo3_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), + .control_reg = LDO3_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO3_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO3_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO3_ICC_SHIFT, + }, + { + .dt_node_name = "ldo4", + .voltage_table = ldo4_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), + .control_reg = LDO4_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO4_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO4_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO4_ICC_SHIFT, + }, + { + .dt_node_name = "ldo5", + .voltage_table = ldo5_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), + .control_reg = LDO5_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO5_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO5_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO5_ICC_SHIFT, + }, + { + .dt_node_name = "ldo6", + .voltage_table = ldo6_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), + .control_reg = LDO6_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = LDO6_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = LDO6_MASK_RESET, ++ .icc_reg = LDO_ICC_TURNOFF_REG, ++ .icc_mask = LDO6_ICC_SHIFT, + }, + { + .dt_node_name = "vref_ddr", + .voltage_table = vref_ddr_voltage_table, + .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), + .control_reg = VREF_DDR_CONTROL_REG, ++ .enable_mask = LDO_BUCK_ENABLE_MASK, + .low_power_reg = VREF_DDR_PWRCTRL_REG, + .mask_reset_reg = MASK_RESET_LDO_REG, + .mask_reset = VREF_DDR_MASK_RESET, +@@ -538,21 +580,27 @@ static const struct regul_struct regulators_table[] = { + .voltage_table = fixed_5v_voltage_table, + .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), + .control_reg = USB_CONTROL_REG, +- .mask_reset = BOOST_ENABLED, ++ .enable_mask = BOOST_ENABLED, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = BOOST_ICC_SHIFT, + }, + { + .dt_node_name = "pwr_sw1", + .voltage_table = fixed_5v_voltage_table, + .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), + .control_reg = USB_CONTROL_REG, +- .mask_reset = USBSW_OTG_SWITCH_ENABLED, ++ .enable_mask = USBSW_OTG_SWITCH_ENABLED, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = PWR_SW1_ICC_SHIFT, + }, + { + .dt_node_name = "pwr_sw2", + .voltage_table = fixed_5v_voltage_table, + .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), + .control_reg = USB_CONTROL_REG, +- .mask_reset = SWIN_SWOUT_ENABLED, ++ .enable_mask = SWIN_SWOUT_ENABLED, ++ .icc_reg = BUCK_ICC_TURNOFF_REG, ++ .icc_mask = PWR_SW2_ICC_SHIFT, + }, + }; + +@@ -607,8 +655,8 @@ int stpmic1_regulator_enable(const char *name) + { + const struct regul_struct *regul = get_regulator_data(name); + +- return stpmic1_register_update(regul->control_reg, LDO_BUCK_ENABLE_MASK, +- LDO_BUCK_ENABLE_MASK); ++ return stpmic1_register_update(regul->control_reg, regul->enable_mask, ++ regul->enable_mask); + } + + int stpmic1_regulator_disable(const char *name) +@@ -616,7 +664,7 @@ int stpmic1_regulator_disable(const char *name) + const struct regul_struct *regul = get_regulator_data(name); + + return stpmic1_register_update(regul->control_reg, 0, +- LDO_BUCK_ENABLE_MASK); ++ regul->enable_mask); + } + + bool stpmic1_is_regulator_enabled(const char *name) +@@ -628,7 +676,7 @@ bool stpmic1_is_regulator_enabled(const char *name) + panic(); + } + +- return (val & LDO_BUCK_ENABLE_MASK) == LDO_BUCK_ENABLE_MASK; ++ return (val & regul->enable_mask) == regul->enable_mask; + } + + int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) +@@ -637,6 +685,16 @@ int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) + const struct regul_struct *regul = get_regulator_data(name); + uint8_t mask; + ++ if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { ++ /* ++ * when the LDO3 is in special mode, we do not change voltage, ++ * because by setting voltage, the LDO would leaves sink-source ++ * mode. There is obviously no reason to leave sink-source mode ++ * at runtime. ++ */ ++ return 0; ++ } ++ + /* Voltage can be set for buck or ldo (except ldo4) regulators */ + if (strncmp(name, "buck", 4) == 0) { + mask = BUCK_VOLTAGE_MASK; +@@ -670,12 +728,74 @@ int stpmic1_regulator_mask_reset_set(const char *name) + { + const struct regul_struct *regul = get_regulator_data(name); + ++ if (regul->mask_reset_reg == 0U) { ++ return -EPERM; ++ } ++ + return stpmic1_register_update(regul->mask_reset_reg, + BIT(regul->mask_reset), + LDO_BUCK_RESET_MASK << + regul->mask_reset); + } + ++int stpmic1_regulator_icc_set(const char *name) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ if (regul->mask_reset_reg == 0U) { ++ return -EPERM; ++ } ++ ++ return stpmic1_register_update(regul->icc_reg, ++ BIT(regul->icc_mask), ++ BIT(regul->icc_mask)); ++} ++ ++int stpmic1_regulator_sink_mode_set(const char *name) ++{ ++ if (strncmp(name, "ldo3", 4) != 0) { ++ return -EPERM; ++ } ++ ++ ldo3_special_mode = true; ++ ++ /* disable bypass mode, enable sink mode */ ++ return stpmic1_register_update(LDO3_CONTROL_REG, ++ LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT, ++ LDO3_BYPASS | LDO_VOLTAGE_MASK); ++} ++ ++int stpmic1_regulator_bypass_mode_set(const char *name) ++{ ++ if (strncmp(name, "ldo3", 4) != 0) { ++ return -EPERM; ++ } ++ ++ ldo3_special_mode = true; ++ ++ /* enable bypass mode, disable sink mode */ ++ return stpmic1_register_update(LDO3_CONTROL_REG, ++ LDO3_BYPASS, ++ LDO3_BYPASS | LDO_VOLTAGE_MASK); ++} ++ ++int stpmic1_active_discharge_mode_set(const char *name) ++{ ++ if (strncmp(name, "pwr_sw1", 7) == 0) { ++ return stpmic1_register_update(USB_CONTROL_REG, ++ VBUS_OTG_DISCHARGE, ++ VBUS_OTG_DISCHARGE); ++ } ++ ++ if (strncmp(name, "pwr_sw2", 7) == 0) { ++ return stpmic1_register_update(USB_CONTROL_REG, ++ SW_OUT_DISCHARGE, ++ SW_OUT_DISCHARGE); ++ } ++ ++ return -EPERM; ++} ++ + /* Low-power functions */ + int stpmic1_lp_copy_reg(const char *name) + { +@@ -732,6 +852,22 @@ int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts) + mask); + } + ++int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels, ++ size_t *levels_count) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { ++ *levels_count = ARRAY_SIZE(ldo3_special_mode_table); ++ *levels = ldo3_special_mode_table; ++ } else { ++ *levels_count = regul->voltage_table_size; ++ *levels = regul->voltage_table; ++ } ++ ++ return 0; ++} ++ + int stpmic1_regulator_voltage_get(const char *name) + { + const struct regul_struct *regul = get_regulator_data(name); +@@ -739,6 +875,10 @@ int stpmic1_regulator_voltage_get(const char *name) + uint8_t mask; + int status; + ++ if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { ++ return 0; ++ } ++ + /* Voltage can be set for buck or ldo (except ldo4) regulators */ + if (strncmp(name, "buck", 4) == 0) { + mask = BUCK_VOLTAGE_MASK; +diff --git a/drivers/st/regulator/regulator_fixed.c b/drivers/st/regulator/regulator_fixed.c +new file mode 100644 +index 0000000000..56593717f6 +--- /dev/null ++++ b/drivers/st/regulator/regulator_fixed.c +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2020-2021, STMicroelectronics ++ */ ++ ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#ifndef PLAT_NB_FIXED_REGS ++#error "Missing PLAT_NB_FIXED_REGS" ++#endif ++ ++#define FIXED_NAME_LEN 32U ++ ++struct fixed_data { ++ char name[FIXED_NAME_LEN]; ++ uint16_t volt; ++ struct regul_description desc; ++}; ++ ++static struct fixed_data data[PLAT_NB_FIXED_REGS]; ++ ++static int fixed_set_state(const struct regul_description *desc, bool state) ++{ ++ return 0; ++} ++ ++static int fixed_get_state(const struct regul_description *desc) ++{ ++ return 1; ++} ++ ++static struct regul_ops fixed_ops = { ++ .set_state = fixed_set_state, ++ .get_state = fixed_get_state, ++}; ++ ++int fixed_regulator_register(void) ++{ ++ uint32_t count = 0; ++ void *fdt; ++ int node = 0; ++ ++ VERBOSE("fixed reg init!\n"); ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ do { ++ size_t len __unused; ++ int ret; ++ struct fixed_data *d = &data[count]; ++ const char *reg_name; ++ ++ node = fdt_node_offset_by_compatible(fdt, node, "regulator-fixed"); ++ if (node < 0) { ++ break; ++ } ++ ++ reg_name = fdt_get_name(fdt, node, NULL); ++ ++ VERBOSE("register fixed reg %s!\n", reg_name); ++ ++ len = snprintf(d->name, FIXED_NAME_LEN - 1, "%s", reg_name); ++ assert((len > 0) && (len < (FIXED_NAME_LEN - 1))); ++ ++ d->desc.node_name = d->name; ++ d->desc.driver_data = d; ++ d->desc.ops = &fixed_ops; ++ ++ ret = regulator_register(&d->desc, node); ++ if (ret != 0) { ++ WARN("%s:%d failed to register %s\n", __func__, ++ __LINE__, reg_name); ++ return ret; ++ } ++ ++ count++; ++ assert(count <= PLAT_NB_FIXED_REGS); ++ ++ } while (node > 0); ++ ++ return 0; ++} +diff --git a/drivers/st/regulator/stm32mp_dummy_regulator.c b/drivers/st/regulator/stm32mp_dummy_regulator.c +deleted file mode 100644 +index 1003aba054..0000000000 +--- a/drivers/st/regulator/stm32mp_dummy_regulator.c ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +- +-static int dummy_regulator_enable(struct stm32mp_regulator *regu) +-{ +- return 0; +-} +- +-static int dummy_regulator_disable(struct stm32mp_regulator *regu) +-{ +- return 0; +-} +- +-static const struct stm32mp_regulator_ops dummy_regu_ops = { +- .enable = dummy_regulator_enable, +- .disable = dummy_regulator_disable, +-}; +- +-void bind_dummy_regulator(struct stm32mp_regulator *regu) +-{ +- regu->ops = &dummy_regu_ops; +-} +diff --git a/drivers/st/regulator/stm32mp_regulator.c b/drivers/st/regulator/stm32mp_regulator.c +deleted file mode 100644 +index f0e4a4ae5c..0000000000 +--- a/drivers/st/regulator/stm32mp_regulator.c ++++ /dev/null +@@ -1,38 +0,0 @@ +-/* +- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +- +-#include +- +-#pragma weak plat_bind_regulator +-int plat_bind_regulator(struct stm32mp_regulator *regu) +-{ +- return -1; +-} +- +-int stm32mp_regulator_enable(struct stm32mp_regulator *regu) +-{ +- assert((regu->ops != NULL) && (regu->ops->enable != NULL)); +- +- return regu->ops->enable(regu); +-} +- +-int stm32mp_regulator_disable(struct stm32mp_regulator *regu) +-{ +- assert((regu->ops != NULL) && (regu->ops->disable != NULL)); +- +- if (regu->always_on) { +- return 0; +- } +- +- return regu->ops->disable(regu); +-} +- +-int stm32mp_regulator_register(struct stm32mp_regulator *regu) +-{ +- return plat_bind_regulator(regu); +-} +diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c +index c9a9e9aef8..5a4dde38cd 100644 +--- a/drivers/st/tamper/stm32_tamp.c ++++ b/drivers/st/tamper/stm32_tamp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -11,8 +11,10 @@ + + #include + ++#include + #include + #include ++#include + #include + #include + #include +@@ -20,98 +22,190 @@ + + #define DT_TAMP_COMPAT "st,stm32-tamp" + /* STM32 Registers */ +-#define STM32_TAMP_CR1 0x00U +-#define STM32_TAMP_CR2 0x04U +-#define STM32_TAMP_FLTCR 0x0CU +-#define STM32_TAMP_ATCR 0x10U +-#define STM32_TAMP_ATSEEDR 0x14U +-#define STM32_TAMP_ATOR 0x18U +-#define STM32_TAMP_SMCR 0x20U +-#define STM32_TAMP_IER 0x2CU +-#define STM32_TAMP_SR 0x30U +-#define STM32_TAMP_SCR 0x3CU +-#define STM32_TAMP_COUNTR 0x40U +-#define STM32_TAMP_OR 0x50U +-#define STM32_TAMP_HWCFGR2 0x3ECU +-#define STM32_TAMP_HWCFGR1 0x3F0U +-#define STM32_TAMP_VERR 0x3F4U +-#define STM32_TAMP_IPIDR 0x3F8U +-#define STM32_TAMP_SIDR 0x3FCU +- +-/* STM32_TAMP_FLTCR bit fields */ +-#define STM32_TAMP_FLTCR_TAMPFREQ GENMASK(2, 0) +-#define STM32_TAMP_FLTCR_TAMPFLT GENMASK(4, 3) +-#define STM32_TAMP_FLTCR_TAMPPRCH GENMASK(6, 5) +-#define STM32_TAMP_FLTCR_TAMPPUDIS BIT(7) +- +-/* STM32_TAMP_ATCR bit fields */ +-#define STM32_TAMP_ATCR_ATCKSEL GENMASK(18, 16) +-#define STM32_TAMP_ATCR_ATPER GENMASK(26, 24) +-#define STM32_TAMP_ATCR_ATOSHARE BIT(30) +-#define STM32_TAMP_ATCR_FLTEN BIT(31) +- +-/* STM32_TAMP_ATOR bit fields */ +-#define STM32_TAMP_PRNG GENMASK(7, 0) +-#define STM32_TAMP_SEEDF BIT(14) +-#define STM32_TAMP_INITS BIT(15) +- +-/* STM32_TAMP_IER bit fields */ +-#define STM32_TAMP_IER_TAMPXIE_ALL GENMASK(7, 0) +-#define STM32_TAMP_IER_ITAMPXIE_ALL GENMASK(31, 16) +- +-/* STM32_TAMP_SR bit fields */ +-#define STM32_TAMP_SR_TAMPXF_MASK GENMASK(7, 0) +-#define STM32_TAMP_SR_ITAMPXF_MASK GENMASK(31, 16) +- +-/* STM32_TAMP_SMCR but fields */ +-#define STM32_TAMP_SMCR_DPROT BIT(31) +- +-/* STM32_TAMP_CFGR bit fields */ +-#define STM32_TAMP_OR_OUT3RMP BIT(0) +- +-/* STM32_TAMP_HWCFGR2 bit fields */ +-#define STM32_TAMP_HWCFGR2_TZ GENMASK(11, 8) +-#define STM32_TAMP_HWCFGR2_OR GENMASK(7, 0) +- +-/* STM32_TAMP_HWCFGR1 bit fields */ +-#define STM32_TAMP_HWCFGR1_BKPREG GENMASK(7, 0) +-#define STM32_TAMP_HWCFGR1_TAMPER GENMASK(11, 8) +-#define STM32_TAMP_HWCFGR1_ACTIVE GENMASK(15, 12) +-#define STM32_TAMP_HWCFGR1_INTERN GENMASK(31, 16) +- +-/* STM32_TAMP_VERR bit fields */ +-#define STM32_TAMP_VERR_MINREV GENMASK(3, 0) +-#define STM32_TAMP_VERR_MAJREV GENMASK(7, 4) +- +-#define STM32_TAMP_MAX_INTERNAL 16U +-#define STM32_TAMP_MAX_EXTERNAL 8U ++#define _TAMP_CR1 0x00U ++#define _TAMP_CR2 0x04U ++#define _TAMP_FLTCR 0x0CU ++#define _TAMP_ATCR1 0x10U ++#define _TAMP_ATSEEDR 0x14U ++#define _TAMP_ATOR 0x18U ++#define _TAMP_SMCR 0x20U ++#define _TAMP_IER 0x2CU ++#define _TAMP_SR 0x30U ++#define _TAMP_MISR 0x34U ++#define _TAMP_SMISR 0x38U ++#define _TAMP_SCR 0x3CU ++#define _TAMP_COUNTR 0x40U ++#define _TAMP_OR 0x50U ++#define _TAMP_HWCFGR2 0x3ECU ++#define _TAMP_HWCFGR1 0x3F0U ++#define _TAMP_VERR 0x3F4U ++#define _TAMP_IPIDR 0x3F8U ++#define _TAMP_SIDR 0x3FCU ++ ++/* _TAMP_CR1 bit filds */ ++#define _TAMP_CR1_ITAMP(id) BIT((id) + 16U) ++#define _TAMP_CR1_ETAMP(id) BIT((id)) ++ ++/* _TAMP_CR2 bit filds */ ++#define _TAMP_CR2_ETAMPTRG(id) BIT((id) + 24U) ++#define _TAMP_CR2_ETAMPMSK_MAX_ID 3U ++#define _TAMP_CR2_ETAMPMSK(id) BIT((id) + 16U) ++#define _TAMP_CR2_ETAMPNOER(id) BIT((id)) ++ ++/* _TAMP_FLTCR bit fields */ ++#define _TAMP_FLTCR_TAMPFREQ GENMASK(2, 0) ++#define _TAMP_FLTCR_TAMPFLT GENMASK(4, 3) ++#define _TAMP_FLTCR_TAMPPRCH GENMASK(6, 5) ++#define _TAMP_FLTCR_TAMPPUDIS BIT(7) ++ ++/* _TAMP_ATCR bit fields */ ++#define _TAMP_ATCR1_ATCKSEL GENMASK(18, 16) ++#define _TAMP_ATCR1_ATPER GENMASK(26, 24) ++#define _TAMP_ATCR1_COMMON_MASK GENMASK(31, 16) ++#define _TAMP_ATCR1_ETAMPAM(id) BIT((id)) ++#define _TAMP_ATCR1_ATOSEL_MASK(i) GENMASK(((i) + 1) * 2U + 7U, (i) * 2U + 8U) ++#define _TAMP_ATCR1_ATOSEL(i, o) (((o) - 1U) << ((i) * 2U + 8U)) ++ ++/* _TAMP_ATOR bit fields */ ++#define _TAMP_PRNG GENMASK(7, 0) ++#define _TAMP_SEEDF BIT(14) ++#define _TAMP_INITS BIT(15) ++ ++/* _TAMP_IER bit fields */ ++#define _TAMP_IER_ITAMP(id) BIT((id) + 16U) ++#define _TAMP_IER_ETAMP(id) BIT((id)) ++ ++/* _TAMP_SR bit fields */ ++#define _TAMP_SR_ETAMPXF_MASK GENMASK(7, 0) ++#define _TAMP_SR_ITAMPXF_MASK GENMASK(31, 16) ++#define _TAMP_SR_ITAMP(id) BIT((id) + 16U) ++#define _TAMP_SR_ETAMP(id) BIT((id)) ++ ++/* _TAMP_SCR bit fields */ ++#define _TAMP_SCR_ITAMP(id) BIT((id) + 16U) ++#define _TAMP_SCR_ETAMP(id) BIT((id)) ++ ++/* _TAMP_SMCR bit fields */ ++#define _TAMP_SMCR_BKPRWDPROT_MASK GENMASK(7, 0) ++#define _TAMP_SMCR_BKPRWDPROT_SHIFT U(0) ++#define _TAMP_SMCR_BKPWDPROT_MASK GENMASK(23, 16) ++#define _TAMP_SMCR_BKPWDPROT_SHIFT U(16) ++#define _TAMP_SMCR_DPROT BIT(31) ++ ++/* _TAMP_OR bit fields */ ++#define _TAMP_OR_OUT3RMP_PI8 0U ++#define _TAMP_OR_OUT3RMP_PC13 BIT(0) ++ ++/* _TAMP_HWCFGR2 bit fields */ ++#define _TAMP_HWCFGR2_TZ GENMASK(11, 8) ++#define _TAMP_HWCFGR2_OR GENMASK(7, 0) ++ ++/* _TAMP_HWCFGR1 bit fields */ ++#define _TAMP_HWCFGR1_BKPREG GENMASK(7, 0) ++#define _TAMP_HWCFGR1_TAMPER GENMASK(11, 8) ++#define _TAMP_HWCFGR1_ACTIVE GENMASK(15, 12) ++#define _TAMP_HWCFGR1_INTERN GENMASK(31, 16) ++#define _TAMP_HWCFGR1_ITAMP_MAX_ID 16U ++#define _TAMP_HWCFGR1_ITAMP(id) BIT((id) + 16U) ++ ++/* _TAMP_VERR bit fields */ ++#define _TAMP_VERR_MINREV GENMASK(3, 0) ++#define _TAMP_VERR_MAJREV GENMASK(7, 4) ++ ++#define _TAMP_NB_MONOTONIC_COUNTER 0x1 ++ ++/* ++ * Macro to manage bit manipulation when we work on local variable ++ * before writing only once to the real register ++ */ ++ ++#define CLRBITS(v, bits) (v) &= ~(bits) ++#define SETBITS(v, bits) (v) |= (bits) ++#define CLRSETBITS(v, mask, bits) (v) = ((v) & ~(mask)) | (bits) ++ ++struct stm32_tamp_int { ++ const uint32_t id; ++ uint32_t mode; ++ int (*func)(int id); ++}; ++ ++struct stm32_tamp_ext { ++ const uint32_t id; ++ uint32_t mode; ++ uint8_t out_pin; ++ int (*func)(int id); ++}; + + struct stm32_tamp_instance { + uintptr_t base; + uint32_t clock; + uint32_t hwconf1; + uint32_t hwconf2; +- uint16_t int_nbtamp; +- uint8_t ext_nbtamp; +- struct stm32_tamp_int *int_tamp; +- struct stm32_tamp_ext *ext_tamp; ++ uint32_t secret_list_conf; ++ uint32_t privilege_conf; ++ uint32_t secure_conf; ++ uint32_t passive_conf; ++ uint32_t active_conf; ++ struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT]; ++ struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT]; + }; + +-static struct stm32_tamp_instance stm32_tamp; ++/* 0 is the expected initial values for all fields but .id */ ++static struct stm32_tamp_instance stm32_tamp = { ++ .int_tamp = { ++ { ++ .id = INT_TAMP1, ++ }, ++ { ++ .id = INT_TAMP2, ++ }, ++ { ++ .id = INT_TAMP3, ++ }, ++ { ++ .id = INT_TAMP4, ++ }, ++ { ++ .id = INT_TAMP5, ++ }, ++ { ++ .id = INT_TAMP8, ++ }, ++ }, ++ .ext_tamp = { ++ { ++ .id = EXT_TAMP1, ++ }, ++ { ++ .id = EXT_TAMP2, ++ }, ++ { ++ .id = EXT_TAMP3, ++ }, ++ } ++}; + +-static void stm32_tamp_set_secured(unsigned long base) ++static void stm32_tamp_set_secure(unsigned long base, uint32_t mode) + { +- mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); ++ if (mode & TAMP_REGS_IT_SECURE) { ++ mmio_clrbits_32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); ++ } else { ++ mmio_setbits_32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); ++ } + } + +-static void stm32_tamp_configure_or(unsigned long base, uint32_t out3) ++static void stm32_tamp_set_privilege(unsigned long base __unused, uint32_t mode __unused) + { +- mmio_setbits_32(base + STM32_TAMP_OR, out3); + } + +-static int stm32_tamp_seed_init(unsigned long base) ++static void stm32_tamp_set_output_pin(unsigned long base, uint32_t out) + { +- /* Need RNG access */ ++ mmio_setbits_32(base + _TAMP_OR, out); ++} ++ ++static int stm32_tamp_set_seed(unsigned long base) ++{ ++ /* Need RNG access. */ + uint32_t timeout = 100; + uint8_t idx; + +@@ -123,11 +217,10 @@ static int stm32_tamp_seed_init(unsigned long base) + } + + VERBOSE("Seed init %u\n", rnd); +- mmio_write_32(base + STM32_TAMP_ATSEEDR, rnd); ++ mmio_write_32(base + _TAMP_ATSEEDR, rnd); + } + +- while (((mmio_read_32(base + STM32_TAMP_ATOR) & +- STM32_TAMP_SEEDF) != 0U) && ++ while (((mmio_read_32(base + _TAMP_ATOR) & _TAMP_SEEDF) != 0U) && + (timeout != 0U)) { + timeout--; + } +@@ -139,129 +232,334 @@ static int stm32_tamp_seed_init(unsigned long base) + return 0; + } + +-static void stm32_tamp_reset_register(unsigned long base) ++static bool is_int_tamp_id_valid(uint32_t id) + { +- /* Disable all internal tamper */ +- mmio_write_32(base + STM32_TAMP_CR1, 0U); +- +- /* Disable all external tamper */ +- mmio_write_32(base + STM32_TAMP_CR2, 0U); ++ if (id > _TAMP_HWCFGR1_ITAMP_MAX_ID) { ++ return false; ++ } + +- /* Clean configuration registers */ +- mmio_write_32(base + STM32_TAMP_FLTCR, 0U); +- mmio_write_32(base + STM32_TAMP_ATCR, 0U); +- mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); ++ return (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_ITAMP(id)) ++ == _TAMP_HWCFGR1_ITAMP(id); ++} + +- /* Clean Tamper IT */ +- mmio_write_32(base + STM32_TAMP_IER, 0U); +- mmio_write_32(base + STM32_TAMP_SCR, ~0U); ++static bool is_ext_tamp_id_valid(uint32_t id) ++{ ++ if (id > PLAT_MAX_TAMP_EXT) { ++ return false; ++ } + +- mmio_clrbits_32(base + STM32_TAMP_OR, STM32_TAMP_OR_OUT3RMP); ++ return true; + } + +-void stm32_tamp_write_mcounter(void) ++static int stm32_tamp_set_int_config(struct stm32_tamp_int *tamp_int, ++ uint32_t *cr1, uint32_t *cr3, uint32_t *ier) + { +- mmio_write_32(stm32_tamp.base + STM32_TAMP_COUNTR, 1U); ++ uint32_t id; ++ ++ if (tamp_int == NULL) { ++ return -EINVAL; ++ } ++ ++ id = tamp_int->id; ++ ++ if (!is_int_tamp_id_valid(id)) { ++ return -EINVAL; ++ } ++ ++ /* If etamp is disabled */ ++ if ((tamp_int->mode & TAMP_ENABLE) != TAMP_ENABLE) { ++ CLRBITS(*cr1, _TAMP_CR1_ITAMP(id)); ++ CLRBITS(*ier, _TAMP_IER_ITAMP(id)); ++ return 0; ++ } ++ ++ SETBITS(*cr1, _TAMP_CR1_ITAMP(id)); ++ SETBITS(*ier, _TAMP_IER_ITAMP(id)); ++ ++ return 0; + } + +-void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, +- uint16_t nb_tamper) ++static int stm32_tamp_set_ext_config(struct stm32_tamp_ext *tamp_ext, ++ uint32_t *cr1, uint32_t *cr2, ++ uint32_t *atcr1, uint32_t *atcr2, uint32_t *ier) + { +- uint16_t i; ++ uint32_t id; + +- assert(nb_tamper < STM32_TAMP_MAX_INTERNAL); ++ if (tamp_ext == NULL) { ++ return -EINVAL; ++ } + +- for (i = 0; i < nb_tamper; i++) { +- int id = tamper_list[i].id; +- uint32_t u_id; ++ id = tamp_ext->id; + +- if (id == -1) { +- continue; +- } ++ /* Exit if not a valid TAMP_ID */ ++ if (!is_ext_tamp_id_valid(id)) { ++ return -EINVAL; ++ } ++ ++ /* If etamp is disabled */ ++ if ((tamp_ext->mode & TAMP_ENABLE) != TAMP_ENABLE) { ++ CLRBITS(*cr1, _TAMP_CR1_ETAMP(id)); ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); ++ CLRBITS(*ier, _TAMP_IER_ETAMP(id)); ++ return 0; ++ } ++ ++ SETBITS(*cr1, _TAMP_CR1_ETAMP(id)); ++ ++ if ((tamp_ext->mode & TAMP_TRIG_ON) == TAMP_TRIG_ON) { ++ SETBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); ++ } else { ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); ++ } ++ ++ if ((tamp_ext->mode & TAMP_ACTIVE) == TAMP_ACTIVE) { ++ SETBITS(*cr1, _TAMP_ATCR1_ETAMPAM(id)); ++ } else { ++ CLRBITS(*cr1, _TAMP_ATCR1_ETAMPAM(id)); ++ } ++ ++ if ((tamp_ext->mode & TAMP_NOERASE) == TAMP_NOERASE) { ++ SETBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); ++ } else { ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); ++ } + +- u_id = (uint32_t)id; ++ /* Configure output pin: ++ * For the case out_pin = 0, we select same output pin than the input one. ++ */ ++ if (tamp_ext->out_pin == TAMPOUTSEL_SAME_AS_INPUT) { ++ tamp_ext->out_pin = id + 1; ++ } ++ ++ if (tamp_ext->out_pin < PLAT_MAX_TAMP_EXT + 1U) { ++ CLRSETBITS(*atcr1, _TAMP_ATCR1_ATOSEL_MASK(id), ++ _TAMP_ATCR1_ATOSEL(id, tamp_ext->out_pin)); ++ } + +- if ((stm32_tamp.hwconf1 & BIT(u_id + 16U)) != 0U) { +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, +- BIT(u_id + 16U)); +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, +- BIT(u_id + 16U)); ++ if (id < _TAMP_CR2_ETAMPMSK_MAX_ID) { ++ /* ++ * Only external TAMP 1, 2 and 3 can be masked ++ */ ++ if ((tamp_ext->mode & TAMP_EVT_MASK) == TAMP_EVT_MASK) { ++ /* ++ * ETAMP(id) event generates a trigger event. This ETAMP(id) is masked ++ * and internally cleared by hardware. The backup registers are not erased. ++ */ ++ CLRBITS(*ier, _TAMP_IER_ETAMP(id)); ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); ++ } else { ++ /* ++ * normal ETAMP interrupt: ++ * ETAMP(id) event generates a trigger event and TAMP(id)F must be cleared ++ * by software to * allow next tamper event detection. ++ */ ++ CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); ++ CLRBITS(*ier, _TAMP_IER_ETAMP(id)); + } ++ } else { ++ /* other than 1,2,3 external TAMP, we want its interruption */ ++ CLRBITS(*ier, _TAMP_IER_ETAMP(id)); + } + +- stm32_tamp.int_tamp = tamper_list; +- stm32_tamp.int_nbtamp = nb_tamper; ++ return 0; + } + +-void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, +- uint8_t nb_tamper, uint32_t passive_conf, +- uint32_t active_conf) ++int stm32_tamp_set_secure_bkpregs(struct bkpregs_conf *bkpregs_conf) + { +- /* External configuration */ +- uint8_t i, active_tamp = 0; ++ uint32_t first_z2; ++ uint32_t first_z3; + +- assert(nb_tamper < STM32_TAMP_MAX_EXTERNAL); ++ if (bkpregs_conf == NULL) { ++ return -EINVAL; ++ } + +- /* Enable external Tamp */ +- for (i = 0; i < nb_tamper; i++) { +- int id = ext_tamper_list[i].id; +- uint32_t reg = 0, u_id; ++ first_z2 = bkpregs_conf->nb_zone1_regs; ++ first_z3 = bkpregs_conf->nb_zone1_regs + bkpregs_conf->nb_zone2_regs; + +- if (id == -1) { +- continue; +- } ++ if ((first_z2 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG)) || ++ (first_z3 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG))) { ++ return -ENODEV; ++ } ++ ++ mmio_clrsetbits_32(stm32_tamp.base + _TAMP_SMCR, ++ _TAMP_SMCR_BKPRWDPROT_MASK, ++ (first_z2 << _TAMP_SMCR_BKPRWDPROT_SHIFT) & ++ _TAMP_SMCR_BKPRWDPROT_MASK); + +- u_id = (uint32_t)id; ++ mmio_clrsetbits_32(stm32_tamp.base + _TAMP_SMCR, ++ _TAMP_SMCR_BKPWDPROT_MASK, ++ (first_z3 << _TAMP_SMCR_BKPWDPROT_SHIFT) & ++ _TAMP_SMCR_BKPWDPROT_MASK); ++ return 0; ++} ++ ++int stm32_tamp_set_config(void) ++{ ++ int ret; ++ uint32_t i; ++ uint32_t cr1 = 0, cr2 = 0, cr3 = 0; ++ uint32_t atcr1 = 0, atcr2 = 0; ++ uint32_t fltcr = 0; ++ uint32_t ier = 0; ++ ++ /* Select access in secure or unsecure */ ++ stm32_tamp_set_secure(stm32_tamp.base, stm32_tamp.secure_conf); ++ ++ /* Select acces in privileged mode or unprivileged mode */ ++ stm32_tamp_set_privilege(stm32_tamp.base, stm32_tamp.privilege_conf); ++ ++ if (stm32_tamp.passive_conf != 0U) { ++ /* Filter mode register set */ ++ fltcr = stm32_tamp.passive_conf; ++ } + +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, +- BIT(u_id)); ++ if (stm32_tamp.active_conf != 0U) { ++ /* Active mode configuration */ ++ CLRSETBITS(atcr1, _TAMP_ATCR1_COMMON_MASK, ++ (stm32_tamp.active_conf & _TAMP_ATCR1_COMMON_MASK)); ++ } + +- if (ext_tamper_list[i].mode == TAMP_TRIG_ON) { +- reg |= BIT(u_id + 24U); ++ for (i = 0U; i < PLAT_MAX_TAMP_INT; i++) { ++ ret = stm32_tamp_set_int_config(&(stm32_tamp.int_tamp[i]), ++ &cr1, &cr3, &ier); ++ if (ret != 0) { ++ return ret; + } ++ } + +- if (ext_tamper_list[i].mode == TAMP_ACTIVE) { +- active_tamp |= BIT(u_id); ++ for (i = 0U; i < PLAT_MAX_TAMP_EXT; i++) { ++ ret = stm32_tamp_set_ext_config(&(stm32_tamp.ext_tamp[i]), ++ &cr1, &cr2, &atcr1, &atcr2, &ier); ++ if (ret != 0) { ++ return ret; + } ++ } ++ ++ /* ++ * We apply configuration all in a row: ++ * As for active ext tamper "all the needed tampers must be enabled in the same write ++ * access". ++ */ ++ mmio_write_32(stm32_tamp.base + _TAMP_FLTCR, fltcr); ++ /* Active filter configuration applied only if not already done. */ ++ if (((mmio_read_32(stm32_tamp.base + _TAMP_ATOR) & _TAMP_INITS) != _TAMP_INITS)) { ++ mmio_write_32(stm32_tamp.base + _TAMP_ATCR1, atcr1); ++ } + +- if (ext_tamper_list[i].erase != 0U) { +- reg |= BIT(u_id); ++ mmio_write_32(stm32_tamp.base + _TAMP_CR1, cr1); ++ mmio_write_32(stm32_tamp.base + _TAMP_CR2, cr2); ++ /* If active tamper we reinit the seed. */ ++ if (stm32_tamp.active_conf != 0U) { ++ if (stm32_tamp_set_seed(stm32_tamp.base) != 0) { ++ ERROR("Active tamper: SEED not initialized\n"); ++ return -EPERM; + } ++ } + +- if (ext_tamper_list[i].evt_mask != 0U) { +- reg |= BIT(u_id + 16U); +- } else { +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, +- BIT(u_id)); ++ /* Ack all pending interrupt */ ++ mmio_write_32(stm32_tamp.base + _TAMP_SCR, ~0U); ++ /* Enable interrupts. */ ++ mmio_write_32(stm32_tamp.base + _TAMP_IER, ier); ++ ++ return 0; ++} ++ ++int stm32_tamp_write_mcounter(int counter_idx) ++{ ++ mmio_write_32(stm32_tamp.base + _TAMP_COUNTR, 1U); ++ ++ return 0; ++} ++ ++uint32_t stm32_tamp_read_mcounter(int counter_idx) ++{ ++ return mmio_read_32(stm32_tamp.base + _TAMP_COUNTR); ++} ++ ++void stm32_tamp_configure_secret_list(uint32_t secret_list_conf) ++{ ++ stm32_tamp.secret_list_conf = secret_list_conf; ++} ++ ++void stm32_tamp_configure_privilege_access(uint32_t privilege_conf) ++{ ++ stm32_tamp.privilege_conf = privilege_conf; ++} ++ ++void stm32_tamp_configure_secure_access(uint32_t secure_conf) ++{ ++ stm32_tamp.secure_conf = secure_conf; ++} ++ ++void stm32_tamp_configure_passive(uint32_t passive_conf) ++{ ++ stm32_tamp.passive_conf = passive_conf; ++} ++ ++void stm32_tamp_configure_active(uint32_t active_conf) ++{ ++ stm32_tamp.active_conf = active_conf; ++} ++ ++int stm32_tamp_configure_internal(enum stm32_tamp_int_id id, uint32_t mode, int (*callback)(int id)) ++{ ++ uint32_t i; ++ uint32_t itamp_id = id; ++ struct stm32_tamp_int *tamp_int = NULL; ++ ++ /* Find internal Tamp struct*/ ++ for (i = 0U; i < PLAT_MAX_TAMP_INT; i++) { ++ if (stm32_tamp.int_tamp[i].id == itamp_id) { ++ tamp_int = &(stm32_tamp.int_tamp[i]); ++ break; + } ++ } + +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR2, reg); ++ if (tamp_int == NULL) { ++ return -EINVAL; + } + +- /* Filter mode register set */ +- mmio_write_32(stm32_tamp.base + STM32_TAMP_FLTCR, passive_conf); ++ tamp_int->mode = mode; ++ tamp_int->func = callback; + +- /* Active mode configuration */ +- if (active_tamp != 0U) { +- mmio_write_32(stm32_tamp.base + STM32_TAMP_ATCR, +- active_conf | active_tamp); +- if (stm32_tamp_seed_init(stm32_tamp.base) != 0) { +- ERROR("Active tamper: SEED not initialized\n"); +- panic(); ++ return 0; ++} ++ ++int stm32_tamp_configure_external(enum stm32_tamp_ext_id id, uint32_t mode, ++ enum stm32_tamp_ext_out_id out_pin, int (*callback)(int id)) ++{ ++ uint32_t i; ++ uint32_t etamp_id = id; ++ struct stm32_tamp_ext *tamp_ext = NULL; ++ ++ /* Find external Tamp struct */ ++ for (i = 0U; i < PLAT_MAX_TAMP_EXT; i++) { ++ if (stm32_tamp.ext_tamp[i].id == etamp_id) { ++ tamp_ext = &(stm32_tamp.ext_tamp[i]); ++ break; + } + } + +- stm32_tamp.ext_tamp = ext_tamper_list; +- stm32_tamp.ext_nbtamp = nb_tamper; ++ if (tamp_ext == NULL) { ++ return -EINVAL; ++ } ++ ++ tamp_ext->mode = mode; ++ tamp_ext->out_pin = out_pin; ++ tamp_ext->func = callback; ++ ++ return 0; + } + + void stm32_tamp_it_handler(void) + { +- uint32_t it = mmio_read_32(stm32_tamp.base + STM32_TAMP_SR); ++ uint32_t it = mmio_read_32(stm32_tamp.base + _TAMP_SR); ++ uint32_t int_it = it & _TAMP_SR_ITAMPXF_MASK; ++ uint32_t ext_it = it & _TAMP_SR_ETAMPXF_MASK; + uint8_t tamp = 0; + struct stm32_rtc_time tamp_ts; +- struct stm32_tamp_int *int_list = stm32_tamp.int_tamp; +- struct stm32_tamp_ext *ext_list = stm32_tamp.ext_tamp; + + if (stm32_rtc_is_timestamp_enable()) { + stm32_rtc_get_timestamp(&tamp_ts); +@@ -271,45 +569,53 @@ void stm32_tamp_it_handler(void) + tamp_ts.min, tamp_ts.sec); + } + +- /* Internal tamper interrupt */ +- if ((it & STM32_TAMP_IER_ITAMPXIE_ALL) == 0U) { +- goto tamp_ext; +- } ++ while ((int_it != 0U) && (tamp < PLAT_MAX_TAMP_INT)) { ++ int ret = -1; ++ uint32_t int_id = stm32_tamp.int_tamp[tamp].id; + +- while ((it != 0U) && (tamp < stm32_tamp.int_nbtamp)) { +- uint32_t int_id = (uint32_t)int_list[tamp].id; ++ if ((it & _TAMP_SR_ITAMP(int_id)) != 0U) { ++ if (stm32_tamp.int_tamp[tamp].func != NULL) { ++ ret = stm32_tamp.int_tamp[tamp].func(int_id); ++ } ++ ++ if (ret >= 0) { ++ mmio_setbits_32(stm32_tamp.base + _TAMP_SCR, ++ _TAMP_SR_ITAMP(int_id)); ++ ext_it &= ~_TAMP_SR_ITAMP(int_id); + +- if ((it & BIT(int_id + 16U)) != 0U) { +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, BIT(int_id + 16U)); +- it &= ~BIT(int_id + 16U); +- if (int_list[tamp].func != NULL) { +- int_list[tamp].func(int_id); ++ if (ret > 0) { ++ stm32mp_system_reset(); ++ } + } + } + tamp++; + } + +-tamp_ext: + tamp = 0; + /* External tamper interrupt */ +- if ((it == 0U) || ((it & STM32_TAMP_IER_TAMPXIE_ALL) == 0U)) { +- return; +- } ++ while ((ext_it != 0U) && (tamp < PLAT_MAX_TAMP_EXT)) { ++ int ret = -1; ++ uint32_t ext_id = stm32_tamp.ext_tamp[tamp].id; + +- while ((it != 0U) && (tamp < stm32_tamp.ext_nbtamp)) { +- uint32_t ext_id = (uint32_t)ext_list[tamp].id; +- +- if ((it & BIT(ext_id)) != 0U) { +- if (ext_list[tamp].func != NULL) { +- ext_list[tamp].func(ext_id); ++ if ((ext_it & _TAMP_SR_ETAMP(ext_id)) != 0U) { ++ if (stm32_tamp.ext_tamp[tamp].func != NULL) { ++ ret = stm32_tamp.ext_tamp[tamp].func(ext_id); + } + +- mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, +- BIT(ext_id)); +- it &= ~BIT(ext_id); ++ if (ret >= 0) { ++ mmio_setbits_32(stm32_tamp.base + _TAMP_SCR, ++ _TAMP_SCR_ETAMP(ext_id)); ++ ext_it &= ~_TAMP_SR_ETAMP(ext_id); ++ ++ if (ret > 0) { ++ stm32mp_system_reset(); ++ } ++ } + } + tamp++; + } ++ ++ gicv2_end_of_interrupt(STM32MP1_IRQ_TAMPSERRS); + } + + int stm32_tamp_init(void) +@@ -325,7 +631,7 @@ int stm32_tamp_init(void) + + node = dt_get_node(&dt_tamp, -1, DT_TAMP_COMPAT); + if (node < 0) { +- return -FDT_ERR_NOTFOUND; ++ return -EINVAL; + } + + assert(dt_tamp.base != 0U); +@@ -337,37 +643,34 @@ int stm32_tamp_init(void) + /* Init Tamp clock */ + clk_enable(stm32_tamp.clock); + +- /* Reset Tamp register without modifying backup registers conf */ +- stm32_tamp_reset_register(stm32_tamp.base); +- + /* Check if TAMP is enabled */ + if ((dt_tamp.status != DT_SECURE) && + (dt_tamp.status != DT_SHARED)) { + return 0; + } + +- stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR1); +- stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR2); ++ stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + _TAMP_HWCFGR1); ++ stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + _TAMP_HWCFGR2); + +- rev = mmio_read_32(stm32_tamp.base + STM32_TAMP_VERR); +- VERBOSE("STM32 TAMPER V%u.%u\n", (rev & STM32_TAMP_VERR_MAJREV) >> 4, +- rev & STM32_TAMP_VERR_MINREV); ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ rev = mmio_read_32(stm32_tamp.base + _TAMP_VERR); ++ VERBOSE("STM32 TAMPER V%u.%u\n", (rev & _TAMP_VERR_MAJREV) >> 4, ++ rev & _TAMP_VERR_MINREV); ++#endif + +- if ((stm32_tamp.hwconf2 & STM32_TAMP_HWCFGR2_TZ) == 0U) { ++ if ((stm32_tamp.hwconf2 & _TAMP_HWCFGR2_TZ) == 0U) { + ERROR("Tamper IP doesn't support trustzone"); + return -EPERM; + } + +- stm32_tamp_set_secured(stm32_tamp.base); +- + if (dt_set_pinctrl_config(node) != -FDT_ERR_NOTFOUND) { + if (fdt_getprop(fdt, node, "st,out3-pc13", NULL) != NULL) { +- stm32_tamp_configure_or(stm32_tamp.base, 1); ++ stm32_tamp_set_output_pin(stm32_tamp.base, _TAMP_OR_OUT3RMP_PC13); + } + } + + if (stm32_gic_enable_spi(node, NULL) < 0) { +- panic(); ++ return -EPERM; + } + + if (fdt_getprop(fdt, node, "wakeup-source", NULL) != NULL) { +diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S +index 2cb04a88fc..5872157323 100644 +--- a/drivers/st/uart/aarch32/stm32_console.S ++++ b/drivers/st/uart/aarch32/stm32_console.S +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -45,7 +45,12 @@ func console_stm32_core_init + /* Check the input base address */ + cmp r0, #0 + beq core_init_fail +-#if defined(IMAGE_BL2) ++#if !defined(IMAGE_BL2) ++ /* Skip UART initialization if it is already enabled */ ++ ldr r3, [r0, #USART_CR1] ++ ands r3, r3, #USART_CR1_UE ++ bne 1f ++#endif /* IMAGE_BL2 */ + /* Check baud rate and uart clock for sanity */ + cmp r1, #0 + beq core_init_fail +@@ -78,7 +83,7 @@ teack_loop: + ldr r3, [r0, #USART_ISR] + tst r3, #USART_ISR_TEACK + beq teack_loop +-#endif /* IMAGE_BL2 */ ++1: + mov r0, #1 + bx lr + core_init_fail: +diff --git a/fdts/stm32mp15-ddr-512m-fw-config.dts b/fdts/stm32mp15-ddr-512m-fw-config.dts +deleted file mode 100644 +index 3d0722181a..0000000000 +--- a/fdts/stm32mp15-ddr-512m-fw-config.dts ++++ /dev/null +@@ -1,63 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (c) 2020, STMicroelectronics - All Rights Reserved +- */ +- +-#include +- +-#include +-#include +- +-/dts-v1/; +- +-/ { +- dtb-registry { +- compatible = "fconf,dyn_cfg-dtb_registry"; +- +- hw-config { +- load-address = <0x0 STM32MP_HW_CONFIG_BASE>; +- max-size = ; +- id = ; +- }; +- +- nt_fw { +- load-address = <0x0 STM32MP_BL33_BASE>; +- max-size = ; +- id = ; +- }; +- +-#ifdef AARCH32_SP_OPTEE +- tos_fw { +- load-address = <0x0 0x2FFC0000>; +- max-size = <0x0001F000>; +- id = ; +- }; +-#else +- tos_fw { +- load-address = <0x0 STM32MP_BL32_BASE>; +- max-size = ; +- id = ; +- }; +- +- tos_fw-config { +- load-address = <0x0 STM32MP_BL32_DTB_BASE>; +- max-size = ; +- id = ; +- }; +-#endif +- }; +- +- st-mem-firewall { +- compatible = "st,mem-firewall"; +-#ifdef AARCH32_SP_OPTEE +- memory-ranges = < +- 0xc0000000 0x1e000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR +- 0xde000000 0x01e00000 TZC_REGION_S_RDWR 0 +- 0xdfe00000 0x00200000 TZC_REGION_S_NONE +- TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID)>; +-#else +- memory-ranges = < +- 0xc0000000 0x20000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; +-#endif +- }; +-}; +diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi +index 734943c0ea..43424a0079 100644 +--- a/fdts/stm32mp15-ddr.dtsi ++++ b/fdts/stm32mp15-ddr.dtsi +@@ -1,165 +1,129 @@ + // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + /* +- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved + */ + +-/ { +- soc { +- ddr: ddr@5a003000{ ++&ddr { ++ st,mem-name = DDR_MEM_NAME; ++ st,mem-speed = ; ++ st,mem-size = ; + +- compatible = "st,stm32mp1-ddr"; ++ st,ctl-reg = < ++ DDR_MSTR ++ DDR_MRCTRL0 ++ DDR_MRCTRL1 ++ DDR_DERATEEN ++ DDR_DERATEINT ++ DDR_PWRCTL ++ DDR_PWRTMG ++ DDR_HWLPCTL ++ DDR_RFSHCTL0 ++ DDR_RFSHCTL3 ++ DDR_CRCPARCTL0 ++ DDR_ZQCTL0 ++ DDR_DFITMG0 ++ DDR_DFITMG1 ++ DDR_DFILPCFG0 ++ DDR_DFIUPD0 ++ DDR_DFIUPD1 ++ DDR_DFIUPD2 ++ DDR_DFIPHYMSTR ++ DDR_ODTMAP ++ DDR_DBG0 ++ DDR_DBG1 ++ DDR_DBGCMD ++ DDR_POISONCFG ++ DDR_PCCFG ++ >; + +- reg = <0x5A003000 0x550 +- 0x5A004000 0x234>; ++ st,ctl-timing = < ++ DDR_RFSHTMG ++ DDR_DRAMTMG0 ++ DDR_DRAMTMG1 ++ DDR_DRAMTMG2 ++ DDR_DRAMTMG3 ++ DDR_DRAMTMG4 ++ DDR_DRAMTMG5 ++ DDR_DRAMTMG6 ++ DDR_DRAMTMG7 ++ DDR_DRAMTMG8 ++ DDR_DRAMTMG14 ++ DDR_ODTCFG ++ >; + +- clocks = <&rcc AXIDCG>, +- <&rcc DDRC1>, +-#if STM32MP_DDR_DUAL_AXI_PORT +- <&rcc DDRC2>, +-#endif +- <&rcc DDRPHYC>, +- <&rcc DDRCAPB>, +- <&rcc DDRPHYCAPB>; +- +- clock-names = "axidcg", +- "ddrc1", +-#if STM32MP_DDR_DUAL_AXI_PORT +- "ddrc2", +-#endif +- "ddrphyc", +- "ddrcapb", +- "ddrphycapb"; ++ st,ctl-map = < ++ DDR_ADDRMAP1 ++ DDR_ADDRMAP2 ++ DDR_ADDRMAP3 ++ DDR_ADDRMAP4 ++ DDR_ADDRMAP5 ++ DDR_ADDRMAP6 ++ DDR_ADDRMAP9 ++ DDR_ADDRMAP10 ++ DDR_ADDRMAP11 ++ >; + +- st,mem-name = DDR_MEM_NAME; +- st,mem-speed = ; +- st,mem-size = ; ++ st,ctl-perf = < ++ DDR_SCHED ++ DDR_SCHED1 ++ DDR_PERFHPR1 ++ DDR_PERFLPR1 ++ DDR_PERFWR1 ++ DDR_PCFGR_0 ++ DDR_PCFGW_0 ++ DDR_PCFGQOS0_0 ++ DDR_PCFGQOS1_0 ++ DDR_PCFGWQOS0_0 ++ DDR_PCFGWQOS1_0 ++ DDR_PCFGR_1 ++ DDR_PCFGW_1 ++ DDR_PCFGQOS0_1 ++ DDR_PCFGQOS1_1 ++ DDR_PCFGWQOS0_1 ++ DDR_PCFGWQOS1_1 ++ >; + +- st,ctl-reg = < +- DDR_MSTR +- DDR_MRCTRL0 +- DDR_MRCTRL1 +- DDR_DERATEEN +- DDR_DERATEINT +- DDR_PWRCTL +- DDR_PWRTMG +- DDR_HWLPCTL +- DDR_RFSHCTL0 +- DDR_RFSHCTL3 +- DDR_CRCPARCTL0 +- DDR_ZQCTL0 +- DDR_DFITMG0 +- DDR_DFITMG1 +- DDR_DFILPCFG0 +- DDR_DFIUPD0 +- DDR_DFIUPD1 +- DDR_DFIUPD2 +- DDR_DFIPHYMSTR +- DDR_ODTMAP +- DDR_DBG0 +- DDR_DBG1 +- DDR_DBGCMD +- DDR_POISONCFG +- DDR_PCCFG +- >; ++ st,phy-reg = < ++ DDR_PGCR ++ DDR_ACIOCR ++ DDR_DXCCR ++ DDR_DSGCR ++ DDR_DCR ++ DDR_ODTCR ++ DDR_ZQ0CR1 ++ DDR_DX0GCR ++ DDR_DX1GCR ++ DDR_DX2GCR ++ DDR_DX3GCR ++ >; + +- st,ctl-timing = < +- DDR_RFSHTMG +- DDR_DRAMTMG0 +- DDR_DRAMTMG1 +- DDR_DRAMTMG2 +- DDR_DRAMTMG3 +- DDR_DRAMTMG4 +- DDR_DRAMTMG5 +- DDR_DRAMTMG6 +- DDR_DRAMTMG7 +- DDR_DRAMTMG8 +- DDR_DRAMTMG14 +- DDR_ODTCFG +- >; +- +- st,ctl-map = < +- DDR_ADDRMAP1 +- DDR_ADDRMAP2 +- DDR_ADDRMAP3 +- DDR_ADDRMAP4 +- DDR_ADDRMAP5 +- DDR_ADDRMAP6 +- DDR_ADDRMAP9 +- DDR_ADDRMAP10 +- DDR_ADDRMAP11 +- >; +- +- st,ctl-perf = < +- DDR_SCHED +- DDR_SCHED1 +- DDR_PERFHPR1 +- DDR_PERFLPR1 +- DDR_PERFWR1 +- DDR_PCFGR_0 +- DDR_PCFGW_0 +- DDR_PCFGQOS0_0 +- DDR_PCFGQOS1_0 +- DDR_PCFGWQOS0_0 +- DDR_PCFGWQOS1_0 +-#if STM32MP_DDR_DUAL_AXI_PORT +- DDR_PCFGR_1 +- DDR_PCFGW_1 +- DDR_PCFGQOS0_1 +- DDR_PCFGQOS1_1 +- DDR_PCFGWQOS0_1 +- DDR_PCFGWQOS1_1 +-#endif +- >; +- +- st,phy-reg = < +- DDR_PGCR +- DDR_ACIOCR +- DDR_DXCCR +- DDR_DSGCR +- DDR_DCR +- DDR_ODTCR +- DDR_ZQ0CR1 +- DDR_DX0GCR +- DDR_DX1GCR +-#if STM32MP_DDR_DUAL_AXI_PORT +- DDR_DX2GCR +- DDR_DX3GCR +-#endif +- >; +- +- st,phy-timing = < +- DDR_PTR0 +- DDR_PTR1 +- DDR_PTR2 +- DDR_DTPR0 +- DDR_DTPR1 +- DDR_DTPR2 +- DDR_MR0 +- DDR_MR1 +- DDR_MR2 +- DDR_MR3 +- >; ++ st,phy-timing = < ++ DDR_PTR0 ++ DDR_PTR1 ++ DDR_PTR2 ++ DDR_DTPR0 ++ DDR_DTPR1 ++ DDR_DTPR2 ++ DDR_MR0 ++ DDR_MR1 ++ DDR_MR2 ++ DDR_MR3 ++ >; + + #ifdef DDR_PHY_CAL_SKIP +- st,phy-cal = < +- DDR_DX0DLLCR +- DDR_DX0DQTR +- DDR_DX0DQSTR +- DDR_DX1DLLCR +- DDR_DX1DQTR +- DDR_DX1DQSTR +-#if STM32MP_DDR_DUAL_AXI_PORT +- DDR_DX2DLLCR +- DDR_DX2DQTR +- DDR_DX2DQSTR +- DDR_DX3DLLCR +- DDR_DX3DQTR +- DDR_DX3DQSTR ++ st,phy-cal = < ++ DDR_DX0DLLCR ++ DDR_DX0DQTR ++ DDR_DX0DQSTR ++ DDR_DX1DLLCR ++ DDR_DX1DQTR ++ DDR_DX1DQSTR ++ DDR_DX2DLLCR ++ DDR_DX2DQTR ++ DDR_DX2DQSTR ++ DDR_DX3DLLCR ++ DDR_DX3DQTR ++ DDR_DX3DQSTR ++ >; + #endif +- >; +-#endif +- +- status = "okay"; +- }; +- }; + }; +diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +index 127053b86a..6ca6293d4c 100644 +--- a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi ++++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +@@ -15,7 +15,7 @@ + * Save Date: 2020.02.20, save Time: 18:45:20 + */ + +-#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000Khz" ++#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000kHz" + #define DDR_MEM_SPEED 533000 + #define DDR_MEM_SIZE 0x20000000 + +@@ -61,13 +61,13 @@ + #define DDR_DBGCMD 0x00000000 + #define DDR_POISONCFG 0x00000000 + #define DDR_PCCFG 0x00000010 +-#define DDR_PCFGR_0 0x00000000 ++#define DDR_PCFGR_0 0x00010000 + #define DDR_PCFGW_0 0x00000000 + #define DDR_PCFGQOS0_0 0x02100C03 + #define DDR_PCFGQOS1_0 0x00800100 + #define DDR_PCFGWQOS0_0 0x01100C03 + #define DDR_PCFGWQOS1_0 0x01000200 +-#define DDR_PCFGR_1 0x00000000 ++#define DDR_PCFGR_1 0x00010000 + #define DDR_PCFGW_1 0x00000000 + #define DDR_PCFGQOS0_1 0x02100C03 + #define DDR_PCFGQOS1_1 0x00800040 +diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +index 5ae861fee1..548f69a197 100644 +--- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi ++++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +@@ -15,7 +15,7 @@ + * Save Date: 2020.02.20, save Time: 18:49:33 + */ + +-#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000Khz" ++#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000kHz" + #define DDR_MEM_SPEED 533000 + #define DDR_MEM_SIZE 0x40000000 + +@@ -61,13 +61,13 @@ + #define DDR_DBGCMD 0x00000000 + #define DDR_POISONCFG 0x00000000 + #define DDR_PCCFG 0x00000010 +-#define DDR_PCFGR_0 0x00000000 ++#define DDR_PCFGR_0 0x00010000 + #define DDR_PCFGW_0 0x00000000 + #define DDR_PCFGQOS0_0 0x02100C03 + #define DDR_PCFGQOS1_0 0x00800100 + #define DDR_PCFGWQOS0_0 0x01100C03 + #define DDR_PCFGWQOS1_0 0x01000200 +-#define DDR_PCFGR_1 0x00000000 ++#define DDR_PCFGR_1 0x00010000 + #define DDR_PCFGW_1 0x00000000 + #define DDR_PCFGQOS0_1 0x02100C03 + #define DDR_PCFGQOS1_1 0x00800040 +diff --git a/fdts/stm32mp15-ddr-1g-fw-config.dts b/fdts/stm32mp15-fw-config.dts +similarity index 60% +rename from fdts/stm32mp15-ddr-1g-fw-config.dts +rename to fdts/stm32mp15-fw-config.dts +index c871463062..f5c4972061 100644 +--- a/fdts/stm32mp15-ddr-1g-fw-config.dts ++++ b/fdts/stm32mp15-fw-config.dts +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + /* +- * Copyright (c) 2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved + */ + + #include +@@ -8,6 +8,21 @@ + #include + #include + ++#ifndef DDR_SIZE ++#error "DDR_SIZE is not defined" ++#endif ++ ++#define DDR_NS_BASE STM32MP_DDR_BASE ++#ifdef AARCH32_SP_OPTEE ++#define DDR_SHARE_SIZE 0x00200000 ++#define DDR_SHARE_BASE (STM32MP_DDR_BASE + (DDR_SIZE - DDR_SHARE_SIZE)) ++#define DDR_SEC_SIZE 0x01e00000 ++#define DDR_SEC_BASE (DDR_SHARE_BASE - DDR_SEC_SIZE) ++#define DDR_NS_SIZE (DDR_SEC_BASE - DDR_NS_BASE) ++#else ++#define DDR_NS_SIZE DDR_SIZE ++#endif ++ + /dts-v1/; + + / { +@@ -51,13 +66,13 @@ + compatible = "st,mem-firewall"; + #ifdef AARCH32_SP_OPTEE + memory-ranges = < +- 0xc0000000 0x3e000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR +- 0xfe000000 0x01e00000 TZC_REGION_S_RDWR 0 +- 0xffe00000 0x00200000 TZC_REGION_S_NONE ++ DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR ++ DDR_SEC_BASE DDR_SEC_SIZE TZC_REGION_S_RDWR 0 ++ DDR_SHARE_BASE DDR_SHARE_SIZE TZC_REGION_S_NONE + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID)>; + #else + memory-ranges = < +- 0xc0000000 0x40000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; ++ DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; + #endif + }; + }; +diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi +index 714d94710f..90b93387a6 100644 +--- a/fdts/stm32mp151.dtsi ++++ b/fdts/stm32mp151.dtsi +@@ -382,6 +382,24 @@ + secure-status = "disabled"; + }; + ++ ddr: ddr@5a003000{ ++ compatible = "st,stm32mp1-ddr"; ++ reg = <0x5A003000 0x550 0x5A004000 0x234>; ++ clocks = <&rcc AXIDCG>, ++ <&rcc DDRC1>, ++ <&rcc DDRC2>, ++ <&rcc DDRPHYC>, ++ <&rcc DDRCAPB>, ++ <&rcc DDRPHYCAPB>; ++ clock-names = "axidcg", ++ "ddrc1", ++ "ddrc2", ++ "ddrphyc", ++ "ddrcapb", ++ "ddrphycapb"; ++ status = "okay"; ++ }; ++ + usbphyc: usbphyc@5a006000 { + #address-cells = <1>; + #size-cells = <0>; +diff --git a/fdts/stm32mp157a-avenger96-fw-config.dts b/fdts/stm32mp157a-avenger96-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157a-avenger96-fw-config.dts ++++ b/fdts/stm32mp157a-avenger96-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157a-dk1-fw-config.dts b/fdts/stm32mp157a-dk1-fw-config.dts +index 256d0db935..d2be11aab2 100644 +--- a/fdts/stm32mp157a-dk1-fw-config.dts ++++ b/fdts/stm32mp157a-dk1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-512m-fw-config.dts" ++#define DDR_SIZE 0x20000000 /* 512MB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157a-ed1-fw-config.dts b/fdts/stm32mp157a-ed1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157a-ed1-fw-config.dts ++++ b/fdts/stm32mp157a-ed1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157a-ev1-fw-config.dts b/fdts/stm32mp157a-ev1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157a-ev1-fw-config.dts ++++ b/fdts/stm32mp157a-ev1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157c-dk2-fw-config.dts b/fdts/stm32mp157c-dk2-fw-config.dts +index 256d0db935..d2be11aab2 100644 +--- a/fdts/stm32mp157c-dk2-fw-config.dts ++++ b/fdts/stm32mp157c-dk2-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-512m-fw-config.dts" ++#define DDR_SIZE 0x20000000 /* 512MB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157c-ed1-fw-config.dts b/fdts/stm32mp157c-ed1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157c-ed1-fw-config.dts ++++ b/fdts/stm32mp157c-ed1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157c-ev1-fw-config.dts b/fdts/stm32mp157c-ev1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157c-ev1-fw-config.dts ++++ b/fdts/stm32mp157c-ev1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157d-dk1-fw-config.dts b/fdts/stm32mp157d-dk1-fw-config.dts +index 256d0db935..d2be11aab2 100644 +--- a/fdts/stm32mp157d-dk1-fw-config.dts ++++ b/fdts/stm32mp157d-dk1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-512m-fw-config.dts" ++#define DDR_SIZE 0x20000000 /* 512MB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157d-ed1-fw-config.dts b/fdts/stm32mp157d-ed1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157d-ed1-fw-config.dts ++++ b/fdts/stm32mp157d-ed1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157d-ev1-fw-config.dts b/fdts/stm32mp157d-ev1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157d-ev1-fw-config.dts ++++ b/fdts/stm32mp157d-ev1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157f-dk2-fw-config.dts b/fdts/stm32mp157f-dk2-fw-config.dts +index 256d0db935..d2be11aab2 100644 +--- a/fdts/stm32mp157f-dk2-fw-config.dts ++++ b/fdts/stm32mp157f-dk2-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-512m-fw-config.dts" ++#define DDR_SIZE 0x20000000 /* 512MB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157f-ed1-fw-config.dts b/fdts/stm32mp157f-ed1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157f-ed1-fw-config.dts ++++ b/fdts/stm32mp157f-ed1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp157f-ev1-fw-config.dts b/fdts/stm32mp157f-ev1-fw-config.dts +index 10f9402c4a..275406410e 100644 +--- a/fdts/stm32mp157f-ev1-fw-config.dts ++++ b/fdts/stm32mp157f-ev1-fw-config.dts +@@ -3,4 +3,5 @@ + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +-#include "stm32mp15-ddr-1g-fw-config.dts" ++#define DDR_SIZE 0x40000000 /* 1GB */ ++#include "stm32mp15-fw-config.dts" +diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi +index e5166706ee..fa1a4baaca 100644 +--- a/fdts/stm32mp15xx-dkx.dtsi ++++ b/fdts/stm32mp15xx-dkx.dtsi +@@ -134,14 +134,15 @@ + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; +- regulator-min-microvolt = <500000>; +- regulator-max-microvolt = <750000>; + regulator-always-on; + regulator-over-current-protection; ++ st,regulator-sink-source; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; + }; + + vdda: ldo5 { +@@ -161,7 +162,6 @@ + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; +- regulator-over-current-protection; + }; + + bst_out: boost { +@@ -254,7 +254,7 @@ + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK +- CLK_ETH_DISABLED ++ CLK_ETH_PLL4P + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE +diff --git a/fdts/stm32mp15xx-edx.dtsi b/fdts/stm32mp15xx-edx.dtsi +index 540f5b9d97..cccf3e3595 100644 +--- a/fdts/stm32mp15xx-edx.dtsi ++++ b/fdts/stm32mp15xx-edx.dtsi +@@ -136,14 +136,15 @@ + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; +- regulator-min-microvolt = <500000>; +- regulator-max-microvolt = <750000>; + regulator-always-on; + regulator-over-current-protection; ++ st,regulator-sink-source; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; + }; + + vdd_sd: ldo5 { +@@ -162,7 +163,6 @@ + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; +- regulator-over-current-protection; + }; + + bst_out: boost { +@@ -256,7 +256,7 @@ + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK +- CLK_ETH_DISABLED ++ CLK_ETH_PLL4P + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE +diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S +index 6bbcde2e0a..ed4ca273e9 100644 +--- a/include/arch/aarch32/el3_common_macros.S ++++ b/include/arch/aarch32/el3_common_macros.S +@@ -351,10 +351,21 @@ + * includes the data and NOBITS sections. This is done to + * safeguard against possible corruption of this memory by + * dirty cache lines in a system cache as a result of use by +- * an earlier boot loader stage. ++ * an earlier boot loader stage. If PIE is enabled however, ++ * RO sections including the GOT may be modified during ++ * pie fixup. Therefore, to be on the safe side, invalidate ++ * the entire image region if PIE is enabled. + * ----------------------------------------------------------------- + */ ++#if ENABLE_PIE ++#if SEPARATE_CODE_AND_RODATA ++ ldr r0, =__TEXT_START__ ++#else ++ ldr r0, =__RO_START__ ++#endif /* SEPARATE_CODE_AND_RODATA */ ++#else + ldr r0, =__RW_START__ ++#endif /* ENABLE_PIE */ + ldr r1, =__RW_END__ + sub r1, r1, r0 + bl inv_dcache_range +diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S +index 6f4143c5f5..20adcac2fd 100644 +--- a/include/arch/aarch64/el3_common_macros.S ++++ b/include/arch/aarch64/el3_common_macros.S +@@ -375,11 +375,24 @@ + * includes the data and NOBITS sections. This is done to + * safeguard against possible corruption of this memory by + * dirty cache lines in a system cache as a result of use by +- * an earlier boot loader stage. ++ * an earlier boot loader stage. If PIE is enabled however, ++ * RO sections including the GOT may be modified during ++ * pie fixup. Therefore, to be on the safe side, invalidate ++ * the entire image region if PIE is enabled. + * ------------------------------------------------------------- + */ ++#if ENABLE_PIE ++#if SEPARATE_CODE_AND_RODATA ++ adrp x0, __TEXT_START__ ++ add x0, x0, :lo12:__TEXT_START__ ++#else ++ adrp x0, __RO_START__ ++ add x0, x0, :lo12:__RO_START__ ++#endif /* SEPARATE_CODE_AND_RODATA */ ++#else + adrp x0, __RW_START__ + add x0, x0, :lo12:__RW_START__ ++#endif /* ENABLE_PIE */ + adrp x1, __RW_END__ + add x1, x1, :lo12:__RW_END__ + sub x1, x1, x0 +diff --git a/include/drivers/regulator.h b/include/drivers/regulator.h +new file mode 100644 +index 0000000000..392051f96e +--- /dev/null ++++ b/include/drivers/regulator.h +@@ -0,0 +1,160 @@ ++/* ++ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++#ifndef REGULATOR_H ++#define REGULATOR_H ++ ++#include ++ ++#ifndef PLAT_NB_RDEVS ++#error "Missing PLAT_NB_RDEVS" ++#endif ++ ++#ifndef PLAT_NB_SUSPEND_MODES ++#error "Missing PLAT_NB_SUSPEND_MODES" ++#endif ++ ++const char *plat_get_lp_mode_name(int mode); ++ ++/* ++ * Consumer interface ++ */ ++ ++/* regulator-always-on : regulator should never be disabled */ ++#define REGUL_ALWAYS_ON BIT(0) ++/* ++ * regulator-boot-on: ++ * It's expected that this regulator was left on by the bootloader. ++ * The core shouldn't prevent it from being turned off later. ++ * The regulator is needed to exit from suspend so it is turned on during suspend entry. ++ */ ++#define REGUL_BOOT_ON BIT(1) ++/* regulator-over-current-protection: Enable over current protection. */ ++#define REGUL_OCP BIT(2) ++/* regulator-active-discharge: enable active discharge. */ ++#define REGUL_ACTIVE_DISCHARGE BIT(3) ++/* regulator-pull-down: Enable pull down resistor when the regulator is disabled. */ ++#define REGUL_PULL_DOWN BIT(4) ++/* ++ * st,mask-reset: set mask reset for the regulator, meaning that the regulator ++ * setting is maintained during pmic reset. ++ */ ++#define REGUL_MASK_RESET BIT(5) ++/* st,regulator-sink-source: set the regulator in sink source mode */ ++#define REGUL_SINK_SOURCE BIT(6) ++/* st,regulator-bypass: set the regulator in bypass mode */ ++#define REGUL_ENABLE_BYPASS BIT(7) ++ ++struct rdev *regulator_get_by_name(const char *node_name); ++ ++#if defined(IMAGE_BL32) ++struct rdev *regulator_get_by_regulator_name(const char *reg_name); ++#endif ++ ++struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name); ++ ++int regulator_enable(struct rdev *rdev); ++int regulator_disable(struct rdev *rdev); ++int regulator_is_enabled(const struct rdev *rdev); ++ ++int regulator_set_voltage(struct rdev *rdev, uint16_t volt); ++int regulator_set_min_voltage(struct rdev *rdev); ++int regulator_get_voltage(const struct rdev *rdev); ++ ++int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count); ++void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv); ++int regulator_set_flag(struct rdev *rdev, uint16_t flag); ++ ++/* ++ * Driver Interface ++ */ ++ ++/* set_state() arguments */ ++#define STATE_DISABLE false ++#define STATE_ENABLE true ++ ++/* suspend() arguments */ ++#define LP_STATE_OFF BIT(0) ++#define LP_STATE_ON BIT(1) ++#define LP_STATE_UNCHANGED BIT(2) ++#define LP_STATE_SET_VOLT BIT(3) ++ ++struct regul_description { ++ const char *node_name; ++ const struct regul_ops *ops; ++ const void *driver_data; ++ const char *supply_name; ++ const uint32_t enable_ramp_delay; ++}; ++ ++struct regul_ops { ++ int (*set_state)(const struct regul_description *desc, bool state); ++ int (*get_state)(const struct regul_description *desc); ++ int (*set_voltage)(const struct regul_description *desc, uint16_t mv); ++ int (*get_voltage)(const struct regul_description *desc); ++ int (*list_voltages)(const struct regul_description *desc, ++ const uint16_t **levels, size_t *count); ++ int (*set_flag)(const struct regul_description *desc, uint16_t flag); ++#if defined(IMAGE_BL32) ++ void (*lock)(const struct regul_description *desc); ++ void (*unlock)(const struct regul_description *desc); ++ int (*suspend)(const struct regul_description *desc, uint8_t state, ++ uint16_t mv); ++#endif ++}; ++ ++int regulator_register(const struct regul_description *desc, int node); ++ ++/* ++ * Internal regulator structure ++ * The structure is internal to the core, and the content should not be used ++ * by a consumer nor a driver. ++ */ ++struct rdev { ++ const struct regul_description *desc; ++ ++ int32_t phandle; ++ ++ uint16_t min_mv; ++ uint16_t max_mv; ++ ++ uint16_t flags; ++ ++ uint32_t enable_ramp_delay; ++#if defined(IMAGE_BL32) ++ const char *reg_name; ++ ++ uint8_t use_count; ++ ++ int32_t supply_phandle; ++ struct rdev *supply_dev; ++ ++ uint8_t lp_state[PLAT_NB_SUSPEND_MODES]; ++ uint16_t lp_mv[PLAT_NB_SUSPEND_MODES]; ++#endif ++}; ++ ++#if defined(IMAGE_BL32) ++ ++/* Boot and init */ ++int regulator_core_config(void); ++int regulator_core_cleanup(void); ++ ++/* Suspend resume operations */ ++#define PLAT_BACKUP_REGULATOR_SIZE (sizeof(int8_t) * PLAT_NB_RDEVS) ++ ++int regulator_core_suspend(int mode); ++int regulator_core_resume(void); ++ ++void regulator_core_backup_context(void *backup_area, size_t backup_size); ++void regulator_core_restore_context(void *backup_area, size_t backup_size); ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++void regulator_core_dump(void); ++#endif ++ ++#endif ++ ++#endif /* REGULATOR_H */ +diff --git a/include/drivers/st/regulator_fixed.h b/include/drivers/st/regulator_fixed.h +new file mode 100644 +index 0000000000..b03c6e38c6 +--- /dev/null ++++ b/include/drivers/st/regulator_fixed.h +@@ -0,0 +1,12 @@ ++/* ++ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef REGULATOR_FIXED_H ++#define REGULATOR_FIXED_H ++ ++int fixed_regulator_register(void); ++ ++#endif /* REGULATOR_FIXED_H */ +diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h +index e241f584f7..b072345159 100644 +--- a/include/drivers/st/stm32_gpio.h ++++ b/include/drivers/st/stm32_gpio.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2015-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -52,6 +52,7 @@ int dt_set_pinctrl_config(int node); + void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, + uint32_t pull, uint32_t alternate, uint8_t status); + void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure); ++void set_gpio_reset_cfg(uint32_t bank, uint32_t pin); + #endif /*__ASSEMBLER__*/ + + #endif /* STM32_GPIO_H */ +diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h +index 5b4bd0e167..af02b91ea5 100644 +--- a/include/drivers/st/stm32_sdmmc2.h ++++ b/include/drivers/st/stm32_sdmmc2.h +@@ -10,7 +10,7 @@ + #include + + #include +-#include ++#include + + struct stm32_sdmmc2_params { + uintptr_t reg_base; +@@ -25,7 +25,7 @@ struct stm32_sdmmc2_params { + unsigned int reset_id; + unsigned int max_freq; + bool use_dma; +- struct stm32mp_regulator vmmc_regu; ++ struct rdev *vmmc_regu; + }; + + unsigned long long stm32_sdmmc2_mmc_get_device_size(void); +diff --git a/include/drivers/st/stm32_tamp.h b/include/drivers/st/stm32_tamp.h +index 424cbb205a..11dc96df69 100644 +--- a/include/drivers/st/stm32_tamp.h ++++ b/include/drivers/st/stm32_tamp.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2014-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -9,22 +9,22 @@ + + /* Internal Tamper */ + enum stm32_tamp_int_id { +- ITAMP1 = 0, +- ITAMP2, +- ITAMP3, +- ITAMP4, +- ITAMP5, +- ITAMP6, +- ITAMP7, +- ITAMP8, +- ITAMP9, +- ITAMP10, +- ITAMP11, +- ITAMP12, +- ITAMP13, +- ITAMP14, +- ITAMP15, +- ITAMP16 ++ INT_TAMP1 = 0, ++ INT_TAMP2, ++ INT_TAMP3, ++ INT_TAMP4, ++ INT_TAMP5, ++ INT_TAMP6, ++ INT_TAMP7, ++ INT_TAMP8, ++ INT_TAMP9, ++ INT_TAMP10, ++ INT_TAMP11, ++ INT_TAMP12, ++ INT_TAMP13, ++ INT_TAMP14, ++ INT_TAMP15, ++ INT_TAMP16 + }; + + /* External Tamper */ +@@ -39,95 +39,111 @@ enum stm32_tamp_ext_id { + EXT_TAMP8 + }; + +-enum stm32_tamp_state { +- TAMP_DISABLE = 0, +- TAMP_ENABLE ++/* Out pin to compare for external Tamper */ ++enum stm32_tamp_ext_out_id { ++ TAMPOUTSEL_SAME_AS_INPUT = 0, ++ TAMPOUTSEL1 = 1, ++ TAMPOUTSEL2, ++ TAMPOUTSEL3, ++ TAMPOUTSEL4, ++ TAMPOUTSEL5, ++ TAMPOUTSEL6, ++ TAMPOUTSEL7, ++ TAMPOUTSEL8, + }; + +-#define TAMP_UNUSED {.id = -1} ++/* Define number of backup registers in zone 1 and zone 2 (remaining are in ++ * zone 3) ++ * ++ * backup registers in zone 1 : read/write only in secure mode ++ * zone 2 : write only in secure mode, read in secure ++ * and non-secure mode ++ * zone 3 : read/write in secure and non-secure mode ++ * ++ * Protection zone 1 if nb_zone1_regs == 0 no backup register are in zone 1 ++ * else backup registers from TAMP_BKP0R to TAMP_BKPxR ++ * with x = nb_zone1_regs - 1 are in zone 1. ++ * Protection zone 2 if nb_zone2_regs == 0 no backup register are in zone 2 ++ * else backup registers from TAMP_BKPyR with y = nb_zone1_regs ++ * to TAMP_BKPzR with z = (nb_zone1_regs1 + nb_zone2_regs - 1) ++ * are in zone 2. ++ * Protection zone 3 backup registers from TAMP_BKPtR ++ * with t = nb_zone1_regs1 + nb_zone2_regs to last backup ++ * register are in zone 3. ++ */ ++struct bkpregs_conf { ++ uint32_t nb_zone1_regs; ++ uint32_t nb_zone2_regs; ++}; + +-/* define TAMPER modes */ ++/* Define TAMPER modes */ ++#define TAMP_DISABLE 0x0U ++#define TAMP_ENABLE 0x1U + #define TAMP_TRIG_OFF 0x0U +-#define TAMP_TRIG_ON 0x1U +-#define TAMP_ACTIVE 0x2U ++#define TAMP_TRIG_ON 0x2U ++#define TAMP_ACTIVE 0x4U + #define TAMP_ERASE 0x0U +-#define TAMP_NOERASE 0x1U ++#define TAMP_NOERASE 0x8U + #define TAMP_NO_EVT_MASK 0x0U +-#define TAMP_EVT_MASK 0x1U +- +-/* define Passive FILTER mode */ +-#define TAMP_FILTER_PRECHARGE 0x0U +-#define TAMP_FILTER_PULL_UP_DISABLE 0x1U +-#define TAMP_FILTER_DURATION_1_CYCLE 0x0U +-#define TAMP_FILTER_DURATION_2_CYCLES 0x1U +-#define TAMP_FILTER_DURATION_3_CYCLES 0x2U +-#define TAMP_FILTER_DURATION_4_CYCLES 0x3U +-#define TAMP_FILTER_COUNT_1 0x0U +-#define TAMP_FILTER_COUNT_2 0x1U +-#define TAMP_FILTER_COUNT_4 0x2U +-#define TAMP_FILTER_COUNT_8 0x3U +-#define TAMP_FILTER_SAMPLING_32768 0x0U +-#define TAMP_FILTER_SAMPLING_16384 0x1U +-#define TAMP_FILTER_SAMPLING_8192 0x2U +-#define TAMP_FILTER_SAMPLING_4096 0x3U +-#define TAMP_FILTER_SAMPLING_2048 0x4U +-#define TAMP_FILTER_SAMPLING_1024 0x5U +-#define TAMP_FILTER_SAMPLING_512 0x6U +-#define TAMP_FILTER_SAMPLING_256 0x7U +- +-/* define active filter */ +-#define TAMP_ACTIVE_FILTER_OFF 0x0U +-#define TAMP_ACTIVE_FILTER_ON 0x1U +-#define TAMP_ACTIVE_ATO_DEDICATED 0x0U +-#define TAMP_ACTIVE_ATO_TAMPOUTSEL 0x1U +-#define TAMP_ACTIVE_APER_1_OUTPUT 0x0U +-#define TAMP_ACTIVE_APER_2_OUTPUTS 0x1U +-#define TAMP_ACTIVE_APER_3_4_OUTPUTS 0x2U +-#define TAMP_ACTIVE_APER_5_OUTPUTS 0x3U +-#define TAMP_ACTIVE_CKSEL_DIV_0 0x0U +-#define TAMP_ACTIVE_CKSEL_DIV_2 0x1U +-#define TAMP_ACTIVE_CKSEL_DIV_4 0x2U +-#define TAMP_ACTIVE_CKSEL_DIV_8 0x3U +-#define TAMP_ACTIVE_CKSEL_DIV_16 0x4U +-#define TAMP_ACTIVE_CKSEL_DIV_32 0x5U +-#define TAMP_ACTIVE_CKSEL_DIV_64 0x6U +-#define TAMP_ACTIVE_CKSEL_DIV_128 0x7U +-#define TAMP_ACTIVE_ATOSEL_OUT1_(X) (0x0U << ((X) * 2)) +-#define TAMP_ACTIVE_ATOSEL_OUT2_(X) (0x1U << ((X) * 2)) +-#define TAMP_ACTIVE_ATOSEL_OUT3_(X) (0x2U << ((X) * 2)) +-#define TAMP_ACTIVE_ATOSEL_OUT4_(X) (0x3U << ((X) * 2)) +- +-#define TAMP_EXT(tamp_id, trig, erase, mask) (((tamp_id) << 3) | ((trig) << 2)\ +- | ((erase) << 1) | (mask)) +- +-#define TAMP_FLTCR(precharge, duration, count, sample) (((precharge) << 7) |\ +- ((duration) << 5) |\ +- ((count) << 3) |\ +- (sample)) +- +-#define TAMP_ACT(filter, ato, aper, atcksel, atosel) (((filter) << 31) |\ +- ((ato) << 30) |\ +- ((aper) << 24) |\ +- ((atcksel) << 16) |\ +- (atosel) << 8) +- +-struct stm32_tamp_int { +- int id; +- void (*func)(int id); +-}; +- +-struct stm32_tamp_ext { +- int id; +- uint8_t mode; +- uint8_t erase; +- uint8_t evt_mask; +- void (*func)(int id); +-}; ++#define TAMP_EVT_MASK 0x10U ++ ++/* Define Passive FILTER mode */ ++#define TAMP_FILTER_TAMPPUDIS_OFFSET 7U ++#define TAMP_FILTER_PRECHARGE (0x0U << TAMP_FILTER_TAMPPUDIS_OFFSET) ++#define TAMP_FILTER_PULL_UP_DISABLE (0x1U << TAMP_FILTER_TAMPPUDIS_OFFSET) ++#define TAMP_FILTER_TAMPPRCH_OFFSET 5U ++#define TAMP_FILTER_DURATION_1_CYCLE (0x0U << TAMP_FILTER_TAMPPRCH_OFFSET) ++#define TAMP_FILTER_DURATION_2_CYCLES (0x1U << TAMP_FILTER_TAMPPRCH_OFFSET) ++#define TAMP_FILTER_DURATION_4_CYCLES (0x2U << TAMP_FILTER_TAMPPRCH_OFFSET) ++#define TAMP_FILTER_DURATION_8_CYCLES (0x3U << TAMP_FILTER_TAMPPRCH_OFFSET) ++#define TAMP_FILTER_TAMPFLT_OFFSET 3U ++#define TAMP_FILTER_COUNT_1 (0x0U << TAMP_FILTER_TAMPFLT_OFFSET) ++#define TAMP_FILTER_COUNT_2 (0x1U << TAMP_FILTER_TAMPFLT_OFFSET) ++#define TAMP_FILTER_COUNT_4 (0x2U << TAMP_FILTER_TAMPFLT_OFFSET) ++#define TAMP_FILTER_COUNT_8 (0x3U << TAMP_FILTER_TAMPFLT_OFFSET) ++#define TAMP_FILTER_TAMPFREQ_OFFSET 0U ++#define TAMP_FILTER_SAMPLING_32768 (0x0U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_16384 (0x1U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_8192 (0x2U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_4096 (0x3U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_2048 (0x4U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_1024 (0x5U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_512 (0x6U << TAMP_FILTER_TAMPFREQ_OFFSET) ++#define TAMP_FILTER_SAMPLING_256 (0x7U << TAMP_FILTER_TAMPFREQ_OFFSET) ++ ++/* Define active filter */ ++#define TAMP_ACTIVE_FLTEN_OFFSET 31U ++#define TAMP_ACTIVE_FILTER_OFF (0x0U << TAMP_ACTIVE_FLTEN_OFFSET) ++#define TAMP_ACTIVE_FILTER_ON (0x1U << TAMP_ACTIVE_FLTEN_OFFSET) ++#define TAMP_FILTER_ATOSHARE_OFFSET 30U ++#define TAMP_FILTER_USE_DEDICATED_OUT (0x0U << TAMP_FILTER_ATOSHARE_OFFSET) ++#define TAMP_FILTER_SELECT_OUT (0x1U << TAMP_FILTER_ATOSHARE_OFFSET) ++#define TAMP_ACTIVE_ATPER_OFFSET 24U ++#define TAMP_ACTIVE_ATPER_1_OUTPUT (0x0U << TAMP_ACTIVE_ATPER_OFFSET) ++#define TAMP_ACTIVE_ATPER_2_OUTPUTS (0x1U << TAMP_ACTIVE_ATPER_OFFSET) ++#define TAMP_ACTIVE_ATPER_3_4_OUTPUTS (0x2U << TAMP_ACTIVE_ATPER_OFFSET) ++#define TAMP_ACTIVE_ATPER_5_OUTPUTS (0x3U << TAMP_ACTIVE_ATPER_OFFSET) ++#define TAMP_ACTIVE_ATCKSEL_OFFSET 16U ++#define TAMP_ACTIVE_CKSEL_DIV_0 (0x0U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_2 (0x1U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_4 (0x2U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_8 (0x3U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_16 (0x4U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_32 (0x5U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_64 (0x6U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++#define TAMP_ACTIVE_CKSEL_DIV_128 (0x7U << TAMP_ACTIVE_ATCKSEL_OFFSET) ++ ++/* Define secure mode acces */ ++/* Tamper configuration and interrupt can be written when the APB access is secure or nonsecure.*/ ++#define TAMP_REGS_IT_UNSECURE 0U ++/* Tamper configuration and interrupt can be written only when the APB access is secure.*/ ++#define TAMP_REGS_IT_SECURE BIT(31) + + /* +- * stm32_tamp_write_mcounter : Increase monotonic counter ++ * stm32_tamp_write_mcounter : Increase monotonic counter[counter_idx] + */ +-void stm32_tamp_write_mcounter(void); ++int stm32_tamp_write_mcounter(int counter_idx); ++uint32_t stm32_tamp_read_mcounter(int counter_idx); + + /* + * stm32_tamp_it_handler : Interrupt handler +@@ -135,24 +151,69 @@ void stm32_tamp_write_mcounter(void); + void stm32_tamp_it_handler(void); + + /* +- * stm32_tamp_configure_internal: Configure internal tamper +- * tamper_list: List of tamper to enable +- * nb_tamper: Number of tamper in list ++ * stm32_tamp_configure_secure_access: Configure which registers can be ++ * read/write from unsecure world ++ * secure_conf is a bit field from TAMP_.*_{UN,}SECURE define ++ */ ++void stm32_tamp_configure_secure_access(uint32_t secure_conf); ++ ++/* ++ * stm32_tamp_configure_privilege_access: Configure which registers can be ++ * read/write from unpriviliged world ++ * privilege_conf is a bit field from TAMP_.*_{UN,}PRIVILEGE define ++ */ ++void stm32_tamp_configure_privilege_access(uint32_t privilege_conf); ++ ++/* ++ * stm32_tamp_configure_passive: Configure passive mode ++ * passive_conf is a bit field from TAMP_FILTER_* define ++ */ ++void stm32_tamp_configure_passive(uint32_t passive_conf); ++ ++/* ++ * stm32_tamp_configure_ctive: Configure active mode ++ * passive_conf is a bit field from TAMP_ACTIVE_* define ++ */ ++void stm32_tamp_configure_active(uint32_t active_conf); ++ ++/* ++ * stm32_tamp_configure_internal: Configure one internal tamper ++ * id: internal tamper id ++ * mode: bitmask from TAMPER modes define ++ * callback: function to call when tamper is raised (can be NULL), ++ * called in interrupt context, ++ * if callback returns negative value, blocked secrets stay blocked ++ * (driver doesn't release this specific tamper). ++ * if callback returns 0 this specific tamp is ack (in case of no-erase ++ * tamper, blocked secret are unblocked) ++ * if callback returns positive value, this specific tamp is ack (in ++ * case of no-erase tamper, blocked secret are unblocked) and system is ++ * rebooted). ++ * ++ * return: -EINVAL if 'id' is not a valid internal tamp id, else 0 + */ +-void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, +- uint16_t nb_tamper); ++int stm32_tamp_configure_internal(enum stm32_tamp_int_id id, uint32_t mode, ++ int (*callback)(int id)); + + /* +- * stm32_tamp_configure_external: Configure external tamper and associated +- * configuration for filtering +- * ext_tamp_list: List of external tamper to configure +- * nb_tamper: Number of tamper in list +- * passive_conf: Filter configuration +- * active_conf: Configuration for active tamper ++ * stm32_tamp_configure_external: Configure one external tamper ++ * id: external tamper id ++ * mode: bitmask from TAMPER modes define ++ * pin_out; output pin connected to input pin (linekd with selected ext tamp id) ++ * callback: function to call when tamper is raised (can be NULL), ++ * called in interrupt context, ++ * if callback returns negative value, blocked secrets stay blocked ++ * (driver doesn't release this specific tamper). ++ * if callback returns 0 this specific tamp is ack (in case of no-erase ++ * tamper, blocked secret are unblocked) ++ * if callback returns positive value, this specific tamp is ack (in ++ * case of no-erase tamper, blocked secret are unblocked) and system is ++ * rebooted). ++ * ++ * return: -EINVAL if 'id' is not a valid external tamp id, else 0 + */ +-void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, +- uint8_t nb_tamper, uint32_t passive_conf, +- uint32_t active_conf); ++int stm32_tamp_configure_external(enum stm32_tamp_ext_id id, uint32_t mode, ++ enum stm32_tamp_ext_out_id out_pin, int (*callback)(int id)); + + /* + * stm32_tamp_init: Initialize tamper from DT +@@ -160,4 +221,32 @@ void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, + */ + int stm32_tamp_init(void); + ++/* ++ * stm32_tamp_set_secure_bkprwregs : Configure backup registers zone. ++ * registers in zone 1 : read/write only in secure mode ++ * zone 2 : write only in secure mode, read in secure and non-secure mode ++ * zone 3 : read/write in secure and non-secure mode ++ * ++ * bkpregs_conf : a pointer to struct bkpregs_conf that define the number of registers in zone 1 ++ * and zone 2 (remaining backup registers will be in zone 3). ++ * ++ * return 0 if OK, -ENODEV if zone 1 and/or zone 2 definition are out of range. ++ */ ++int stm32_tamp_set_secure_bkpregs(struct bkpregs_conf *bkpregs_conf); ++ ++/* ++ * stm32_tamp_set_config: apply configuration ++ * default one if no previous call to any of : ++ * stm32_tamp_configure_passive() ++ * stm32_tamp_configure_active() ++ * stm32_tamp_configure_internal() ++ * stm32_tamp_configure_external() ++ * stm32_tamp_configure_secret_list() ++ * stm32_tamp_configure_secure_access() ++ * stm32_tamp_configure_privilige_access() ++ * ++ * return: < 0 if unable to apply configuration, else 0 ++ */ ++int stm32_tamp_set_config(void); ++ + #endif /* STM32_TAMP_H */ +diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h +index e298fcf77b..1ccefc4fca 100644 +--- a/include/drivers/st/stm32mp1_ddr_regs.h ++++ b/include/drivers/st/stm32mp1_ddr_regs.h +@@ -361,6 +361,7 @@ struct stm32mp1_ddrphy { + #define DDRPHYC_PIR_DRAMRST BIT(5) + #define DDRPHYC_PIR_DRAMINIT BIT(6) + #define DDRPHYC_PIR_QSTRN BIT(7) ++#define DDRPHYC_PIR_RVTRN BIT(8) + #define DDRPHYC_PIR_ICPC BIT(16) + #define DDRPHYC_PIR_ZCALBYP BIT(30) + #define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7) +diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h +index 616051e772..ec6b485046 100644 +--- a/include/drivers/st/stm32mp1_rcc.h ++++ b/include/drivers/st/stm32mp1_rcc.h +@@ -306,6 +306,8 @@ + /* Fields of RCC_RDLSICR register */ + #define RCC_RDLSICR_LSION BIT(0) + #define RCC_RDLSICR_LSIRDY BIT(1) ++#define RCC_RDLSICR_MRD_MASK GENMASK(20, 16) ++#define RCC_RDLSICR_MRD_SHIFT 16 + + /* Used for all RCC_PLLCR registers */ + #define RCC_PLLNCR_PLLON BIT(0) +diff --git a/include/drivers/st/stm32mp_ddr_test.h b/include/drivers/st/stm32mp_ddr_test.h +new file mode 100644 +index 0000000000..fe4c8c08e0 +--- /dev/null ++++ b/include/drivers/st/stm32mp_ddr_test.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (C) 2021, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_DDR_TEST_H ++#define STM32MP_DDR_TEST_H ++ ++uint32_t stm32mp_ddr_test_rw_access(void); ++uint32_t stm32mp_ddr_test_data_bus(void); ++uint32_t stm32mp_ddr_test_addr_bus(uint64_t size); ++uint32_t stm32mp_ddr_check_size(void); ++ ++#endif /* STM32MP_DDR_TEST_H */ +diff --git a/include/drivers/st/stm32mp_dummy_regulator.h b/include/drivers/st/stm32mp_dummy_regulator.h +deleted file mode 100644 +index 6804192ba0..0000000000 +--- a/include/drivers/st/stm32mp_dummy_regulator.h ++++ /dev/null +@@ -1,14 +0,0 @@ +-/* +- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef STM32MP_DUMMY_REGULATOR_H +-#define STM32MP_DUMMY_REGULATOR_H +- +-#include +- +-void bind_dummy_regulator(struct stm32mp_regulator *regu); +- +-#endif /* STM32MP_DUMMY_REGULATOR_H */ +diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h +index 898a28b44c..dd91d5eebc 100644 +--- a/include/drivers/st/stm32mp_pmic.h ++++ b/include/drivers/st/stm32mp_pmic.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -11,8 +11,6 @@ + + #include + +-#include +- + /* + * dt_pmic_status - Check PMIC status from device tree + * +@@ -21,31 +19,6 @@ + */ + int dt_pmic_status(void); + +-/* +- * dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on +- * regulators from device tree configuration +- * +- * Returns 0 on success, and negative values on errors +- */ +-int pmic_configure_boot_on_regulators(void); +- +-int pmic_set_lp_config(const char *node_name); +- +-/* +- * dt_pmic_find_supply - Find the supply name related to a regulator name +- * +- * Returns 0 on success, and negative values on errors +- */ +-int dt_pmic_find_supply(const char **supply_name, const char *regu_name); +- +-/* +- * pmic_set_regulator_min_voltage - Set target supply to its device tree +- * "regulator-min-microvolt" value. +- * +- * Returns 0 on success, and negative values on errors +- */ +-int pmic_set_regulator_min_voltage(const char *regu_name); +- + /* + * initialize_pmic_i2c - Initialize I2C for the PMIC control + * +@@ -60,13 +33,6 @@ bool initialize_pmic_i2c(void); + */ + void initialize_pmic(void); + +-/* +- * configure_pmic - PMIC configuration function, called at platform init +- * +- * Panics on errors +- */ +-void configure_pmic(void); +- + #if DEBUG + void print_pmic_info_and_debug(void); + #else +@@ -75,9 +41,6 @@ static inline void print_pmic_info_and_debug(void) + } + #endif + +-bool is_pmic_regulator(struct stm32mp_regulator *regu); +-void bind_pmic_regulator(struct stm32mp_regulator *regu); +- + /* + * pmic_ddr_power_init - Initialize regulators required for DDR + * +@@ -85,4 +48,11 @@ void bind_pmic_regulator(struct stm32mp_regulator *regu); + */ + int pmic_ddr_power_init(enum ddr_type ddr_type); + ++/* ++ * pmic_switch_off - switch off the platform with PMIC ++ * ++ * Panics on errors ++ */ ++void pmic_switch_off(void); ++ + #endif /* STM32MP_PMIC_H */ +diff --git a/include/drivers/st/stm32mp_regulator.h b/include/drivers/st/stm32mp_regulator.h +deleted file mode 100644 +index 7a66b97ba7..0000000000 +--- a/include/drivers/st/stm32mp_regulator.h ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* +- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef STM32MP_REGULATOR_H +-#define STM32MP_REGULATOR_H +- +-#include +- +-struct stm32mp_regulator; +- +-struct stm32mp_regulator_ops { +- int (*enable)(struct stm32mp_regulator *regu); +- int (*disable)(struct stm32mp_regulator *regu); +-}; +- +-struct stm32mp_regulator { +- const struct stm32mp_regulator_ops *ops; +- int id; +- bool always_on; +-}; +- +-int stm32mp_regulator_enable(struct stm32mp_regulator *regu); +-int stm32mp_regulator_disable(struct stm32mp_regulator *regu); +-int stm32mp_regulator_register(struct stm32mp_regulator *regu); +- +-int plat_bind_regulator(struct stm32mp_regulator *regu); +- +-#endif /* STM32MP_REGULATOR_H */ +diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h +index 5c8933d84d..4e19ba3e5c 100644 +--- a/include/drivers/st/stpmic1.h ++++ b/include/drivers/st/stpmic1.h +@@ -103,6 +103,22 @@ + #define BUCK4_PULL_DOWN_SHIFT 6 + #define VREF_DDR_PULL_DOWN_SHIFT 4 + ++/* ICC register */ ++#define BUCK1_ICC_SHIFT 0 ++#define BUCK2_ICC_SHIFT 1 ++#define BUCK3_ICC_SHIFT 2 ++#define BUCK4_ICC_SHIFT 3 ++#define PWR_SW1_ICC_SHIFT 4 ++#define PWR_SW2_ICC_SHIFT 5 ++#define BOOST_ICC_SHIFT 6 ++ ++#define LDO1_ICC_SHIFT 0 ++#define LDO2_ICC_SHIFT 1 ++#define LDO3_ICC_SHIFT 2 ++#define LDO4_ICC_SHIFT 3 ++#define LDO5_ICC_SHIFT 4 ++#define LDO6_ICC_SHIFT 5 ++ + /* Buck Mask reset register */ + #define BUCK1_MASK_RESET 0 + #define BUCK2_MASK_RESET 1 +@@ -118,6 +134,10 @@ + #define LDO6_MASK_RESET 5 + #define VREF_DDR_MASK_RESET 6 + ++/* LDO3 Special modes */ ++#define LDO3_BYPASS BIT(7) ++#define LDO3_DDR_SEL 31U ++ + /* Main PMIC Control Register (MAIN_CONTROL_REG) */ + #define ICC_EVENT_ENABLED BIT(4) + #define PWRCTRL_POLARITY_HIGH BIT(3) +@@ -145,6 +165,8 @@ + /* USB Control Register */ + #define BOOST_OVP_DISABLED BIT(7) + #define VBUS_OTG_DETECTION_DISABLED BIT(6) ++#define SW_OUT_DISCHARGE BIT(5) ++#define VBUS_OTG_DISCHARGE BIT(4) + #define OCP_LIMIT_HIGH BIT(3) + #define SWIN_SWOUT_ENABLED BIT(2) + #define USBSW_OTG_SWITCH_ENABLED BIT(1) +@@ -159,9 +181,15 @@ int stpmic1_regulator_enable(const char *name); + int stpmic1_regulator_disable(const char *name); + bool stpmic1_is_regulator_enabled(const char *name); + int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts); ++int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels, ++ size_t *levels_count); + int stpmic1_regulator_voltage_get(const char *name); + int stpmic1_regulator_pull_down_set(const char *name); + int stpmic1_regulator_mask_reset_set(const char *name); ++int stpmic1_regulator_icc_set(const char *name); ++int stpmic1_regulator_sink_mode_set(const char *name); ++int stpmic1_regulator_bypass_mode_set(const char *name); ++int stpmic1_active_discharge_mode_set(const char *name); + int stpmic1_lp_copy_reg(const char *name); + int stpmic1_lp_reg_on_off(const char *name, uint8_t enable); + int stpmic1_lp_set_mode(const char *name, uint8_t hplp); +diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h +index aa9158cb1b..881159c7fc 100644 +--- a/include/dt-bindings/interrupt-controller/arm-gic.h ++++ b/include/dt-bindings/interrupt-controller/arm-gic.h +@@ -1,21 +1,26 @@ +-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ + /* ++ * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: MIT ++ * + * This header provides constants for the ARM GIC. + */ + + #ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H + #define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H + ++#include ++ + /* interrupt specifier cell 0 */ + + #define GIC_SPI 0 + #define GIC_PPI 1 + +-#define IRQ_TYPE_NONE 0 +-#define IRQ_TYPE_EDGE_RISING 1 +-#define IRQ_TYPE_EDGE_FALLING 2 +-#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) +-#define IRQ_TYPE_LEVEL_HIGH 4 +-#define IRQ_TYPE_LEVEL_LOW 8 ++/* ++ * Interrupt specifier cell 2. ++ * The flags in irq.h are valid, plus those below. ++ */ ++#define GIC_CPU_MASK_RAW(x) ((x) << 8) ++#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1) + + #endif +diff --git a/include/dt-bindings/interrupt-controller/irq.h b/include/dt-bindings/interrupt-controller/irq.h +new file mode 100644 +index 0000000000..1ff6681e24 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/irq.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: MIT ++ * ++ * This header provides constants for most IRQ bindings. ++ * ++ * Most IRQ bindings include a flags cell as part of the IRQ specifier. ++ * In most cases, the format of the flags cell uses the standard values ++ * defined in this header. ++ */ ++ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H ++ ++#define IRQ_TYPE_NONE 0 ++#define IRQ_TYPE_EDGE_RISING 1 ++#define IRQ_TYPE_EDGE_FALLING 2 ++#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) ++#define IRQ_TYPE_LEVEL_HIGH 4 ++#define IRQ_TYPE_LEVEL_LOW 8 ++ ++#endif +diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S +index aea975c0ad..1cd8e236cf 100644 +--- a/lib/aarch32/misc_helpers.S ++++ b/lib/aarch32/misc_helpers.S +@@ -301,9 +301,9 @@ func fixup_gdt_reloc + cmp r4, r6 + blo 2f + +- /* Skip adding offset if address is >= upper limit */ ++ /* Skip adding offset if address is > upper limit */ + cmp r4, r7 +- bhs 2f ++ bhi 2f + + add r4, r0, r4 + str r4, [r3] +diff --git a/licenses/LICENSE.MIT b/licenses/LICENSE.MIT +new file mode 100644 +index 0000000000..8aa26455d2 +--- /dev/null ++++ b/licenses/LICENSE.MIT +@@ -0,0 +1,21 @@ ++MIT License ++ ++Copyright (c) [year] [fullname] ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. +diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c +index 23794db963..2ea9f627ec 100644 +--- a/plat/st/common/bl2_io_storage.c ++++ b/plat/st/common/bl2_io_storage.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -11,6 +11,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -48,7 +49,7 @@ static uint32_t nand_bkp_offset; + #if STM32MP_SDMMC || STM32MP_EMMC + static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE); + +-static const io_block_dev_spec_t mmc_block_dev_spec = { ++static io_block_dev_spec_t mmc_block_dev_spec = { + /* It's used as temp buffer in block driver */ + .buffer = { + .offset = (size_t)&block_buffer, +@@ -412,6 +413,11 @@ int bl2_plat_handle_pre_image_load(unsigned int image_id) + image_block_spec.length = entry->length; + + gpt_init_done = true; ++ } else { ++ bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); ++ ++ mmc_block_dev_spec.buffer.offset = bl_mem_params->image_info.image_base; ++ mmc_block_dev_spec.buffer.length = bl_mem_params->image_info.image_max_size; + } + + break; +diff --git a/plat/st/common/include/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h +index 947ad43aea..db5dfbf4f4 100644 +--- a/plat/st/common/include/stm32cubeprogrammer.h ++++ b/plat/st/common/include/stm32cubeprogrammer.h +@@ -31,9 +31,6 @@ + #define NACK_BYTE 0x1FU + #define ABORT 0x5FU + +-#define DEVICE_ID_BYTE1 0x05U +-#define DEVICE_ID_BYTE2 0x00U +- + /* Functions provided by plat */ + uint8_t usb_dfu_get_phase(uint8_t alt); + +diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h +index 022e22742a..40291c43ed 100644 +--- a/plat/st/common/include/stm32mp_common.h ++++ b/plat/st/common/include/stm32mp_common.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -7,12 +7,12 @@ + #ifndef STM32MP_COMMON_H + #define STM32MP_COMMON_H + +-#include + #include + + #include + +-void __dead2 stm32mp_plat_reset(int cpu); ++#define JEDEC_ST_BKID U(0x0) ++#define JEDEC_ST_MFID U(0x20) + + /* Functions to save and get boot context address given by ROM code */ + void stm32mp_save_boot_ctx_address(uintptr_t address); +@@ -24,10 +24,6 @@ bool stm32mp_is_single_core(void); + bool stm32mp_is_closed_device(void); + bool stm32mp_is_auth_supported(void); + +-const char *stm32mp_get_cpu_supply_name(void); +-const char *stm32mp_get_vdd_supply_name(void); +-const char *stm32mp_get_usb_phy_supply_name(void); +- + /* Return the base address of the DDR controller */ + uintptr_t stm32mp_ddrctrl_base(void); + +@@ -88,12 +84,15 @@ uintptr_t get_uart_address(uint32_t instance_nb); + uintptr_t stm32_get_gpio_bank_base(unsigned int bank); + unsigned long stm32_get_gpio_bank_clock(unsigned int bank); + uint32_t stm32_get_gpio_bank_offset(unsigned int bank); ++bool stm32_gpio_is_secure_at_reset(unsigned int bank); + + /* Return node offset for target GPIO bank ID @bank or a FDT error code */ + int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank); + + /* Get the chip revision */ +-int stm32mp_get_chip_version(uint32_t *chip_version); ++uint32_t stm32mp_get_chip_version(void); ++/* Get the chip device ID */ ++uint32_t stm32mp_get_chip_dev_id(void); + + /* Get SOC name */ + #define STM32_SOC_NAME_SIZE 20 +diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h +index 0ff30a3827..0414014c2f 100644 +--- a/plat/st/common/include/stm32mp_dt.h ++++ b/plat/st/common/include/stm32mp_dt.h +@@ -44,9 +44,9 @@ int dt_get_max_opp_freqvolt(uint32_t *freq_khz, uint32_t *voltage_mv); + int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array, + uint32_t *voltage_mv_array); + uint32_t dt_get_pwr_vdd_voltage(void); +-const char *dt_get_vdd_regulator_name(void); +-const char *dt_get_cpu_regulator_name(void); +-const char *dt_get_usb_phy_regulator_name(void); ++struct rdev *dt_get_vdd_regulator(void); ++struct rdev *dt_get_cpu_regulator(void); ++struct rdev *dt_get_usb_phy_regulator(void); + const char *dt_get_board_model(void); + int fdt_get_gpio_bank_pin_count(unsigned int bank); + +diff --git a/plat/st/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c +index 3fd16aa39c..7a6e02463f 100644 +--- a/plat/st/common/stm32cubeprogrammer_uart.c ++++ b/plat/st/common/stm32cubeprogrammer_uart.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -203,13 +203,20 @@ static int get_version_command(void) + + static int get_id_command(void) + { +- const uint8_t msg[3] = { +- sizeof(msg) - 1, +- DEVICE_ID_BYTE1, +- DEVICE_ID_BYTE2 +- }; ++ uint32_t id = stm32mp_get_chip_dev_id(); ++ int ret; ++ ++ ret = uart_write_8(2U); /* Length of command */ ++ if (ret != 0) { ++ return ret; ++ } ++ ++ ret = uart_write_8((id & 0xFF00) >> 8); /* device ID byte 1 */ ++ if (ret != 0) { ++ return ret; ++ } + +- return uart_write(msg, sizeof(msg)); ++ return uart_write_8(id & 0xFF); /* device ID byte 2 */ + } + + static int uart_send_phase(uint32_t address) +diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c +index 3f385ca317..04219677cc 100644 +--- a/plat/st/common/stm32mp_common.c ++++ b/plat/st/common/stm32mp_common.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,10 +13,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #define HEADER_VERSION_MAJOR_MASK GENMASK(23, 16) + +@@ -32,12 +34,6 @@ unsigned int plat_get_syscnt_freq2(void) + return read_cntfrq_el0(); + } + +-#pragma weak stm32mp_plat_reset +-void __dead2 stm32mp_plat_reset(int cpu) +-{ +- panic(); +-} +- + static uintptr_t boot_ctx_address; + static uint16_t boot_itf_selected; + static uint32_t boot_action_saved; +@@ -147,58 +143,6 @@ int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer) + } + #endif + +-/* Return CPU supply name */ +-const char *stm32mp_get_cpu_supply_name(void) +-{ +- const char *regulator; +- const char *supply = NULL; +- +- regulator = dt_get_cpu_regulator_name(); +- if (regulator == NULL) { +- return NULL; +- } +- +- if (dt_pmic_status() > 0) { +- if (dt_pmic_find_supply(&supply, regulator) != 0) { +- return NULL; +- } +- } +- +- return supply; +-} +- +-/* Return VDD supply name */ +-const char *stm32mp_get_vdd_supply_name(void) +-{ +- const char *supply = NULL; +- +- if (dt_pmic_status() > 0) { +- const char *regulator = dt_get_vdd_regulator_name(); +- +- if (regulator != NULL) { +- dt_pmic_find_supply(&supply, regulator); +- } +- } +- +- return supply; +-} +- +-/* Return USB phy supply name */ +-const char *stm32mp_get_usb_phy_supply_name(void) +-{ +- const char *supply = NULL; +- +- if (dt_pmic_status() > 0) { +- const char *regulator = dt_get_usb_phy_regulator_name(); +- +- if (regulator != NULL) { +- dt_pmic_find_supply(&supply, regulator); +- } +- } +- +- return supply; +-} +- + #if TRUSTED_BOARD_BOOT && STM32MP_USE_STM32IMAGE + /* Save pointer to last loaded header */ + static boot_api_image_header_t *latest_stm32_header; +@@ -243,3 +187,35 @@ int stm32mp_unmap_ddr(void) + return mmap_remove_dynamic_region(STM32MP_DDR_BASE, + STM32MP_DDR_MAX_SIZE); + } ++ ++/***************************************************************************** ++ * plat_is_smccc_feature_available() - This function checks whether SMCCC ++ * feature is availabile for platform. ++ * @fid: SMCCC function id ++ * ++ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and ++ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. ++ *****************************************************************************/ ++int32_t plat_is_smccc_feature_available(u_register_t fid) ++{ ++ switch (fid) { ++ case SMCCC_ARCH_SOC_ID: ++ return SMC_ARCH_CALL_SUCCESS; ++ default: ++ return SMC_ARCH_CALL_NOT_SUPPORTED; ++ } ++} ++ ++/* Get SOC version */ ++int32_t plat_get_soc_version(void) ++{ ++ uint32_t manfid = (JEDEC_ST_BKID << 24U) | (JEDEC_ST_MFID << 16U); ++ ++ return (int32_t)(manfid | (stm32mp_get_chip_dev_id() & 0xFFFFU)); ++} ++ ++/* Get SOC revision */ ++int32_t plat_get_soc_revision(void) ++{ ++ return (int32_t)stm32mp_get_chip_version(); ++} +diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c +index a3584cbc12..fd25c93fca 100644 +--- a/plat/st/common/stm32mp_dt.c ++++ b/plat/st/common/stm32mp_dt.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + + #include +@@ -71,21 +72,20 @@ bool fdt_check_node(int node) + uint8_t fdt_get_status(int node) + { + uint8_t status = DT_DISABLED; +- int len; + const char *cchar; + +- cchar = fdt_getprop(fdt, node, "status", &len); ++ cchar = fdt_getprop(fdt, node, "status", NULL); + if ((cchar == NULL) || +- (strncmp(cchar, "okay", (size_t)len) == 0)) { ++ (strncmp(cchar, "okay", strlen("okay")) == 0)) { + status |= DT_NON_SECURE; + } + +- cchar = fdt_getprop(fdt, node, "secure-status", &len); ++ cchar = fdt_getprop(fdt, node, "secure-status", NULL); + if (cchar == NULL) { + if (status == DT_NON_SECURE) { + status |= DT_SECURE; + } +- } else if (strncmp(cchar, "okay", (size_t)len) == 0) { ++ } else if (strncmp(cchar, "okay", strlen("okay")) == 0) { + status |= DT_SECURE; + } + +@@ -458,61 +458,23 @@ int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array, + ******************************************************************************/ + uint32_t dt_get_pwr_vdd_voltage(void) + { +- int node; +- const fdt32_t *cuint; ++ struct rdev *regul = dt_get_vdd_regulator(); ++ uint16_t min; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); +- if (node < 0) { ++ if (regul == NULL) { + return 0; + } + +- cuint = fdt_getprop(fdt, node, "vdd-supply", NULL); +- if (cuint == NULL) { +- return 0; +- } ++ regulator_get_range(regul, &min, NULL); + +- node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); +- if (node < 0) { +- return 0; +- } +- +- cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); +- if (cuint == NULL) { +- return 0; +- } +- +- return fdt32_to_cpu(*cuint); ++ return (uint32_t)min * 1000U; + } + + /******************************************************************************* +- * This function return the real regulator name from DT. ++ * This function retrieves VDD supply regulator from DT. ++ * Returns an rdev taken from supply node, NULL otherwise. + ******************************************************************************/ +-static const char *dt_get_regulator_name(int node, const char *regu_name) +-{ +- const fdt32_t *cuint; +- +- if ((node < 0) || (regu_name == NULL)) { +- return NULL; +- } +- +- cuint = fdt_getprop(fdt, node, regu_name, NULL); +- if (cuint == NULL) { +- return NULL; +- } +- +- node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); +- if (node < 0) { +- return NULL; +- } +- +- return (const char *)fdt_getprop(fdt, node, "regulator-name", NULL); +-} +- +-/******************************************************************************* +- * This function retrieves VDD regulator name from DT. +- * Returns string taken from supply node, NULL otherwise. +- ******************************************************************************/ +-const char *dt_get_vdd_regulator_name(void) ++struct rdev *dt_get_vdd_regulator(void) + { + int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); + +@@ -520,14 +482,14 @@ const char *dt_get_vdd_regulator_name(void) + return NULL; + } + +- return dt_get_regulator_name(node, "vdd-supply"); ++ return regulator_get_by_supply_name(fdt, node, "vdd"); + } + + /******************************************************************************* +- * This function retrieves CPU regulator name from DT. +- * Returns string taken from supply node, NULL otherwise. ++ * This function retrieves CPU supply regulator from DT. ++ * Returns an rdev taken from supply node, NULL otherwise. + ******************************************************************************/ +-const char *dt_get_cpu_regulator_name(void) ++struct rdev *dt_get_cpu_regulator(void) + { + int node = fdt_path_offset(fdt, "/cpus/cpu@0"); + +@@ -535,27 +497,27 @@ const char *dt_get_cpu_regulator_name(void) + return NULL; + } + +- return dt_get_regulator_name(node, "cpu-supply"); ++ return regulator_get_by_supply_name(fdt, node, "cpu"); + } + + /******************************************************************************* + * This function retrieves USB phy regulator name from DT. + * Returns string taken from supply node, NULL otherwise. + ******************************************************************************/ +-const char *dt_get_usb_phy_regulator_name(void) ++struct rdev *dt_get_usb_phy_regulator(void) + { + int node = fdt_node_offset_by_compatible(fdt, -1, DT_USBPHYC_COMPAT); + int subnode; +- const char *reg_name = NULL; + + if (node < 0) { + return NULL; + } + + fdt_for_each_subnode(subnode, fdt, node) { +- reg_name = dt_get_regulator_name(subnode, "phy-supply"); +- if (reg_name != NULL) { +- return reg_name; ++ struct rdev *supply = regulator_get_by_supply_name(fdt, node, "phy"); ++ ++ if (supply != NULL) { ++ return supply; + } + } + +diff --git a/plat/st/common/stm32mp_trusted_boot.c b/plat/st/common/stm32mp_trusted_boot.c +index 1ea30abf9b..6bc77e2440 100644 +--- a/plat/st/common/stm32mp_trusted_boot.c ++++ b/plat/st/common/stm32mp_trusted_boot.c +@@ -85,7 +85,7 @@ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, + memcpy(&res, proot_pk, sizeof(uint32_t)); + if ((res == 0U) || (res == 0xFFFFFFFFU)) { + while (idx < ARRAY_SIZE(root_pk_hash)) { +- memcpy(&rootpk, (proot_pk + idx), sizeof(uint32_t)); ++ memcpy(&rootpk, root_pk_hash + idx, sizeof(uint32_t)); + if (res != rootpk) { + return 0; + } +diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c +index 13ce3042a5..642138a1dd 100644 +--- a/plat/st/stm32mp1/bl2_plat_setup.c ++++ b/plat/st/stm32mp1/bl2_plat_setup.c +@@ -17,6 +17,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -189,10 +191,6 @@ void bl2_platform_setup(void) + + /* Clear the context in BKPSRAM */ + stm32_clean_context(); +- +- if (dt_pmic_status() > 0) { +- configure_pmic(); +- } + } + + /* Map DDR for binary load, now with cacheable attribute */ +@@ -269,21 +267,21 @@ static void initialize_clock(void) + + if (dt_pmic_status() > 0) { + int read_voltage; +- const char *name; ++ struct rdev *regul; + +- name = stm32mp_get_cpu_supply_name(); +- if (name == NULL) { ++ regul = dt_get_cpu_regulator(); ++ if (regul == NULL) { + panic(); + } + +- read_voltage = stpmic1_regulator_voltage_get(name); ++ read_voltage = regulator_get_voltage(regul); + if (read_voltage < 0) { + panic(); + } + + if (voltage_mv != (uint32_t)read_voltage) { +- if (stpmic1_regulator_voltage_set(name, +- (uint16_t)voltage_mv) != 0) { ++ if (regulator_set_voltage(regul, ++ (uint16_t)voltage_mv) != 0) { + panic(); + } + } +@@ -380,10 +378,11 @@ void bl2_el3_plat_arch_setup(void) + mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); + } + +- /* Enable BKP Register protection */ +- mmio_write_32(TAMP_SMCR, +- TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_WDPROT_SHIFT | +- TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_RWDPROT_SHIFT); ++ /* Set minimum reset pulse duration to 31ms for discrete power supplied boards */ ++ if (dt_pmic_status() <= 0) { ++ mmio_clrsetbits_32(rcc_base + RCC_RDLSICR, RCC_RDLSICR_MRD_MASK, ++ 31U << RCC_RDLSICR_MRD_SHIFT); ++ } + + generic_delay_timer_init(); + +@@ -411,6 +410,11 @@ void bl2_el3_plat_arch_setup(void) + + initialize_clock(); + ++#if STM32MP_USB_PROGRAMMER ++ /* Deconfigure all UART RX pins configured by ROM code */ ++ stm32mp1_deconfigure_uart_pins(); ++#endif ++ + result = dt_get_stdout_uart_info(&dt_uart_info); + + if ((result <= 0) || +@@ -455,13 +459,11 @@ void bl2_el3_plat_arch_setup(void) + + stm32mp_print_boardinfo(); + +-#if TRUSTED_BOARD_BOOT + if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) { + NOTICE("Bootrom authentication %s\n", + (boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ? + "failed" : "succeeded"); + } +-#endif + + skip_console_init: + #if !TRUSTED_BOARD_BOOT +@@ -506,7 +508,7 @@ skip_console_init: + stm32mp1_syscfg_enable_io_compensation_finish(); + + if (dt_pmic_status() > 0) { +- initialize_pmic(); ++ initialize_pmic_i2c(); + print_pmic_info_and_debug(); + } + +@@ -718,6 +720,19 @@ int bl2_plat_handle_post_image_load(unsigned int image_id) + break; + } + ++#if STM32MP_SDMMC || STM32MP_EMMC ++ /* ++ * Invalidate remaining data read from MMC but not flushed by load_image_flush(). ++ * We take the worst case which is 2 MMC blocks. ++ */ ++ if ((image_id != FW_CONFIG_ID) && ++ ((bl_mem_params->image_info.h.attr & IMAGE_ATTRIB_SKIP_LOADING) == 0U)) { ++ inv_dcache_range(bl_mem_params->image_info.image_base + ++ bl_mem_params->image_info.image_size, ++ 2U * MMC_BLOCK_SIZE); ++ } ++#endif ++ + return err; + } + +diff --git a/plat/st/stm32mp1/include/stm32mp1_critic_power.h b/plat/st/stm32mp1/include/stm32mp1_critic_power.h +index cd7099c444..7563406b4e 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_critic_power.h ++++ b/plat/st/stm32mp1/include/stm32mp1_critic_power.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -12,11 +12,11 @@ + */ + #if defined(IMAGE_BL32) + #if STM32MP_SP_MIN_IN_DDR +-extern void (*stm32_pwr_down_wfi)(bool is_cstop); ++extern void (*stm32_pwr_down_wfi)(bool is_cstop, uint32_t mode); + #else +-extern void stm32_pwr_down_wfi(bool is_cstop); ++extern void stm32_pwr_down_wfi(bool is_cstop, uint32_t mode); + #endif + #endif +-extern void stm32_pwr_down_wfi_wrapper(bool is_cstop); ++extern void stm32_pwr_down_wfi_wrapper(bool is_cstop, uint32_t mode); + + #endif /* STM32MP1_CRITIC_POWER_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h +index ebf9e52bc9..cbcd2c8bd5 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_private.h ++++ b/plat/st/stm32mp1/include/stm32mp1_private.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -40,6 +40,8 @@ void stm32mp1_syscfg_enable_io_compensation_start(void); + void stm32mp1_syscfg_enable_io_compensation_finish(void); + void stm32mp1_syscfg_disable_io_compensation(void); + ++void stm32mp1_deconfigure_uart_pins(void); ++ + #if STM32MP_USE_STM32IMAGE + uint32_t stm32mp_get_ddr_ns_size(void); + #endif +diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +index d322da0090..6092db2b95 100644 +--- a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c ++++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +@@ -21,18 +21,18 @@ + static bl_mem_params_node_t bl2_mem_params_descs[] = { + /* Fill FW_CONFIG related information if it exists */ + { +- .image_id = FW_CONFIG_ID, +- SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, +- VERSION_2, entry_point_info_t, +- SECURE | NON_EXECUTABLE), +- SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, +- VERSION_2, image_info_t, +- IMAGE_ATTRIB_PLAT_SETUP), +- +- .image_info.image_base = STM32MP_FW_CONFIG_BASE, +- .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE, +- +- .next_handoff_image_id = INVALID_IMAGE_ID, ++ .image_id = FW_CONFIG_ID, ++ SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, ++ VERSION_2, entry_point_info_t, ++ SECURE | NON_EXECUTABLE), ++ SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, ++ VERSION_2, image_info_t, ++ IMAGE_ATTRIB_PLAT_SETUP), ++ ++ .image_info.image_base = STM32MP_FW_CONFIG_BASE, ++ .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE, ++ ++ .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* Fill BL32 related information */ +@@ -85,27 +85,28 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { + + /* Fill HW_CONFIG related information if it exists */ + { +- .image_id = HW_CONFIG_ID, +- SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, +- VERSION_2, entry_point_info_t, +- NON_SECURE | NON_EXECUTABLE), +- SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, +- VERSION_2, image_info_t, +- IMAGE_ATTRIB_SKIP_LOADING), +- +- .next_handoff_image_id = INVALID_IMAGE_ID, ++ .image_id = HW_CONFIG_ID, ++ SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, ++ VERSION_2, entry_point_info_t, ++ NON_SECURE | NON_EXECUTABLE), ++ SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, ++ VERSION_2, image_info_t, ++ IMAGE_ATTRIB_SKIP_LOADING), ++ ++ .next_handoff_image_id = INVALID_IMAGE_ID, + }, + ++ /* Fill TOS_FW_CONFIG related information if it exists */ + { +- .image_id = TOS_FW_CONFIG_ID, +- SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, +- VERSION_2, entry_point_info_t, +- SECURE | NON_EXECUTABLE), +- SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, +- VERSION_2, image_info_t, +- IMAGE_ATTRIB_SKIP_LOADING), +- +- .next_handoff_image_id = INVALID_IMAGE_ID, ++ .image_id = TOS_FW_CONFIG_ID, ++ SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, ++ VERSION_2, entry_point_info_t, ++ SECURE | NON_EXECUTABLE), ++ SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, ++ VERSION_2, image_info_t, ++ IMAGE_ATTRIB_SKIP_LOADING), ++ ++ .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* Fill BL33 related information */ +diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk +index 067e1fff9f..55acd67422 100644 +--- a/plat/st/stm32mp1/platform.mk ++++ b/plat/st/stm32mp1/platform.mk +@@ -15,7 +15,7 @@ USE_COHERENT_MEM := 0 + STM32MP_USE_STM32IMAGE ?= 0 + + # Add specific ST version +-ST_VERSION := r1.0 ++ST_VERSION := r2.0 + ifeq ($(STM32MP_USE_STM32IMAGE),1) + ST_VERSION := ${ST_VERSION}-nofip + endif +@@ -107,8 +107,14 @@ BL32_DTSI := stm32mp15-bl32.dtsi + FDT_SOURCES += $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME))) + endif + endif ++ ++$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) ++$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) + DTC_CPPFLAGS += ${INCLUDES} + DTC_FLAGS += -Wno-unit_address_vs_reg ++ifeq ($(shell test $(DTC_VERSION) -ge 10601; echo $$?),0) ++DTC_FLAGS += -Wno-interrupt_provider ++endif + + # Macros and rules to build TF binary + STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed +@@ -129,7 +135,7 @@ STM32IMAGE_SRC := ${STM32IMAGEPATH}/stm32image.c + + ifneq (${STM32MP_USE_STM32IMAGE},1) + FIP_DEPS += dtbs +-STM32MP_NT_FW_CONFIG := ${BL33_CFG} ++STM32MP_HW_CONFIG := ${BL33_CFG} + STM32MP_FW_CONFIG_NAME := $(patsubst %.dtb,%-fw-config.dtb,$(DTB_FILE_NAME)) + STM32MP_FW_CONFIG := ${BUILD_PLAT}/fdts/$(STM32MP_FW_CONFIG_NAME) + ifneq (${AARCH32_SP},none) +@@ -137,8 +143,8 @@ FDT_SOURCES += $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32MP_FW_CONFIG_NA + endif + # Add the FW_CONFIG to FIP and specify the same to certtool + $(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_FW_CONFIG},--fw-config)) +-# Add the NT_FW_CONFIG to FIP and specify the same to certtool +-$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_NT_FW_CONFIG},--hw-config)) ++# Add the HW_CONFIG to FIP and specify the same to certtool ++$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_HW_CONFIG},--hw-config)) + ifeq (${GENERATE_COT},1) + $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) + endif +@@ -212,6 +218,8 @@ PLAT_BL_COMMON_SOURCES := common/fdt_wrappers.c \ + plat/st/common/stm32mp_common.c \ + plat/st/stm32mp1/stm32mp1_private.c + ++PLAT_BL_COMMON_SOURCES += drivers/regulator/regulator_core.c ++ + PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S + + ifneq (${ENABLE_STACK_PROTECTOR},0) +@@ -236,8 +244,6 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \ + drivers/st/iwdg/stm32_iwdg.c \ + drivers/st/pmic/stm32mp_pmic.c \ + drivers/st/pmic/stpmic1.c \ +- drivers/st/regulator/stm32mp_dummy_regulator.c \ +- drivers/st/regulator/stm32mp_regulator.c \ + drivers/st/reset/stm32mp1_reset.c \ + plat/st/common/stm32mp_dt.c \ + plat/st/common/stm32mp_shres_helpers.c \ +@@ -363,7 +369,8 @@ BL2_SOURCES += drivers/st/usb_dwc2/usb_dwc2.c \ + plat/st/stm32mp1/stm32mp1_usb.c + endif + +-BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \ ++BL2_SOURCES += drivers/st/ddr/stm32mp_ddr_test.c \ ++ drivers/st/ddr/stm32mp1_ddr.c \ + drivers/st/ddr/stm32mp1_ram.c + + BL2_SOURCES += common/desc_image_load.c \ +@@ -409,8 +416,6 @@ clean_stm32image: + ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean + + check_dtc_version: +- $(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) +- $(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) + @if [ ${DTC_VERSION} -lt 10404 ]; then \ + echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \ + false; \ +diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c +index e3d845d2ec..633e63eb31 100644 +--- a/plat/st/stm32mp1/services/bsec_svc.c ++++ b/plat/st/stm32mp1/services/bsec_svc.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -87,16 +88,18 @@ static enum bsec_ssp_status bsec_check_ssp(uint32_t otp, uint32_t update) + sizeof(boot_api_ssp_config_t)); + #endif + if (dt_pmic_status() > 0) { +- const char *name; ++ struct rdev *regul; + + initialize_pmic(); + +- name = stm32mp_get_cpu_supply_name(); +- if (name == NULL) { ++ regul = dt_get_cpu_regulator(); ++ if (regul == NULL) { + return BSEC_SSP_ERROR; + } + +- stpmic1_regulator_mask_reset_set(name); ++ if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { ++ return BSEC_SSP_ERROR; ++ } + } + + return BSEC_SSP_SET; +diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk +index dd81d13a08..99575f5666 100644 +--- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk ++++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk +@@ -17,6 +17,7 @@ BL32_CFLAGS += -DSTM32MP_SHARED_RESOURCES + + BL32_SOURCES += drivers/st/clk/stm32mp1_calib.c \ + drivers/st/etzpc/etzpc.c \ ++ drivers/st/regulator/regulator_fixed.c \ + drivers/st/rng/stm32_rng.c \ + drivers/st/rtc/stm32_rtc.c \ + drivers/st/tamper/stm32_tamp.c \ +diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c +index 0065be44fd..d408b76523 100644 +--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c ++++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -18,8 +18,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include +@@ -51,43 +53,26 @@ + static entry_point_info_t bl33_image_ep_info; + + static console_t console; +-static void stm32mp1_tamper_action(int id); +- +-static const char *tamper_name[PLAT_MAX_TAMP_INT] = { +- "RTC power domain", +- "Temperature monitoring", +- "LSE monitoring", +- "HSE monitoring", +- "RTC calendar overflow", +- "Monotonic counter" +-}; ++static struct dt_node_info dt_uart_info; + +-static struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT] = { +- { +- .id = ITAMP1, +- .func = stm32mp1_tamper_action, +- }, +- { +- .id = ITAMP2, +- .func = stm32mp1_tamper_action, +- }, +- { +- .id = ITAMP3, +- .func = stm32mp1_tamper_action, +- }, +- { +- .id = ITAMP4, +- .func = stm32mp1_tamper_action, +- }, +- TAMP_UNUSED, +- TAMP_UNUSED, ++static const char * const tamper_name[] = { ++ [INT_TAMP1] = "RTC power domain", ++ [INT_TAMP2] = "Temperature monitoring", ++ [INT_TAMP3] = "LSE monitoring", ++ [INT_TAMP4] = "HSE monitoring", + }; + +-static struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT] = { +- TAMP_UNUSED, +- TAMP_UNUSED, +- TAMP_UNUSED, +-}; ++static int stm32mp1_tamper_action(int id) ++{ ++ const char *tamp_name = NULL; ++ ++ if ((id >= 0) && ((size_t)id < ARRAY_SIZE(tamper_name))) { ++ tamp_name = tamper_name[id]; ++ } ++ ERROR("Tamper %u (%s) occurs\n", id, tamp_name); ++ ++ return 1; /* ack TAMPER and reset system */ ++} + + static void stm32_sgi1_it_handler(void) + { +@@ -114,12 +99,6 @@ static void stm32_sgi1_it_handler(void) + stm32mp_wait_cpu_reset(); + } + +-static void stm32mp1_tamper_action(int id) +-{ +- ERROR("Tamper %s occurs\n", tamper_name[id]); +- stm32mp_system_reset(); +-} +- + static void configure_wakeup_interrupt(void) + { + int irq_num = fdt_rcc_enable_it("wakeup"); +@@ -141,14 +120,15 @@ static void initialize_pll1_settings(void) + } + + if (dt_pmic_status() > 0) { +- const char *name = stm32mp_get_cpu_supply_name(); ++ struct rdev *regul; + int ret; + +- if (name == NULL) { ++ regul = dt_get_cpu_regulator(); ++ if (regul == NULL) { + panic(); + } + +- ret = stpmic1_regulator_voltage_get(name); ++ ret = regulator_get_voltage(regul); + if (ret < 0) { + panic(); + } +@@ -164,16 +144,18 @@ static void initialize_pll1_settings(void) + static void disable_usb_phy_regulator(void) + { + if (dt_pmic_status() > 0) { +- const char *name = stm32mp_get_usb_phy_supply_name(); ++ struct rdev *regul = dt_get_usb_phy_regulator(); + int ret; + +- if (name == NULL) { ++ if (regul == NULL) { + return; + } + +- ret = stpmic1_regulator_disable(name); +- if (ret < 0) { +- WARN("USBPHYC phy-supply (%s) disable failed\n", name); ++ if (regulator_is_enabled(regul) == 1) { ++ ret = regulator_disable(regul); ++ if (ret < 0) { ++ WARN("USBPHYC phy-supply (%s) disable failed\n", regul->reg_name); ++ } + } + } + } +@@ -262,6 +244,7 @@ static uintptr_t get_saved_pc(void) + entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) + { + entry_point_info_t *next_image_info = &bl33_image_ep_info; ++ unsigned int console_flags; + + /* + * PC is set to 0 when resetting after STANDBY +@@ -276,6 +259,16 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) + panic(); + } + ++ console_flags = CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF; ++ if ((clk_is_enabled(dt_uart_info.clock)) && ++ (clk_get_rate(dt_uart_info.clock) != 0U)) { ++ console_flags |= CONSOLE_FLAG_BOOT; ++#ifdef DEBUG ++ console_flags |= CONSOLE_FLAG_RUNTIME; ++#endif ++ } ++ console_set_scope(&console, console_flags); ++ + cpu_context = cm_get_context(NON_SECURE); + + next_image_info->spsr = read_ctx_reg(get_regs_ctx(cpu_context), +@@ -291,6 +284,8 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) + next_image_info->pc = + read_ctx_reg(get_regs_ctx(cpu_context), CTX_LR); + } ++ ++ regulator_core_resume(); + } + + return next_image_info; +@@ -327,17 +322,12 @@ static void stm32mp1_etzpc_early_setup(void) + etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_SYSRAM, TZMA1_SECURE_RANGE); + } + +-#if !STM32MP_USE_STM32IMAGE ++#if STM32MP_SP_MIN_IN_DDR + static void populate_ns_dt(u_register_t ns_dt_addr, uintptr_t sec_base, size_t sec_size) + { + void *external_fdt = (void *)ns_dt_addr; + int ret; + +- if (sec_base < STM32MP_DDR_BASE) { +- /* No need to reserve memory if secure monitor is not in DDR */ +- return; +- } +- + /* Map Base Non Secure DDR for Non secure DT update */ + ret = mmap_add_dynamic_region(ns_dt_addr, ns_dt_addr, STM32MP_HW_CONFIG_MAX_SIZE, + MT_NON_CACHEABLE | MT_EXECUTE_NEVER | MT_RW | MT_NS); +@@ -377,7 +367,6 @@ out: + ******************************************************************************/ + static void setup_uart_console(void) + { +- struct dt_node_info dt_uart_info; + unsigned int console_flags; + int result; + uint32_t boot_itf; +@@ -419,10 +408,9 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + uintptr_t dt_addr = STM32MP_DTB_BASE; + #else + uintptr_t dt_addr = arg1; +- uintptr_t sec_base = 0U; +- size_t sec_size = 0U; + #endif + #if STM32MP_SP_MIN_IN_DDR ++ uintptr_t sec_base = 0U; + uintptr_t bl2_code_base = 0U; + uintptr_t bl2_code_end = 0U; + uintptr_t bl2_end = 0U; +@@ -511,36 +499,41 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + } + } + +-#if !STM32MP_USE_STM32IMAGE ++#if STM32MP_SP_MIN_IN_DDR + if (bl_params->image_id == BL32_IMAGE_ID) { + sec_base = bl_params->image_info->image_base; +- sec_size = bl_params->image_info->image_max_size; + } + #endif + + bl_params = bl_params->next_params_info; + } + +-#if !STM32MP_USE_STM32IMAGE ++#if STM32MP_SP_MIN_IN_DDR + if (arg2 != 0U) { + /* This will expect the BL32 DT and BL32 are grouped */ + if (dt_addr < sec_base) { +- sec_size = sec_size + sec_base - dt_addr; + sec_base = dt_addr; +- } else { +- sec_size = dt_addr - sec_base + STM32MP_BL32_DTB_SIZE; + } + +- populate_ns_dt(arg2, sec_base, sec_size); ++ populate_ns_dt(arg2, sec_base, DDR_SEC_SIZE); + } else { + INFO("Non-secure device tree not found\n"); + } + #endif + ++ generic_delay_timer_init(); ++ + if (dt_pmic_status() > 0) { + initialize_pmic(); + } + ++ fixed_regulator_register(); ++ ++ if (regulator_core_config() != 0) { ++ ERROR("Regulator core config error\n"); ++ panic(); ++ } ++ + disable_usb_phy_regulator(); + + initialize_pll1_settings(); +@@ -550,8 +543,6 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + + static void init_sec_peripherals(void) + { +- uint32_t filter_conf = 0; +- uint32_t active_conf = 0; + int ret; + + /* Disable MCU subsystem protection */ +@@ -571,9 +562,28 @@ static void init_sec_peripherals(void) + + /* Init tamper */ + if (stm32_tamp_init() > 0) { +- stm32_tamp_configure_internal(int_tamp, PLAT_MAX_TAMP_INT); +- stm32_tamp_configure_external(ext_tamp, PLAT_MAX_TAMP_EXT, +- filter_conf, active_conf); ++ struct bkpregs_conf bkpregs_conf = { ++ .nb_zone1_regs = TAMP_BKP_SEC_NUMBER, ++ .nb_zone2_regs = 0 /* no register in zone 2 */ ++ /* zone3 all remaining */ ++ }; ++ ++ /* Enable BKP Register protection */ ++ if (stm32_tamp_set_secure_bkpregs(&bkpregs_conf) < 0) { ++ panic(); ++ } ++ ++ stm32_tamp_configure_secure_access(TAMP_REGS_IT_SECURE); ++ ++ stm32_tamp_configure_internal(INT_TAMP1, TAMP_ENABLE, stm32mp1_tamper_action); ++ stm32_tamp_configure_internal(INT_TAMP2, TAMP_ENABLE, stm32mp1_tamper_action); ++ stm32_tamp_configure_internal(INT_TAMP3, TAMP_ENABLE, stm32mp1_tamper_action); ++ stm32_tamp_configure_internal(INT_TAMP4, TAMP_ENABLE, stm32mp1_tamper_action); ++ ++ ret = stm32_tamp_set_config(); ++ if (ret < 0) { ++ panic(); ++ } + + /* Enable timestamp for tamper */ + stm32_rtc_set_tamper_timestamp(); +@@ -593,8 +603,6 @@ void sp_min_platform_setup(void) + + ddr_save_sr_mode(); + +- generic_delay_timer_init(); +- + stm32_gic_init(); + + init_sec_peripherals(); +@@ -608,6 +616,11 @@ void sp_min_platform_setup(void) + stm32mp_lock_periph_registering(); + + stm32mp1_init_scmi_server(); ++ ++ /* Cold boot: clean-up regulators state */ ++ if (get_saved_pc() == 0U) { ++ regulator_core_cleanup(); ++ } + } + + void sp_min_plat_arch_setup(void) +diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c +index 027475ed40..1705c15258 100644 +--- a/plat/st/stm32mp1/stm32mp1_context.c ++++ b/plat/st/stm32mp1/stm32mp1_context.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -92,6 +93,7 @@ struct backup_bl32_data_s { + unsigned long long stgen; + uint8_t clock_cfg[CLOCK_CONTEXT_SIZE]; + uint8_t scmi_context[SCMI_CONTEXT_SIZE]; ++ uint8_t regul_context[PLAT_BACKUP_REGULATOR_SIZE]; + }; + + static struct backup_bl32_data_s *get_bl32_backup_data(void) +@@ -101,7 +103,7 @@ static struct backup_bl32_data_s *get_bl32_backup_data(void) + } + + #if STM32MP_SP_MIN_IN_DDR +-void (*stm32_pwr_down_wfi)(bool is_cstop); ++void (*stm32_pwr_down_wfi)(bool is_cstop, uint32_t mode); + #endif + #endif + +@@ -227,6 +229,9 @@ int stm32_save_context(uint32_t zq0cr0_zdata, + + save_clock_pm_context(); + ++ regulator_core_backup_context(backup_bl32_data->regul_context, ++ sizeof(backup_bl32_data->regul_context)); ++ + clk_disable(BKPSRAM); + + return 0; +@@ -279,6 +284,9 @@ int stm32_restore_context(void) + &backup_bl32_data->rtc); + stm32mp_stgen_restore_counter(backup_bl32_data->stgen, stdby_time_in_ms); + ++ regulator_core_restore_context(backup_bl32_data->regul_context, ++ sizeof(backup_bl32_data->regul_context)); ++ + clk_disable(BKPSRAM); + + stm32mp1_clock_resume(); +@@ -317,7 +325,7 @@ void stm32_context_get_bl2_low_power_params(uintptr_t *bl2_code_base, + } + + #if STM32MP_SP_MIN_IN_DDR +- stm32_pwr_down_wfi = (void (*)(bool))backup_data->low_power_ep; ++ stm32_pwr_down_wfi = (void (*)(bool, uint32_t))backup_data->low_power_ep; + #endif + *bl2_code_base = (uintptr_t)backup_data->bl2_code_base; + *bl2_code_end = (uintptr_t)backup_data->bl2_code_end; +@@ -463,6 +471,8 @@ void stm32_save_ddr_training_area(void) + PAGE_SIZE, MT_MEMORY | MT_RW | MT_NS); + assert(ret == 0); + ++ flush_dcache_range(STM32MP_DDR_BASE, TRAINING_AREA_SIZE); ++ + memcpy(&backup_data->ddr_training_backup, + (const uint32_t *)STM32MP_DDR_BASE, + TRAINING_AREA_SIZE); +diff --git a/plat/st/stm32mp1/stm32mp1_critic_power.c b/plat/st/stm32mp1/stm32mp1_critic_power.c +index 583cf93fad..aad11fa508 100644 +--- a/plat/st/stm32mp1/stm32mp1_critic_power.c ++++ b/plat/st/stm32mp1/stm32mp1_critic_power.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,19 +10,38 @@ + #include + #include + #include ++#include + #include ++#include + ++#include + #include + +-static void cstop_critic_enter(void) ++static void cstop_critic_enter(uint32_t mode) + { ++ /* Switch to Software Self-Refresh mode */ ++ ddr_set_sr_mode(DDR_SSR_MODE); ++ + /* + * Set DDR in Self-refresh,. + * This is also the procedure awaited when switching off power supply. + */ + if (ddr_standby_sr_entry() != 0) { + ERROR("Unable to put DDR in SR\n"); +- panic(); ++ if (mode != STM32_PM_SHUTDOWN) { ++ panic(); ++ } ++ } ++} ++ ++static void shutdown_critic_enter(void) ++{ ++ if (dt_pmic_status() > 0) { ++ if (!initialize_pmic_i2c()) { ++ panic(); ++ } ++ ++ pmic_switch_off(); + } + } + +@@ -36,10 +55,18 @@ static void cstop_critic_exit(void) + } + } + +-void stm32_pwr_down_wfi_load(bool is_cstop) ++void stm32_pwr_down_wfi_load(bool is_cstop, uint32_t mode) + { ++ if (mode != STM32_PM_CSLEEP_RUN) { ++ dcsw_op_all(DC_OP_CISW); ++ } ++ + if (is_cstop) { +- cstop_critic_enter(); ++ cstop_critic_enter(mode); ++ } ++ ++ if (mode == STM32_PM_SHUTDOWN) { ++ shutdown_critic_enter(); + } + + /* +@@ -61,12 +88,20 @@ void stm32_pwr_down_wfi_load(bool is_cstop) + extern void wfi_svc_int_enable(uintptr_t stack_addr); + static uint32_t int_stack[STM32MP_INT_STACK_SIZE]; + +-void stm32_pwr_down_wfi(bool is_cstop) ++void stm32_pwr_down_wfi(bool is_cstop, uint32_t mode) + { + uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; + ++ if (mode != STM32_PM_CSLEEP_RUN) { ++ dcsw_op_all(DC_OP_CISW); ++ } ++ + if (is_cstop) { +- cstop_critic_enter(); ++ cstop_critic_enter(mode); ++ } ++ ++ if (mode == STM32_PM_SHUTDOWN) { ++ shutdown_critic_enter(); + } + + stm32mp1_calib_set_wakeup(false); +diff --git a/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S b/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S +index 2c4dd844d2..514def2fc4 100644 +--- a/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S ++++ b/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -21,6 +21,9 @@ + func stm32_pwr_down_wfi_wrapper + push {r4,r5,r6,lr} + ++ # Save r0 and r1 in r2 and r3, as they are used in disable_mmu_secure ++ mov r2, r0 ++ mov r3, r1 + # Save current sp in r4 + mov r4, sp + # Save current VBAR in r5 +@@ -34,20 +37,21 @@ func stm32_pwr_down_wfi_wrapper + stcopr r1, MVBAR + + # Set sp to BL2 STACK (as BL2 is not using it anymore) +- ldr sp, =__STACKS_END__ ++ ldr sp, =__STACKS_END__ + + # Disable MMU as TLB are still stored in DDR, + # and in few instructions DDR won't be readable +- bl disable_mmu_secure ++ bl disable_mmu_secure + + # dsb is done in disable mmu + # isb is done in disable mmu + +- # We didn't change R0 to keep it as first parameter +- bl stm32_pwr_down_wfi_load ++ mov r0, r2 ++ mov r1, r3 ++ bl stm32_pwr_down_wfi_load + + # Restore stack +- mov sp, r4 ++ mov sp, r4 + # Restore VBAR + stcopr r5, VBAR + # Restore MVBAR +diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h +index 326b227842..780d124d17 100644 +--- a/plat/st/stm32mp1/stm32mp1_def.h ++++ b/plat/st/stm32mp1/stm32mp1_def.h +@@ -162,8 +162,8 @@ enum ddr_type { + #define STM32MP_BL2_RO_SIZE U(0x00014000) /* 80 KB */ + #define STM32MP_BL2_SIZE U(0x0001B000) /* 108 KB for BL2 */ + #else +-#define STM32MP_BL2_RO_SIZE U(0x00010000) /* 64 KB */ +-#define STM32MP_BL2_SIZE U(0x00015000) /* 84 KB for BL2 */ ++#define STM32MP_BL2_RO_SIZE U(0x00011000) /* 68 KB */ ++#define STM32MP_BL2_SIZE U(0x00016000) /* 88 KB for BL2 */ + #endif + + #define STM32MP_BL2_BASE (STM32MP_SEC_SYSRAM_BASE + \ +@@ -182,7 +182,7 @@ enum ddr_type { + #if STM32MP_SP_MIN_IN_DDR + #define STM32MP_BL32_SIZE U(0x00025000) /* 148 KB for BL32 */ + #else +-#define STM32MP_BL32_SIZE U(0x0001A000) /* 100 KB for BL32 */ ++#define STM32MP_BL32_SIZE U(0x0001B000) /* 108 KB for BL32 */ + #endif + #endif /* STM32MP_USE_STM32IMAGE */ + #endif /* STM32MP_SSP */ +@@ -265,10 +265,14 @@ enum ddr_type { + STM32MP_BL2_DTB_SIZE) + + #define STM32MP_BL32_DTB_SIZE U(0x00005000) /* 20 KB for DTB */ ++#if STM32MP_SP_MIN_IN_DDR ++#define DDR_SEC_SIZE U(0x02000000) /* 32MB */ ++#else + #define STM32MP_BL32_DTB_BASE STM32MP_SYSRAM_BASE + + #define STM32MP_BL32_BASE (STM32MP_BL32_DTB_BASE + \ + STM32MP_BL32_DTB_SIZE) ++#endif + + #if defined(IMAGE_BL2) + #define STM32MP_DTB_SIZE STM32MP_BL2_DTB_SIZE +@@ -581,11 +585,8 @@ enum ddr_type { + #define PLAT_MAX_TAMP_INT U(6) + #define PLAT_MAX_TAMP_EXT U(3) + #define TAMP_BASE U(0x5C00A000) +-#define TAMP_SMCR (TAMP_BASE + U(0x20)) + #define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100)) + #define TAMP_BKP_SEC_NUMBER U(10) +-#define TAMP_BKP_SEC_WDPROT_SHIFT U(16) +-#define TAMP_BKP_SEC_RWDPROT_SHIFT U(0) + + + #if !(defined(__LINKER__) || defined(__ASSEMBLER__)) +@@ -650,6 +651,16 @@ static inline uint32_t tamp_bkpr(uint32_t idx) + #define PLAT_MAX_OPP_NB U(2) + #define PLAT_MAX_PLLCFG_NB U(6) + ++/******************************************************************************* ++ * REGULATORS ++ ******************************************************************************/ ++/* 3 PWR + 1 VREFBUF + 14 PMIC regulators + 1 FIXED */ ++#define PLAT_NB_RDEVS U(19) ++/* Number of low power modes defined in the device tree */ ++#define PLAT_NB_SUSPEND_MODES 7 ++/* 1 FIXED */ ++#define PLAT_NB_FIXED_REGS U(1) ++ + /******************************************************************************* + * DEBUG + ******************************************************************************/ +diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S +index 315a67f2cf..da3ab1562b 100644 +--- a/plat/st/stm32mp1/stm32mp1_helper.S ++++ b/plat/st/stm32mp1/stm32mp1_helper.S +@@ -251,12 +251,12 @@ func plat_crash_console_init + str r2, [r1] + 1: + ldr r0, [r1] +- ands r0, r2 ++ ands r2, r0, r2 + beq 1b + str r2, [r1, #4] /* RSTCLR register */ + 2: + ldr r0, [r1] +- ands r0, r2 ++ ands r2, r0, r2 + bne 2b + /* Enable GPIOs for UART TX */ + ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) +diff --git a/plat/st/stm32mp1/stm32mp1_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c +index ae6fd88c88..82e2de710c 100644 +--- a/plat/st/stm32mp1/stm32mp1_low_power.c ++++ b/plat/st/stm32mp1/stm32mp1_low_power.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -104,6 +105,11 @@ static struct spinlock lp_lock; + static volatile int cpu0_state = STATE_NONE; + static volatile int cpu1_state = STATE_NONE; + ++const char *plat_get_lp_mode_name(int mode) ++{ ++ return config_pwr[mode].regul_suspend_node_name; ++} ++ + void stm32_apply_pmic_suspend_config(uint32_t mode) + { + const char *node_name; +@@ -116,14 +122,6 @@ void stm32_apply_pmic_suspend_config(uint32_t mode) + if (!initialize_pmic_i2c()) { + panic(); + } +- +- if (pmic_set_lp_config(node_name) < 0) { +- panic(); +- } +- +- if (pmic_configure_boot_on_regulators() < 0) { +- panic(); +- } + } + } + +@@ -147,11 +145,6 @@ static void enter_cstop(uint32_t mode, uint32_t nsec_addr) + + stm32mp1_syscfg_disable_io_compensation(); + +- /* Switch to Software Self-Refresh mode */ +- ddr_set_sr_mode(DDR_SSR_MODE); +- +- dcsw_op_all(DC_OP_CISW); +- + stm32_clean_context(); + + if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) { +@@ -170,6 +163,8 @@ static void enter_cstop(uint32_t mode, uint32_t nsec_addr) + } + } + ++ regulator_core_suspend(mode); ++ + /* Clear RCC interrupt before enabling it */ + mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF); + +@@ -289,6 +284,8 @@ void stm32_exit_cstop(void) + panic(); + } + ++ regulator_core_resume(); ++ + stm32mp1_syscfg_enable_io_compensation_finish(); + } + +@@ -348,7 +345,7 @@ static void stm32_auto_stop_cpu0(void) + + enter_cstop(STM32_PM_CSTOP_ALLOW_LP_STOP, 0); + +- stm32_pwr_down_wfi(true); ++ stm32_pwr_down_wfi(true, STM32_PM_CSTOP_ALLOW_LP_STOP); + + stm32_exit_cstop(); + +@@ -380,27 +377,6 @@ void stm32_auto_stop(void) + } + } + +-static void enter_shutdown(void) +-{ +- /* Set DDR in Self-refresh before shutting down the platform */ +- if (ddr_standby_sr_entry() != 0) { +- WARN("DDR can't be set in Self-refresh mode\n"); +- } +- +- if (dt_pmic_status() > 0) { +- if (!initialize_pmic_i2c()) { +- panic(); +- } +- +- stpmic1_switch_off(); +- +- udelay(100); +- +- /* Shouldn't be reached */ +- panic(); +- } +-} +- + static void enter_csleep(void) + { + uintptr_t pwr_base = stm32mp_pwr_base(); +@@ -410,14 +386,13 @@ static void enter_csleep(void) + mmio_clrsetbits_32(pwr_base + PWR_CR1, PWR_CR1_MASK, + config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1); + +- stm32_pwr_down_wfi(false); ++ stm32_pwr_down_wfi(false, STM32_PM_CSLEEP_RUN); + } + + void stm32_enter_low_power(uint32_t mode, uint32_t nsec_addr) + { + switch (mode) { + case STM32_PM_SHUTDOWN: +- enter_shutdown(); + break; + + case STM32_PM_CSLEEP_RUN: +diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c +index 962a992243..e5f622a5be 100644 +--- a/plat/st/stm32mp1/stm32mp1_pm.c ++++ b/plat/st/stm32mp1/stm32mp1_pm.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -169,7 +169,8 @@ static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t + void (*warm_entrypoint)(void) = + (void (*)(void))stm32_sec_entrypoint; + +- stm32_pwr_down_wfi(stm32_is_cstop_done()); ++ stm32_pwr_down_wfi(stm32_is_cstop_done(), ++ stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND)); + + stm32_exit_cstop(); + +@@ -207,7 +208,7 @@ static void __dead2 stm32_system_off(void) + + stm32_enter_low_power(soc_mode, 0); + +- stm32_pwr_down_wfi(false); ++ stm32_pwr_down_wfi(true, soc_mode); + + /* This shouldn't be reached */ + panic(); +diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c +index 09afe1a6ea..0451efe72f 100644 +--- a/plat/st/stm32mp1/stm32mp1_private.c ++++ b/plat/st/stm32mp1/stm32mp1_private.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,11 +13,9 @@ + #include + #include + #include ++#include + #include +-#include + #include +-#include +-#include + #include + #include + #include +@@ -165,110 +163,6 @@ void __dead2 stm32mp_wait_cpu_reset(void) + } + } + +-/* +- * tzc_source_ip contains the TZC transaction source IPs that need to be reset +- * before a C-A7 subsystem is reset (i.e. independent reset): +- * - C-A7 subsystem is reset separately later in the sequence, +- * - C-M4 subsystem is not concerned here, +- * - DAP is excluded for debug purpose, +- * - IPs are stored with their ETZPC IDs (STM32MP1_ETZPC_MAX_ID if not +- * applicable) because some of them need to be reset only if they are not +- * configured in MCU isolation mode inside ETZPC device tree. +- */ +-struct tzc_source_ip { +- uint32_t reset_id; +- uint32_t clock_id; +- uint32_t decprot_id; +-}; +- +-#define _TZC_FIXED(res, clk) \ +- { \ +- .reset_id = (res), \ +- .clock_id = (clk), \ +- .decprot_id = STM32MP1_ETZPC_MAX_ID, \ +- } +- +-#define _TZC_COND(res, clk, decprot) \ +- { \ +- .reset_id = (res), \ +- .clock_id = (clk), \ +- .decprot_id = (decprot), \ +- } +- +-static const struct tzc_source_ip tzc_source_ip[] = { +- _TZC_FIXED(LTDC_R, LTDC_PX), +- _TZC_FIXED(GPU_R, GPU), +- _TZC_FIXED(USBH_R, USBH), +- _TZC_FIXED(SDMMC1_R, SDMMC1_K), +- _TZC_FIXED(SDMMC2_R, SDMMC2_K), +- _TZC_FIXED(MDMA_R, MDMA), +- _TZC_COND(USBO_R, USBO_K, STM32MP1_ETZPC_OTG_ID), +- _TZC_COND(SDMMC3_R, SDMMC3_K, STM32MP1_ETZPC_SDMMC3_ID), +- _TZC_COND(ETHMAC_R, ETHMAC, STM32MP1_ETZPC_ETH_ID), +- _TZC_COND(DMA1_R, DMA1, STM32MP1_ETZPC_DMA1_ID), +- _TZC_COND(DMA2_R, DMA2, STM32MP1_ETZPC_DMA2_ID), +-}; +- +-#define TIMEOUT_US_1MS U(1000) +- +-void __dead2 stm32mp_plat_reset(int cpu) +-{ +- uint32_t reg = RCC_MP_GRSTCSETR_MPUP0RST; +- uint32_t id; +- +- /* Mask timer interrupts */ +- stm32mp_mask_timer(); +- +- for (id = 0U; id < ARRAY_SIZE(tzc_source_ip); id++) { +- if ((!clk_is_enabled(tzc_source_ip[id].clock_id)) || +- ((tzc_source_ip[id].decprot_id != STM32MP1_ETZPC_MAX_ID) && +- (etzpc_get_decprot(tzc_source_ip[id].decprot_id) == +- ETZPC_DECPROT_MCU_ISOLATION))) { +- continue; +- } +- +- if (tzc_source_ip[id].reset_id != GPU_R) { +- uint32_t reset = tzc_source_ip[id].reset_id; +- int ret; +- +- ret = stm32mp_reset_assert(reset, TIMEOUT_US_1MS); +- if (ret != 0) { +- panic(); +- } +- ret = stm32mp_reset_deassert(reset, TIMEOUT_US_1MS); +- if (ret != 0) { +- panic(); +- } +- } else { +- /* GPU reset automatically cleared by hardware */ +- mmio_setbits_32(stm32mp_rcc_base() + RCC_AHB6RSTSETR, +- RCC_AHB6RSTSETR_GPURST); +- } +- } +- +- if (!stm32mp_is_single_core()) { +- unsigned int sec_cpu = (cpu == STM32MP_PRIMARY_CPU) ? +- STM32MP_SECONDARY_CPU : STM32MP_PRIMARY_CPU; +- +- gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, sec_cpu); +- reg |= RCC_MP_GRSTCSETR_MPUP1RST; +- } +- +- do { +- id = plat_ic_get_pending_interrupt_id(); +- +- if (id <= MAX_SPI_ID) { +- gicv2_end_of_interrupt(id); +- +- plat_ic_disable_interrupt(id); +- } +- } while (id <= MAX_SPI_ID); +- +- mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, reg); +- +- stm32mp_wait_cpu_reset(); +-} +- + uintptr_t stm32_get_gpio_bank_base(unsigned int bank) + { + if (bank == GPIO_BANK_Z) { +@@ -291,6 +185,15 @@ uint32_t stm32_get_gpio_bank_offset(unsigned int bank) + return bank * GPIO_BANK_OFFSET; + } + ++bool stm32_gpio_is_secure_at_reset(unsigned int bank) ++{ ++ if (bank == GPIO_BANK_Z) { ++ return true; ++ } ++ ++ return false; ++} ++ + #if STM32MP_UART_PROGRAMMER || defined(IMAGE_BL32) + /* + * UART Management +@@ -317,6 +220,53 @@ uintptr_t get_uart_address(uint32_t instance_nb) + } + #endif + ++#if STM32MP_USB_PROGRAMMER ++struct gpio_bank_pin_list { ++ uint32_t bank; ++ uint32_t pin; ++}; ++ ++static const struct gpio_bank_pin_list gpio_list[] = { ++ { /* USART2_RX: GPIOA3 */ ++ .bank = 0, ++ .pin = 3, ++ }, ++ { /* USART3_RX: GPIOB12 */ ++ .bank = 1, ++ .pin = 12, ++ }, ++ { /* UART4_RX: GPIOB2 */ ++ .bank = 1, ++ .pin = 2, ++ }, ++ { /* UART5_RX: GPIOB4 */ ++ .bank = 1, ++ .pin = 5, ++ }, ++ { /* USART6_RX: GPIOC7 */ ++ .bank = 2, ++ .pin = 7, ++ }, ++ { /* UART7_RX: GPIOF6 */ ++ .bank = 5, ++ .pin = 6, ++ }, ++ { /* UART8_RX: GPIOE0 */ ++ .bank = 4, ++ .pin = 0, ++ }, ++}; ++ ++void stm32mp1_deconfigure_uart_pins(void) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { ++ set_gpio_reset_cfg(gpio_list[i].bank, gpio_list[i].pin); ++ } ++} ++#endif ++ + unsigned long stm32_get_gpio_bank_clock(unsigned int bank) + { + if (bank == GPIO_BANK_Z) { +@@ -403,25 +353,38 @@ int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val) + return 0; + } + +-int stm32mp_get_chip_version(uint32_t *chip_version) ++uint32_t stm32mp_get_chip_version(void) + { +- return stm32mp1_dbgmcu_get_chip_version(chip_version); ++ uint32_t version = 0U; ++ ++ if (stm32mp1_dbgmcu_get_chip_version(&version) < 0) { ++ INFO("Cannot get CPU version, debug disabled\n"); ++ return 0U; ++ } ++ ++ return version; + } + +-static uint32_t get_part_number(void) ++uint32_t stm32mp_get_chip_dev_id(void) + { +- static uint32_t part_number; + uint32_t dev_id; + +- if (part_number != 0U) { +- return part_number; +- } +- + if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) { + INFO("Use default chip ID, debug disabled\n"); + dev_id = STM32MP1_CHIP_ID; + } + ++ return dev_id; ++} ++ ++static uint32_t get_part_number(void) ++{ ++ static uint32_t part_number; ++ ++ if (part_number != 0U) { ++ return part_number; ++ } ++ + if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) { + panic(); + } +@@ -429,7 +392,7 @@ static uint32_t get_part_number(void) + part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >> + PART_NUMBER_OTP_PART_SHIFT; + +- part_number |= dev_id << 16; ++ part_number |= stm32mp_get_chip_dev_id() << 16; + + return part_number; + } +@@ -477,8 +440,6 @@ bool stm32mp_supports_cpu_opp(uint32_t opp_id) + void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]) + { + char *cpu_s, *cpu_r, *pkg; +- uint32_t chip_dev_id; +- int ret; + + /* MPUs Part Numbers */ + switch (get_part_number()) { +@@ -543,12 +504,7 @@ void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]) + } + + /* REVISION */ +- ret = stm32mp_get_chip_version(&chip_dev_id); +- if (ret < 0) { +- INFO("Cannot get CPU version, debug disabled\n"); +- } +- +- switch (chip_dev_id) { ++ switch (stm32mp_get_chip_version()) { + case STM32MP1_REV_B: + cpu_r = "B"; + break; +@@ -732,29 +688,6 @@ enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) + } + } + +-int plat_bind_regulator(struct stm32mp_regulator *regu) +-{ +- void *fdt; +- int regu_node; +- +- if (fdt_get_address(&fdt) == 0) { +- return false; +- } +- +- if ((dt_pmic_status() > 0) && is_pmic_regulator(regu)) { +- bind_pmic_regulator(regu); +- } else { +- bind_dummy_regulator(regu); +- } +- +- regu_node = fdt_node_offset_by_phandle(fdt, regu->id); +- if (fdt_getprop(fdt, regu_node, "regulator-always-on", NULL) != NULL) { +- regu->always_on = true; +- } +- +- return 0; +-} +- + #if STM32MP_USE_STM32IMAGE + /* Get the non-secure DDR size */ + uint32_t stm32mp_get_ddr_ns_size(void) +@@ -789,9 +722,14 @@ bool stm32mp1_addr_inside_backupsram(uintptr_t addr) + + bool stm32mp1_is_wakeup_from_standby(void) + { ++ uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); + uint32_t bkpr_core1_addr = tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); + uint32_t nsec_address; + ++ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { ++ return false; ++ } ++ + if (stm32mp_get_boot_action() != BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY) { + return false; + } +diff --git a/plat/st/stm32mp1/stm32mp1_ssp.c b/plat/st/stm32mp1/stm32mp1_ssp.c +index bcbf374782..a60721691e 100644 +--- a/plat/st/stm32mp1/stm32mp1_ssp.c ++++ b/plat/st/stm32mp1/stm32mp1_ssp.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -803,24 +804,24 @@ static void ssp_start(boot_api_context_t *boot_context) + * the required MPSYSRST. + */ + if (dt_pmic_status() > 0) { +- const char *name; ++ struct rdev *regul; + +- name = stm32mp_get_cpu_supply_name(); +- if (name == NULL) { +- goto out; ++ regul = dt_get_cpu_regulator(); ++ if (regul == NULL) { ++ panic(); + } + +- if (stpmic1_regulator_mask_reset_set(name) != 0) { +- WARN("Failed to write %s reset mask\n", name); ++ if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { ++ WARN("Failed to write cpu-supply reset mask\n"); + } + +- name = stm32mp_get_vdd_supply_name(); +- if (name == NULL) { ++ regul = dt_get_vdd_regulator(); ++ if (regul == NULL) { + goto out; + } + +- if (stpmic1_regulator_mask_reset_set(name) != 0) { +- WARN("Failed to write %s reset mask\n", name); ++ if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { ++ WARN("Failed to write vdd-supply reset mask\n"); + } + } else { + static const char debug_msg[] = { +@@ -1028,7 +1029,7 @@ skip_console_init: + stm32_iwdg_refresh(); + + if (dt_pmic_status() > 0) { +- initialize_pmic(); ++ initialize_pmic_i2c(); + print_pmic_info_and_debug(); + } + +diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c +index 2c5fa082fc..b471be2096 100644 +--- a/plat/st/stm32mp1/stm32mp1_syscfg.c ++++ b/plat/st/stm32mp1/stm32mp1_syscfg.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -26,6 +26,9 @@ + #define SYSCFG_CMPENSETR 0x24U + #define SYSCFG_CMPENCLRR 0x28U + ++#define CMPCR_CMPENSETR_OFFSET 0x4U ++#define CMPCR_CMPENCLRR_OFFSET 0x8U ++ + /* + * SYSCFG_BOOTR Register + */ +@@ -63,25 +66,61 @@ + */ + #define SYSCFG_CMPENSETR_MPU_EN BIT(0) + +-void stm32mp1_syscfg_init(void) ++static void enable_io_comp_cell_finish(uintptr_t cmpcr_off) ++{ ++ uint64_t start; ++ ++ start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US); ++ ++ while ((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) { ++ if (timeout_elapsed(start)) { ++ /* Failure on IO compensation enable is not a issue: warn only. */ ++ WARN("IO compensation cell not ready\n"); ++ break; ++ } ++ } ++ ++ mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_SW_CTRL); ++} ++ ++static void disable_io_comp_cell(uintptr_t cmpcr_off) ++{ ++ uint32_t value; ++ ++ if (((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) || ++ ((mmio_read_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENSETR_OFFSET) & ++ SYSCFG_CMPENSETR_MPU_EN) == 0U)) { ++ return; ++ } ++ ++ value = mmio_read_32(SYSCFG_BASE + cmpcr_off) >> SYSCFG_CMPCR_ANSRC_SHIFT; ++ ++ mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); ++ ++ value <<= SYSCFG_CMPCR_RANSRC_SHIFT; ++ value |= mmio_read_32(SYSCFG_BASE + cmpcr_off); ++ ++ mmio_write_32(SYSCFG_BASE + cmpcr_off, value | SYSCFG_CMPCR_SW_CTRL); ++ ++ mmio_setbits_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENCLRR_OFFSET, SYSCFG_CMPENSETR_MPU_EN); ++} ++ ++static void enable_high_speed_mode_low_voltage(void) ++{ ++ mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, ++ SYSCFG_IOCTRLSETR_HSLVEN_TRACE | ++ SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | ++ SYSCFG_IOCTRLSETR_HSLVEN_ETH | ++ SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | ++ SYSCFG_IOCTRLSETR_HSLVEN_SPI); ++} ++ ++static void stm32mp1_syscfg_set_hslv(void) + { +- uint32_t bootr; + uint32_t otp_value; + uint32_t vdd_voltage; + bool product_below_2v5; + +- /* +- * Interconnect update : select master using the port 1. +- * LTDC = AXI_M9. +- */ +- mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); +- +- /* Disable Pull-Down for boot pin connected to VDD */ +- bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) & +- SYSCFG_BOOTR_BOOT_MASK; +- mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, +- bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); +- + /* + * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI + * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. +@@ -110,12 +149,7 @@ void stm32mp1_syscfg_init(void) + if (vdd_voltage == 0U) { + WARN("VDD unknown\n"); + } else if (vdd_voltage < 2700000U) { +- mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, +- SYSCFG_IOCTRLSETR_HSLVEN_TRACE | +- SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | +- SYSCFG_IOCTRLSETR_HSLVEN_ETH | +- SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | +- SYSCFG_IOCTRLSETR_HSLVEN_SPI); ++ enable_high_speed_mode_low_voltage(); + + if (!product_below_2v5) { + INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); +@@ -128,6 +162,25 @@ void stm32mp1_syscfg_init(void) + panic(); + } + } ++} ++ ++void stm32mp1_syscfg_init(void) ++{ ++ uint32_t bootr; ++ ++ /* ++ * Interconnect update : select master using the port 1. ++ * LTDC = AXI_M9. ++ */ ++ mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); ++ ++ /* Disable Pull-Down for boot pin connected to VDD */ ++ bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) & ++ SYSCFG_BOOTR_BOOT_MASK; ++ mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, ++ bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); ++ ++ stm32mp1_syscfg_set_hslv(); + + stm32mp1_syscfg_enable_io_compensation_start(); + } +@@ -141,35 +194,17 @@ void stm32mp1_syscfg_enable_io_compensation_start(void) + */ + stm32mp1_clk_force_enable(SYSCFG); + +- mmio_setbits_32(SYSCFG_BASE + SYSCFG_CMPENSETR, ++ mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPCR, + SYSCFG_CMPENSETR_MPU_EN); + } + + void stm32mp1_syscfg_enable_io_compensation_finish(void) + { +- uint64_t start; +- +- start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US); +- +- while ((mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) & +- SYSCFG_CMPCR_READY) == 0U) { +- if (timeout_elapsed(start)) { +- /* +- * Failure on IO compensation enable is not a issue: +- * warn only. +- */ +- WARN("IO compensation cell not ready\n"); +- break; +- } +- } +- +- mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); ++ enable_io_comp_cell_finish(SYSCFG_CMPCR); + } + + void stm32mp1_syscfg_disable_io_compensation(void) + { +- uint32_t value; +- + stm32mp1_clk_force_enable(SYSCFG); + + /* +@@ -178,18 +213,7 @@ void stm32mp1_syscfg_disable_io_compensation(void) + * requested for other usages and always OFF in STANDBY. + * Disable non-secure SYSCFG clock, we assume non-secure is suspended. + */ +- value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) >> +- SYSCFG_CMPCR_ANSRC_SHIFT; +- +- mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR, +- SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); +- +- value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) | +- (value << SYSCFG_CMPCR_RANSRC_SHIFT); +- +- mmio_write_32(SYSCFG_BASE + SYSCFG_CMPCR, value | SYSCFG_CMPCR_SW_CTRL); +- +- mmio_setbits_32(SYSCFG_BASE + SYSCFG_CMPENCLRR, SYSCFG_CMPENSETR_MPU_EN); ++ disable_io_comp_cell(SYSCFG_CMPCR); + + stm32mp1_clk_force_disable(SYSCFG); + } +diff --git a/plat/st/stm32mp1/stm32mp1_usb.c b/plat/st/stm32mp1/stm32mp1_usb.c +index c63db4a2ff..a205b64d34 100644 +--- a/plat/st/stm32mp1/stm32mp1_usb.c ++++ b/plat/st/stm32mp1/stm32mp1_usb.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2020, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -310,7 +310,7 @@ static uint8_t *stm32mp1_product_desc(uint16_t *length) + char str_chip_version[5]; + + stm32mp_get_soc_name(name); +- stm32mp_get_chip_version(&chip_version); ++ chip_version = stm32mp_get_chip_version(); + + int_to_str(STM32MP1_CHIP_ID, (uint8_t *)str_chip_id, 4); + int_to_str(chip_version, (uint8_t *)str_chip_version, 5); +-- +2.17.1 + diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.4.bb b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.4.bb index b5ed459..a82b727 100644 --- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.4.bb +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.4.bb @@ -14,11 +14,13 @@ SRCREV = "e2c509a39c6cc4dda8734e6509cdbe6e3603cdfc" SRC_URI += " \ file://0001-st-update-v2.4-r1.0.0.patch \ + file://0002-v2.4-stm32mp-r1.1-rc1.patch \ + file://0003-v2.4-stm32mp-r2.patch \ " TF_A_VERSION = "v2.4" TF_A_SUBVERSION = "stm32mp" -TF_A_RELEASE = "r1" +TF_A_RELEASE = "r2" PV = "${TF_A_VERSION}-${TF_A_SUBVERSION}-${TF_A_RELEASE}" ARCHIVER_ST_BRANCH = "${TF_A_VERSION}-${TF_A_SUBVERSION}" @@ -28,10 +30,10 @@ ARCHIVER_COMMUNITY_REVISION = "${TF_A_VERSION}" S = "${WORKDIR}/git" -# Configure stm32mp1 make settings -EXTRA_OEMAKE += "PLAT=stm32mp1" -EXTRA_OEMAKE += "ARCH=aarch32" -EXTRA_OEMAKE += "ARM_ARCH_MAJOR=7" +# Configure settings +TFA_PLATFORM = "stm32mp1" +TFA_ARM_MAJOR = "7" +TFA_ARM_ARCH = "aarch32" # Enable the wrapper for debug TF_A_ENABLE_DEBUG_WRAPPER ?= "1" @@ -47,7 +49,7 @@ include ${@oe.utils.ifelse(d.getVar('ST_ARCHIVER_ENABLE') == '1', 'tf-a-stm32mp- BBCLASSEXTEND = "devupstream:target" SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/arm-trusted-firmware.git;protocol=https;branch=${ARCHIVER_ST_BRANCH}" -SRCREV_class-devupstream = "40572e4067f205691a4dca3b5fdabe3a40c69594" +SRCREV_class-devupstream = "3e1e3f0a6149d04946ff5debcd871173e782111c" # --------------------------------- # Configure default preference to manage dynamic selection between tarball and github