stm32mp2: initial support

Add initial support for STM32MP2 SoCs family.

SoCs information are available here :
https://www.st.com/content/st_com/en/campaigns/microprocessor-stm32mp2.html

Migrate all MP1 related code into stm32mp1/ directory
Create stm32mp2 directory dedicated for STM32MP2 SoCs.

Common code to MP1, MP13 and MP25 is kept into
arch/arm/mach-stm32/mach-stm32mp directory :
  - boot_params.c
  - bsec
  - cmd_stm32key
  - cmd_stm32prog
  - dram_init.c
  - syscon.c
  - ecdsa_romapi.c

For STM32MP2, it also :
  - adds memory region description needed for ARMv8 MMU.
  - enables early data cache before relocation.
    During the transition before/after relocation, the MMU, initially setup
    at the beginning of DDR, must be setup again at a correct address after
    relocation. This is done in enables_caches() by disabling cache, force
    arch.tlb_fillptr to NULL which will force the MMU to be setup again but
    with a new value for gd->arch.tlb_addr. gd->arch.tlb_addr has been
    updated after relocation in arm_reserve_mmu().

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
diff --git a/arch/arm/mach-stm32mp/stm32mp1/Makefile b/arch/arm/mach-stm32mp/stm32mp1/Makefile
new file mode 100644
index 0000000..94c7724
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+#
+
+obj-y += cpu.o
+
+obj-$(CONFIG_STM32MP13x) += stm32mp13x.o
+obj-$(CONFIG_STM32MP15x) += stm32mp15x.o
+
+obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+obj-y += tzc400.o
+else
+obj-$(CONFIG_ARMV7_PSCI) += psci.o
+endif
+
+obj-$(CONFIG_$(SPL_)STM32MP15_PWR) += pwr_regulator.o
+obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o
diff --git a/arch/arm/mach-stm32mp/stm32mp1/cpu.c b/arch/arm/mach-stm32mp/stm32mp1/cpu.c
new file mode 100644
index 0000000..e07abbe
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/cpu.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <debug_uart.h>
+#include <env.h>
+#include <init.h>
+#include <log.h>
+#include <lmb.h>
+#include <misc.h>
+#include <net.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/stm32.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/global_data.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+
+/*
+ * early TLB into the .data section so that it not get cleared
+ * with 16kB allignment (see TTBR0_BASE_ADDR_MASK)
+ */
+u8 early_tlb[PGTABLE_SIZE] __section(".data") __aligned(0x4000);
+
+struct lmb lmb;
+
+u32 get_bootmode(void)
+{
+	/* read bootmode from TAMP backup register */
+	return (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >>
+		    TAMP_BOOT_MODE_SHIFT;
+}
+
+/*
+ * weak function overidde: set the DDR/SYSRAM executable before to enable the
+ * MMU and configure DACR, for early early_enable_caches (SPL or pre-reloc)
+ */
+void dram_bank_mmu_setup(int bank)
+{
+	struct bd_info *bd = gd->bd;
+	int	i;
+	phys_addr_t start;
+	phys_size_t size;
+	bool use_lmb = false;
+	enum dcache_option option;
+
+	if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+/* STM32_SYSRAM_BASE exist only when SPL is supported */
+#ifdef CONFIG_SPL
+		start = ALIGN_DOWN(STM32_SYSRAM_BASE, MMU_SECTION_SIZE);
+		size = ALIGN(STM32_SYSRAM_SIZE, MMU_SECTION_SIZE);
+#endif
+	} else if (gd->flags & GD_FLG_RELOC) {
+		/* bd->bi_dram is available only after relocation */
+		start = bd->bi_dram[bank].start;
+		size =  bd->bi_dram[bank].size;
+		use_lmb = true;
+	} else {
+		/* mark cacheable and executable the beggining of the DDR */
+		start = STM32_DDR_BASE;
+		size = CONFIG_DDR_CACHEABLE_SIZE;
+	}
+
+	for (i = start >> MMU_SECTION_SHIFT;
+	     i < (start >> MMU_SECTION_SHIFT) + (size >> MMU_SECTION_SHIFT);
+	     i++) {
+		option = DCACHE_DEFAULT_OPTION;
+		if (use_lmb && lmb_is_reserved_flags(&lmb, i << MMU_SECTION_SHIFT, LMB_NOMAP))
+			option = 0; /* INVALID ENTRY in TLB */
+		set_section_dcache(i, option);
+	}
+}
+/*
+ * initialize the MMU and activate cache in SPL or in U-Boot pre-reloc stage
+ * MMU/TLB is updated in enable_caches() for U-Boot after relocation
+ * or is deactivated in U-Boot entry function start.S::cpu_init_cp15
+ */
+static void early_enable_caches(void)
+{
+	/* I-cache is already enabled in start.S: cpu_init_cp15 */
+
+	if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+		return;
+
+	if (!(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))) {
+		gd->arch.tlb_size = PGTABLE_SIZE;
+		gd->arch.tlb_addr = (unsigned long)&early_tlb;
+	}
+
+	/* enable MMU (default configuration) */
+	dcache_enable();
+}
+
+/*
+ * Early system init
+ */
+int arch_cpu_init(void)
+{
+	early_enable_caches();
+
+	/* early armv7 timer init: needed for polling */
+	timer_init();
+
+	return 0;
+}
+
+/* weak function for SOC specific initialization */
+__weak void stm32mp_cpu_init(void)
+{
+}
+
+int mach_cpu_init(void)
+{
+	u32 boot_mode;
+
+	stm32mp_cpu_init();
+
+	boot_mode = get_bootmode();
+
+	if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) &&
+	    (boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART)
+		gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
+	else if (IS_ENABLED(CONFIG_DEBUG_UART) && IS_ENABLED(CONFIG_SPL_BUILD))
+		debug_uart_init();
+
+	return 0;
+}
+
+void enable_caches(void)
+{
+	/* parse device tree when data cache is still activated */
+	lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
+
+	/* I-cache is already enabled in start.S: icache_enable() not needed */
+
+	/* deactivate the data cache, early enabled in arch_cpu_init() */
+	dcache_disable();
+	/*
+	 * update MMU after relocation and enable the data cache
+	 * warning: the TLB location udpated in board_f.c::reserve_mmu
+	 */
+	dcache_enable();
+}
+
+/* used when CONFIG_DISPLAY_CPUINFO is activated */
+int print_cpuinfo(void)
+{
+	char name[SOC_NAME_SIZE];
+
+	get_soc_name(name);
+	printf("CPU: %s\n", name);
+
+	return 0;
+}
+
+static void setup_boot_mode(void)
+{
+	const u32 serial_addr[] = {
+		STM32_USART1_BASE,
+		STM32_USART2_BASE,
+		STM32_USART3_BASE,
+		STM32_UART4_BASE,
+		STM32_UART5_BASE,
+		STM32_USART6_BASE,
+		STM32_UART7_BASE,
+		STM32_UART8_BASE
+	};
+	const u32 sdmmc_addr[] = {
+		STM32_SDMMC1_BASE,
+		STM32_SDMMC2_BASE,
+		STM32_SDMMC3_BASE
+	};
+	char cmd[60];
+	u32 boot_ctx = readl(TAMP_BOOT_CONTEXT);
+	u32 boot_mode =
+		(boot_ctx & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT;
+	unsigned int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1;
+	u32 forced_mode = (boot_ctx & TAMP_BOOT_FORCED_MASK);
+	struct udevice *dev;
+
+	log_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d forced=%x\n",
+		  __func__, boot_ctx, boot_mode, instance, forced_mode);
+	switch (boot_mode & TAMP_BOOT_DEVICE_MASK) {
+	case BOOT_SERIAL_UART:
+		if (instance >= ARRAY_SIZE(serial_addr))
+			break;
+		/* serial : search associated node in devicetree */
+		sprintf(cmd, "serial@%x", serial_addr[instance]);
+		if (uclass_get_device_by_name(UCLASS_SERIAL, cmd, &dev)) {
+			/* restore console on error */
+			if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL))
+				gd->flags &= ~(GD_FLG_SILENT |
+					       GD_FLG_DISABLE_CONSOLE);
+			log_err("uart%d = %s not found in device tree!\n",
+				instance + 1, cmd);
+			break;
+		}
+		sprintf(cmd, "%d", dev_seq(dev));
+		env_set("boot_device", "serial");
+		env_set("boot_instance", cmd);
+
+		/* restore console on uart when not used */
+		if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && gd->cur_serial_dev != dev) {
+			gd->flags &= ~(GD_FLG_SILENT |
+				       GD_FLG_DISABLE_CONSOLE);
+			log_info("serial boot with console enabled!\n");
+		}
+		break;
+	case BOOT_SERIAL_USB:
+		env_set("boot_device", "usb");
+		env_set("boot_instance", "0");
+		break;
+	case BOOT_FLASH_SD:
+	case BOOT_FLASH_EMMC:
+		if (instance >= ARRAY_SIZE(sdmmc_addr))
+			break;
+		/* search associated sdmmc node in devicetree */
+		sprintf(cmd, "mmc@%x", sdmmc_addr[instance]);
+		if (uclass_get_device_by_name(UCLASS_MMC, cmd, &dev)) {
+			printf("mmc%d = %s not found in device tree!\n",
+			       instance, cmd);
+			break;
+		}
+		sprintf(cmd, "%d", dev_seq(dev));
+		env_set("boot_device", "mmc");
+		env_set("boot_instance", cmd);
+		break;
+	case BOOT_FLASH_NAND:
+		env_set("boot_device", "nand");
+		env_set("boot_instance", "0");
+		break;
+	case BOOT_FLASH_SPINAND:
+		env_set("boot_device", "spi-nand");
+		env_set("boot_instance", "0");
+		break;
+	case BOOT_FLASH_NOR:
+		env_set("boot_device", "nor");
+		env_set("boot_instance", "0");
+		break;
+	default:
+		env_set("boot_device", "invalid");
+		env_set("boot_instance", "");
+		log_err("unexpected boot mode = %x\n", boot_mode);
+		break;
+	}
+
+	switch (forced_mode) {
+	case BOOT_FASTBOOT:
+		log_info("Enter fastboot!\n");
+		env_set("preboot", "env set preboot; fastboot 0");
+		break;
+	case BOOT_STM32PROG:
+		env_set("boot_device", "usb");
+		env_set("boot_instance", "0");
+		break;
+	case BOOT_UMS_MMC0:
+	case BOOT_UMS_MMC1:
+	case BOOT_UMS_MMC2:
+		log_info("Enter UMS!\n");
+		instance = forced_mode - BOOT_UMS_MMC0;
+		sprintf(cmd, "env set preboot; ums 0 mmc %d", instance);
+		env_set("preboot", cmd);
+		break;
+	case BOOT_RECOVERY:
+		env_set("preboot", "env set preboot; run altbootcmd");
+		break;
+	case BOOT_NORMAL:
+		break;
+	default:
+		log_debug("unexpected forced boot mode = %x\n", forced_mode);
+		break;
+	}
+
+	/* clear TAMP for next reboot */
+	clrsetbits_le32(TAMP_BOOT_CONTEXT, TAMP_BOOT_FORCED_MASK, BOOT_NORMAL);
+}
+
+/*
+ * If there is no MAC address in the environment, then it will be initialized
+ * (silently) from the value in the OTP.
+ */
+__weak int setup_mac_address(void)
+{
+	int ret;
+	int i;
+	u32 otp[3];
+	uchar enetaddr[6];
+	struct udevice *dev;
+	int nb_eth, nb_otp, index;
+
+	if (!IS_ENABLED(CONFIG_NET))
+		return 0;
+
+	nb_eth = get_eth_nb();
+
+	/* 6 bytes for each MAC addr and 4 bytes for each OTP */
+	nb_otp = DIV_ROUND_UP(6 * nb_eth, 4);
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_DRIVER_GET(stm32mp_bsec),
+					  &dev);
+	if (ret)
+		return ret;
+
+	ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_MAC), otp, 4 * nb_otp);
+	if (ret < 0)
+		return ret;
+
+	for (index = 0; index < nb_eth; index++) {
+		/* MAC already in environment */
+		if (eth_env_get_enetaddr_by_index("eth", index, enetaddr))
+			continue;
+
+		for (i = 0; i < 6; i++)
+			enetaddr[i] = ((uint8_t *)&otp)[i + 6 * index];
+
+		if (!is_valid_ethaddr(enetaddr)) {
+			log_err("invalid MAC address %d in OTP %pM\n",
+				index, enetaddr);
+			return -EINVAL;
+		}
+		log_debug("OTP MAC address %d = %pM\n", index, enetaddr);
+		ret = eth_env_set_enetaddr_by_index("eth", index, enetaddr);
+		if (ret) {
+			log_err("Failed to set mac address %pM from OTP: %d\n",
+				enetaddr, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int setup_serial_number(void)
+{
+	char serial_string[25];
+	u32 otp[3] = {0, 0, 0 };
+	struct udevice *dev;
+	int ret;
+
+	if (env_get("serial#"))
+		return 0;
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_DRIVER_GET(stm32mp_bsec),
+					  &dev);
+	if (ret)
+		return ret;
+
+	ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_SERIAL),
+			otp, sizeof(otp));
+	if (ret < 0)
+		return ret;
+
+	sprintf(serial_string, "%08X%08X%08X", otp[0], otp[1], otp[2]);
+	env_set("serial#", serial_string);
+
+	return 0;
+}
+
+__weak void stm32mp_misc_init(void)
+{
+}
+
+int arch_misc_init(void)
+{
+	setup_boot_mode();
+	setup_mac_address();
+	setup_serial_number();
+	stm32mp_misc_init();
+
+	return 0;
+}
+
+/*
+ * Without forcing the ".data" section, this would get saved in ".bss". BSS
+ * will be cleared soon after, so it's not suitable.
+ */
+static uintptr_t rom_api_table __section(".data");
+static uintptr_t nt_fw_dtb __section(".data");
+
+/*
+ * The ROM gives us the API location in r0 when starting. This is only available
+ * during SPL, as there isn't (yet) a mechanism to pass this on to u-boot. Save
+ * the FDT address provided by TF-A in r2 at boot time. This function is called
+ * from start.S
+ */
+void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2,
+		      unsigned long r3)
+{
+	if (IS_ENABLED(CONFIG_STM32_ECDSA_VERIFY))
+		rom_api_table = r0;
+
+	if (IS_ENABLED(CONFIG_TFABOOT))
+		nt_fw_dtb = r2;
+
+	save_boot_params_ret();
+}
+
+uintptr_t get_stm32mp_rom_api_table(void)
+{
+	return rom_api_table;
+}
+
+uintptr_t get_stm32mp_bl2_dtb(void)
+{
+	return nt_fw_dtb;
+}
+
+#ifdef CONFIG_SPL_BUILD
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+	typedef void __noreturn (*image_entry_stm32_t)(u32 romapi);
+	uintptr_t romapi = get_stm32mp_rom_api_table();
+
+	image_entry_stm32_t image_entry =
+		(image_entry_stm32_t)spl_image->entry_point;
+
+	printf("image entry point: 0x%lx\n", spl_image->entry_point);
+	image_entry(romapi);
+}
+#endif
diff --git a/arch/arm/mach-stm32mp/stm32mp1/fdt.c b/arch/arm/mach-stm32mp/stm32mp1/fdt.c
new file mode 100644
index 0000000..de5c5a5
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/fdt.c
@@ -0,0 +1,514 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <log.h>
+#include <tee.h>
+#include <asm/arch/sys_proto.h>
+#include <dt-bindings/pinctrl/stm32-pinfunc.h>
+#include <linux/io.h>
+
+#define ETZPC_DECPROT(n)	(STM32_ETZPC_BASE + 0x10 + 4 * (n))
+#define ETZPC_DECPROT_NB	6
+
+#define DECPROT_MASK		0x03
+#define NB_PROT_PER_REG		0x10
+#define DECPROT_NB_BITS		2
+
+#define DECPROT_SECURED		0x00
+#define DECPROT_WRITE_SECURE	0x01
+#define DECPROT_MCU_ISOLATION	0x02
+#define DECPROT_NON_SECURED	0x03
+
+#define ETZPC_RESERVED		0xffffffff
+
+#define STM32MP13_FDCAN_BASE	0x4400F000
+#define STM32MP13_ADC1_BASE	0x48003000
+#define STM32MP13_TSC_BASE	0x5000B000
+#define STM32MP13_CRYP_BASE	0x54002000
+#define STM32MP13_ETH2_BASE	0x5800E000
+#define STM32MP13_DCMIPP_BASE	0x5A000000
+#define STM32MP13_LTDC_BASE	0x5A010000
+
+#define STM32MP15_FDCAN_BASE	0x4400e000
+#define STM32MP15_CRYP2_BASE	0x4c005000
+#define STM32MP15_CRYP1_BASE	0x54001000
+#define STM32MP15_GPU_BASE	0x59000000
+#define STM32MP15_DSI_BASE	0x5a000000
+
+static const u32 stm32mp13_ip_addr[] = {
+	0x50025000,		/* 0 VREFBUF APB3 */
+	0x50021000,		/* 1 LPTIM2 APB3 */
+	0x50022000,		/* 2 LPTIM3 APB3 */
+	STM32MP13_LTDC_BASE,	/* 3 LTDC APB4 */
+	STM32MP13_DCMIPP_BASE,	/* 4 DCMIPP APB4 */
+	0x5A006000,		/* 5 USBPHYCTRL APB4 */
+	0x5A003000,		/* 6 DDRCTRLPHY APB4 */
+	ETZPC_RESERVED,		/* 7 Reserved*/
+	ETZPC_RESERVED,		/* 8 Reserved*/
+	ETZPC_RESERVED,		/* 9 Reserved*/
+	0x5C006000,		/* 10 TZC APB5 */
+	0x58001000,		/* 11 MCE APB5 */
+	0x5C000000,		/* 12 IWDG1 APB5 */
+	0x5C008000,		/* 13 STGENC APB5 */
+	ETZPC_RESERVED,		/* 14 Reserved*/
+	ETZPC_RESERVED,		/* 15 Reserved*/
+	0x4C000000,		/* 16 USART1 APB6 */
+	0x4C001000,		/* 17 USART2 APB6 */
+	0x4C002000,		/* 18 SPI4 APB6 */
+	0x4C003000,		/* 19 SPI5 APB6 */
+	0x4C004000,		/* 20 I2C3 APB6 */
+	0x4C005000,		/* 21 I2C4 APB6 */
+	0x4C006000,		/* 22 I2C5 APB6 */
+	0x4C007000,		/* 23 TIM12 APB6 */
+	0x4C008000,		/* 24 TIM13 APB6 */
+	0x4C009000,		/* 25 TIM14 APB6 */
+	0x4C00A000,		/* 26 TIM15 APB6 */
+	0x4C00B000,		/* 27 TIM16 APB6 */
+	0x4C00C000,		/* 28 TIM17 APB6 */
+	ETZPC_RESERVED,		/* 29 Reserved*/
+	ETZPC_RESERVED,		/* 30 Reserved*/
+	ETZPC_RESERVED,		/* 31 Reserved*/
+	STM32MP13_ADC1_BASE,	/* 32 ADC1 AHB2 */
+	0x48004000,		/* 33 ADC2 AHB2 */
+	0x49000000,		/* 34 OTG AHB2 */
+	ETZPC_RESERVED,		/* 35 Reserved*/
+	ETZPC_RESERVED,		/* 36 Reserved*/
+	STM32MP13_TSC_BASE,	/* 37 TSC AHB4 */
+	ETZPC_RESERVED,		/* 38 Reserved*/
+	ETZPC_RESERVED,		/* 39 Reserved*/
+	0x54004000,		/* 40 RNG AHB5 */
+	0x54003000,		/* 41 HASH AHB5 */
+	STM32MP13_CRYP_BASE,	/* 42 CRYPT AHB5 */
+	0x54005000,		/* 43 SAES AHB5 */
+	0x54006000,		/* 44 PKA AHB5 */
+	0x54000000,		/* 45 BKPSRAM AHB5 */
+	ETZPC_RESERVED,		/* 46 Reserved*/
+	ETZPC_RESERVED,		/* 47 Reserved*/
+	0x5800A000,		/* 48 ETH1 AHB6 */
+	STM32MP13_ETH2_BASE,	/* 49 ETH2 AHB6 */
+	0x58005000,		/* 50 SDMMC1 AHB6 */
+	0x58007000,		/* 51 SDMMC2 AHB6 */
+	ETZPC_RESERVED,		/* 52 Reserved*/
+	ETZPC_RESERVED,		/* 53 Reserved*/
+	0x58002000,		/* 54 FMC AHB6 */
+	0x58003000,		/* 55 QSPI AHB6 */
+	ETZPC_RESERVED,		/* 56 Reserved*/
+	ETZPC_RESERVED,		/* 57 Reserved*/
+	ETZPC_RESERVED,		/* 58 Reserved*/
+	ETZPC_RESERVED,		/* 59 Reserved*/
+	0x30000000,		/* 60 SRAM1 MLAHB */
+	0x30004000,		/* 61 SRAM2 MLAHB */
+	0x30006000,		/* 62 SRAM3 MLAHB */
+	ETZPC_RESERVED,		/* 63 Reserved*/
+	ETZPC_RESERVED,		/* 64 Reserved*/
+	ETZPC_RESERVED,		/* 65 Reserved*/
+	ETZPC_RESERVED,		/* 66 Reserved*/
+	ETZPC_RESERVED,		/* 67 Reserved*/
+	ETZPC_RESERVED,		/* 68 Reserved*/
+	ETZPC_RESERVED,		/* 69 Reserved*/
+	ETZPC_RESERVED,		/* 70 Reserved*/
+	ETZPC_RESERVED,		/* 71 Reserved*/
+	ETZPC_RESERVED,		/* 72 Reserved*/
+	ETZPC_RESERVED,		/* 73 Reserved*/
+	ETZPC_RESERVED,		/* 74 Reserved*/
+	ETZPC_RESERVED,		/* 75 Reserved*/
+	ETZPC_RESERVED,		/* 76 Reserved*/
+	ETZPC_RESERVED,		/* 77 Reserved*/
+	ETZPC_RESERVED,		/* 78 Reserved*/
+	ETZPC_RESERVED,		/* 79 Reserved*/
+	ETZPC_RESERVED,		/* 80 Reserved*/
+	ETZPC_RESERVED,		/* 81 Reserved*/
+	ETZPC_RESERVED,		/* 82 Reserved*/
+	ETZPC_RESERVED,		/* 83 Reserved*/
+	ETZPC_RESERVED,		/* 84 Reserved*/
+	ETZPC_RESERVED,		/* 85 Reserved*/
+	ETZPC_RESERVED,		/* 86 Reserved*/
+	ETZPC_RESERVED,		/* 87 Reserved*/
+	ETZPC_RESERVED,		/* 88 Reserved*/
+	ETZPC_RESERVED,		/* 89 Reserved*/
+	ETZPC_RESERVED,		/* 90 Reserved*/
+	ETZPC_RESERVED,		/* 91 Reserved*/
+	ETZPC_RESERVED,		/* 92 Reserved*/
+	ETZPC_RESERVED,		/* 93 Reserved*/
+	ETZPC_RESERVED,		/* 94 Reserved*/
+	ETZPC_RESERVED,		/* 95 Reserved*/
+};
+
+static const u32 stm32mp15_ip_addr[] = {
+	0x5c008000,	/* 00 stgenc */
+	0x54000000,	/* 01 bkpsram */
+	0x5c003000,	/* 02 iwdg1 */
+	0x5c000000,	/* 03 usart1 */
+	0x5c001000,	/* 04 spi6 */
+	0x5c002000,	/* 05 i2c4 */
+	ETZPC_RESERVED,	/* 06 reserved */
+	0x54003000,	/* 07 rng1 */
+	0x54002000,	/* 08 hash1 */
+	STM32MP15_CRYP1_BASE,	/* 09 cryp1 */
+	0x5a003000,	/* 0A ddrctrl */
+	0x5a004000,	/* 0B ddrphyc */
+	0x5c009000,	/* 0C i2c6 */
+	ETZPC_RESERVED,	/* 0D reserved */
+	ETZPC_RESERVED,	/* 0E reserved */
+	ETZPC_RESERVED,	/* 0F reserved */
+	0x40000000,	/* 10 tim2 */
+	0x40001000,	/* 11 tim3 */
+	0x40002000,	/* 12 tim4 */
+	0x40003000,	/* 13 tim5 */
+	0x40004000,	/* 14 tim6 */
+	0x40005000,	/* 15 tim7 */
+	0x40006000,	/* 16 tim12 */
+	0x40007000,	/* 17 tim13 */
+	0x40008000,	/* 18 tim14 */
+	0x40009000,	/* 19 lptim1 */
+	0x4000a000,	/* 1A wwdg1 */
+	0x4000b000,	/* 1B spi2 */
+	0x4000c000,	/* 1C spi3 */
+	0x4000d000,	/* 1D spdifrx */
+	0x4000e000,	/* 1E usart2 */
+	0x4000f000,	/* 1F usart3 */
+	0x40010000,	/* 20 uart4 */
+	0x40011000,	/* 21 uart5 */
+	0x40012000,	/* 22 i2c1 */
+	0x40013000,	/* 23 i2c2 */
+	0x40014000,	/* 24 i2c3 */
+	0x40015000,	/* 25 i2c5 */
+	0x40016000,	/* 26 cec */
+	0x40017000,	/* 27 dac */
+	0x40018000,	/* 28 uart7 */
+	0x40019000,	/* 29 uart8 */
+	ETZPC_RESERVED,	/* 2A reserved */
+	ETZPC_RESERVED,	/* 2B reserved */
+	0x4001c000,	/* 2C mdios */
+	ETZPC_RESERVED,	/* 2D reserved */
+	ETZPC_RESERVED,	/* 2E reserved */
+	ETZPC_RESERVED,	/* 2F reserved */
+	0x44000000,	/* 30 tim1 */
+	0x44001000,	/* 31 tim8 */
+	ETZPC_RESERVED,	/* 32 reserved */
+	0x44003000,	/* 33 usart6 */
+	0x44004000,	/* 34 spi1 */
+	0x44005000,	/* 35 spi4 */
+	0x44006000,	/* 36 tim15 */
+	0x44007000,	/* 37 tim16 */
+	0x44008000,	/* 38 tim17 */
+	0x44009000,	/* 39 spi5 */
+	0x4400a000,	/* 3A sai1 */
+	0x4400b000,	/* 3B sai2 */
+	0x4400c000,	/* 3C sai3 */
+	0x4400d000,	/* 3D dfsdm */
+	STM32MP15_FDCAN_BASE,	/* 3E tt_fdcan */
+	ETZPC_RESERVED,	/* 3F reserved */
+	0x50021000,	/* 40 lptim2 */
+	0x50022000,	/* 41 lptim3 */
+	0x50023000,	/* 42 lptim4 */
+	0x50024000,	/* 43 lptim5 */
+	0x50027000,	/* 44 sai4 */
+	0x50025000,	/* 45 vrefbuf */
+	0x4c006000,	/* 46 dcmi */
+	0x4c004000,	/* 47 crc2 */
+	0x48003000,	/* 48 adc */
+	0x4c002000,	/* 49 hash2 */
+	0x4c003000,	/* 4A rng2 */
+	STM32MP15_CRYP2_BASE,	/* 4B cryp2 */
+	ETZPC_RESERVED,	/* 4C reserved */
+	ETZPC_RESERVED,	/* 4D reserved */
+	ETZPC_RESERVED,	/* 4E reserved */
+	ETZPC_RESERVED,	/* 4F reserved */
+	ETZPC_RESERVED,	/* 50 sram1 */
+	ETZPC_RESERVED,	/* 51 sram2 */
+	ETZPC_RESERVED,	/* 52 sram3 */
+	ETZPC_RESERVED,	/* 53 sram4 */
+	ETZPC_RESERVED,	/* 54 retram */
+	0x49000000,	/* 55 otg */
+	0x48004000,	/* 56 sdmmc3 */
+	0x48005000,	/* 57 dlybsd3 */
+	0x48000000,	/* 58 dma1 */
+	0x48001000,	/* 59 dma2 */
+	0x48002000,	/* 5A dmamux */
+	0x58002000,	/* 5B fmc */
+	0x58003000,	/* 5C qspi */
+	0x58004000,	/* 5D dlybq */
+	0x5800a000,	/* 5E eth */
+	ETZPC_RESERVED,	/* 5F reserved */
+};
+
+/* fdt helper */
+static bool fdt_disable_subnode_by_address(void *fdt, int offset, u32 addr)
+{
+	int node;
+	fdt_addr_t regs;
+
+	for (node = fdt_first_subnode(fdt, offset);
+	     node >= 0;
+	     node = fdt_next_subnode(fdt, node)) {
+		regs = fdtdec_get_addr(fdt, node, "reg");
+		if (addr == regs) {
+			if (fdtdec_get_is_enabled(fdt, node)) {
+				fdt_status_disabled(fdt, node);
+
+				return true;
+			}
+			return false;
+		}
+	}
+
+	return false;
+}
+
+static int stm32_fdt_fixup_etzpc(void *fdt, int soc_node)
+{
+	const u32 *array;
+	int array_size, i;
+	int offset, shift;
+	u32 addr, status, decprot[ETZPC_DECPROT_NB];
+
+	if (IS_ENABLED(CONFIG_STM32MP13x)) {
+		array = stm32mp13_ip_addr;
+		array_size = ARRAY_SIZE(stm32mp13_ip_addr);
+	}
+
+	if (IS_ENABLED(CONFIG_STM32MP15x)) {
+		array = stm32mp15_ip_addr;
+		array_size = ARRAY_SIZE(stm32mp15_ip_addr);
+	}
+
+	for (i = 0; i < ETZPC_DECPROT_NB; i++)
+		decprot[i] = readl(ETZPC_DECPROT(i));
+
+	for (i = 0; i < array_size; i++) {
+		offset = i / NB_PROT_PER_REG;
+		shift = (i % NB_PROT_PER_REG) * DECPROT_NB_BITS;
+		status = (decprot[offset] >> shift) & DECPROT_MASK;
+		addr = array[i];
+
+		log_debug("ETZPC: 0x%08x decprot %d=%d\n", addr, i, status);
+
+		if (addr == ETZPC_RESERVED ||
+		    status == DECPROT_NON_SECURED)
+			continue;
+
+		if (fdt_disable_subnode_by_address(fdt, soc_node, addr))
+			log_notice("ETZPC: 0x%08x node disabled, decprot %d=%d\n",
+				   addr, i, status);
+	}
+
+	return 0;
+}
+
+/* deactivate all the cpu except core 0 */
+static void stm32_fdt_fixup_cpu(void *blob, char *name)
+{
+	int off;
+	u32 reg;
+
+	off = fdt_path_offset(blob, "/cpus");
+	if (off < 0) {
+		log_warning("%s: couldn't find /cpus node\n", __func__);
+		return;
+	}
+
+	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+	while (off != -FDT_ERR_NOTFOUND) {
+		reg = fdtdec_get_addr(blob, off, "reg");
+		if (reg != 0) {
+			fdt_del_node(blob, off);
+			log_notice("FDT: cpu %d node remove for %s\n",
+				   reg, name);
+			/* after delete we can't trust the offsets anymore */
+			off = -1;
+		}
+		off = fdt_node_offset_by_prop_value(blob, off,
+						    "device_type", "cpu", 4);
+	}
+}
+
+static void stm32_fdt_disable(void *fdt, int offset, u32 addr,
+			      const char *string, const char *name)
+{
+	if (fdt_disable_subnode_by_address(fdt, offset, addr))
+		log_notice("FDT: %s@%08x node disabled for %s\n",
+			   string, addr, name);
+}
+
+static void stm32_fdt_disable_optee(void *blob)
+{
+	int off, node;
+
+	/* Delete "optee" firmware node */
+	off = fdt_node_offset_by_compatible(blob, -1, "linaro,optee-tz");
+	if (off >= 0 && fdtdec_get_is_enabled(blob, off))
+		fdt_del_node(blob, off);
+
+	/* Delete "optee@..." reserved-memory node */
+	off = fdt_path_offset(blob, "/reserved-memory/");
+	if (off < 0)
+		return;
+	for (node = fdt_first_subnode(blob, off);
+	     node >= 0;
+	     node = fdt_next_subnode(blob, node)) {
+		if (strncmp(fdt_get_name(blob, node, NULL), "optee@", 6))
+			continue;
+
+		if (fdt_del_node(blob, node))
+			printf("Failed to remove optee reserved-memory node\n");
+	}
+}
+
+static void stm32mp13_fdt_fixup(void *blob, int soc, u32 cpu, char *name)
+{
+	switch (cpu) {
+	case CPU_STM32MP131Fxx:
+	case CPU_STM32MP131Dxx:
+	case CPU_STM32MP131Cxx:
+	case CPU_STM32MP131Axx:
+		stm32_fdt_disable(blob, soc, STM32MP13_FDCAN_BASE, "can", name);
+		stm32_fdt_disable(blob, soc, STM32MP13_ADC1_BASE, "adc", name);
+		fallthrough;
+	case CPU_STM32MP133Fxx:
+	case CPU_STM32MP133Dxx:
+	case CPU_STM32MP133Cxx:
+	case CPU_STM32MP133Axx:
+		stm32_fdt_disable(blob, soc, STM32MP13_LTDC_BASE, "ltdc", name);
+		stm32_fdt_disable(blob, soc, STM32MP13_DCMIPP_BASE, "dcmipp",
+				  name);
+		stm32_fdt_disable(blob, soc, STM32MP13_TSC_BASE, "tsc", name);
+		break;
+	default:
+		break;
+	}
+
+	switch (cpu) {
+	case CPU_STM32MP135Dxx:
+	case CPU_STM32MP135Axx:
+	case CPU_STM32MP133Dxx:
+	case CPU_STM32MP133Axx:
+	case CPU_STM32MP131Dxx:
+	case CPU_STM32MP131Axx:
+		stm32_fdt_disable(blob, soc, STM32MP13_CRYP_BASE, "cryp", name);
+		break;
+	default:
+		break;
+	}
+}
+
+static void stm32mp15_fdt_fixup(void *blob, int soc, u32 cpu, char *name)
+{
+	u32 pkg;
+
+	switch (cpu) {
+	case CPU_STM32MP151Fxx:
+	case CPU_STM32MP151Dxx:
+	case CPU_STM32MP151Cxx:
+	case CPU_STM32MP151Axx:
+		stm32_fdt_fixup_cpu(blob, name);
+		/* after cpu delete we can't trust the soc offsets anymore */
+		soc = fdt_path_offset(blob, "/soc");
+		stm32_fdt_disable(blob, soc, STM32MP15_FDCAN_BASE, "can", name);
+		fallthrough;
+	case CPU_STM32MP153Fxx:
+	case CPU_STM32MP153Dxx:
+	case CPU_STM32MP153Cxx:
+	case CPU_STM32MP153Axx:
+		stm32_fdt_disable(blob, soc, STM32MP15_GPU_BASE, "gpu", name);
+		stm32_fdt_disable(blob, soc, STM32MP15_DSI_BASE, "dsi", name);
+		break;
+	default:
+		break;
+	}
+	switch (cpu) {
+	case CPU_STM32MP157Dxx:
+	case CPU_STM32MP157Axx:
+	case CPU_STM32MP153Dxx:
+	case CPU_STM32MP153Axx:
+	case CPU_STM32MP151Dxx:
+	case CPU_STM32MP151Axx:
+		stm32_fdt_disable(blob, soc, STM32MP15_CRYP1_BASE, "cryp",
+				  name);
+		stm32_fdt_disable(blob, soc, STM32MP15_CRYP2_BASE, "cryp",
+				  name);
+		break;
+	default:
+		break;
+	}
+	switch (get_cpu_package()) {
+	case STM32MP15_PKG_AA_LBGA448:
+		pkg = STM32MP_PKG_AA;
+		break;
+	case STM32MP15_PKG_AB_LBGA354:
+		pkg = STM32MP_PKG_AB;
+		break;
+	case STM32MP15_PKG_AC_TFBGA361:
+		pkg = STM32MP_PKG_AC;
+		break;
+	case STM32MP15_PKG_AD_TFBGA257:
+		pkg = STM32MP_PKG_AD;
+		break;
+	default:
+		pkg = 0;
+		break;
+	}
+	if (pkg) {
+		do_fixup_by_compat_u32(blob, "st,stm32mp157-pinctrl",
+				       "st,package", pkg, false);
+		do_fixup_by_compat_u32(blob, "st,stm32mp157-z-pinctrl",
+				       "st,package", pkg, false);
+	}
+}
+
+/*
+ * This function is called right before the kernel is booted. "blob" is the
+ * device tree that will be passed to the kernel.
+ */
+int ft_system_setup(void *blob, struct bd_info *bd)
+{
+	int ret = 0;
+	int soc;
+	u32 cpu;
+	char name[SOC_NAME_SIZE];
+
+	soc = fdt_path_offset(blob, "/soc");
+	/* when absent, nothing to do */
+	if (soc == -FDT_ERR_NOTFOUND)
+		return 0;
+	if (soc < 0)
+		return soc;
+
+	if (CONFIG_IS_ENABLED(STM32_ETZPC)) {
+		ret = stm32_fdt_fixup_etzpc(blob, soc);
+		if (ret)
+			return ret;
+	}
+
+	/* MPUs Part Numbers and name*/
+	cpu = get_cpu_type();
+	get_soc_name(name);
+
+	if (IS_ENABLED(CONFIG_STM32MP13x))
+		stm32mp13_fdt_fixup(blob, soc, cpu, name);
+
+	if (IS_ENABLED(CONFIG_STM32MP15x)) {
+		stm32mp15_fdt_fixup(blob, soc, cpu, name);
+
+		/*
+		 * TEMP: remove OP-TEE nodes in kernel device tree
+		 *       copied from U-Boot device tree by optee_copy_fdt_nodes
+		 *       when OP-TEE is not detected (probe failed)
+		 * these OP-TEE nodes are present in <board>-u-boot.dtsi
+		 * under CONFIG_STM32MP15x_STM32IMAGE only for compatibility
+		 * when FIP is not used by TF-A
+		 */
+		if (IS_ENABLED(CONFIG_STM32MP15x_STM32IMAGE) &&
+		    !tee_find_device(NULL, NULL, NULL, NULL))
+			stm32_fdt_disable_optee(blob);
+	}
+
+	return ret;
+}
diff --git a/arch/arm/mach-stm32mp/stm32mp1/psci.c b/arch/arm/mach-stm32mp/stm32mp1/psci.c
new file mode 100644
index 0000000..8cdeb0a
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/psci.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/armv7.h>
+#include <asm/cache.h>
+#include <asm/gic.h>
+#include <asm/io.h>
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <hang.h>
+#include <linux/bitops.h>
+
+/* PWR */
+#define PWR_CR3					0x0c
+#define PWR_MPUCR				0x10
+
+#define PWR_CR3_DDRSREN				BIT(10)
+#define PWR_CR3_DDRRETEN			BIT(12)
+
+#define PWR_MPUCR_PDDS				BIT(0)
+#define PWR_MPUCR_CSTDBYDIS			BIT(3)
+#define PWR_MPUCR_CSSF				BIT(9)
+
+/* RCC */
+#define RCC_MSSCKSELR				0x48
+#define RCC_DDRITFCR				0xd8
+
+#define RCC_DDRITFCR_DDRC1EN			BIT(0)
+#define RCC_DDRITFCR_DDRC1LPEN			BIT(1)
+#define RCC_DDRITFCR_DDRC2EN			BIT(2)
+#define RCC_DDRITFCR_DDRC2LPEN			BIT(3)
+#define RCC_DDRITFCR_DDRPHYCEN			BIT(4)
+#define RCC_DDRITFCR_DDRPHYCLPEN		BIT(5)
+#define RCC_DDRITFCR_DDRCAPBEN			BIT(6)
+#define RCC_DDRITFCR_DDRCAPBLPEN		BIT(7)
+#define RCC_DDRITFCR_AXIDCGEN			BIT(8)
+#define RCC_DDRITFCR_DDRPHYCAPBEN		BIT(9)
+#define RCC_DDRITFCR_DDRPHYCAPBLPEN		BIT(10)
+#define RCC_DDRITFCR_DDRCKMOD_MASK		GENMASK(22, 20)
+#define RCC_DDRITFCR_GSKPCTRL			BIT(24)
+
+#define RCC_MP_SREQSETR				0x104
+#define RCC_MP_SREQCLRR				0x108
+
+#define RCC_MP_CIER				0x414
+#define RCC_MP_CIFR				0x418
+#define RCC_MP_CIFR_WKUPF			BIT(20)
+
+#define RCC_MCUDIVR				0x830
+#define RCC_PLL3CR				0x880
+#define RCC_PLL4CR				0x894
+
+/* SYSCFG */
+#define SYSCFG_CMPCR				0x20
+#define SYSCFG_CMPCR_SW_CTRL			BIT(2)
+#define SYSCFG_CMPENSETR			0x24
+#define SYSCFG_CMPENCLRR			0x28
+#define SYSCFG_CMPENR_MPUEN			BIT(0)
+
+/* DDR Controller registers offsets */
+#define DDRCTRL_STAT				0x004
+#define DDRCTRL_PWRCTL				0x030
+#define DDRCTRL_PWRTMG				0x034
+#define DDRCTRL_HWLPCTL				0x038
+#define DDRCTRL_DFIMISC				0x1b0
+#define DDRCTRL_SWCTL				0x320
+#define DDRCTRL_SWSTAT				0x324
+#define DDRCTRL_PSTAT				0x3fc
+#define DDRCTRL_PCTRL_0				0x490
+#define DDRCTRL_PCTRL_1				0x540
+
+/* DDR Controller Register fields */
+#define DDRCTRL_STAT_OPERATING_MODE_MASK	GENMASK(2, 0)
+#define DDRCTRL_STAT_OPERATING_MODE_NORMAL	0x1
+#define DDRCTRL_STAT_OPERATING_MODE_SR		0x3
+#define DDRCTRL_STAT_SELFREF_TYPE_MASK		GENMASK(5, 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_ASR		(0x3 << 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_SR		(0x2 << 4)
+
+#define DDRCTRL_PWRCTL_SELFREF_EN		BIT(0)
+#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE	BIT(3)
+#define DDRCTRL_PWRCTL_SELFREF_SW		BIT(5)
+
+#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK	GENMASK(23, 16)
+#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0		BIT(16)
+
+#define DDRCTRL_HWLPCTL_HW_LP_EN		BIT(0)
+
+#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN	BIT(0)
+
+#define DDRCTRL_SWCTL_SW_DONE			BIT(0)
+
+#define DDRCTRL_SWSTAT_SW_DONE_ACK		BIT(0)
+
+#define DDRCTRL_PSTAT_RD_PORT_BUSY_0		BIT(0)
+#define DDRCTRL_PSTAT_RD_PORT_BUSY_1		BIT(1)
+#define DDRCTRL_PSTAT_WR_PORT_BUSY_0		BIT(16)
+#define DDRCTRL_PSTAT_WR_PORT_BUSY_1		BIT(17)
+
+#define DDRCTRL_PCTRL_N_PORT_EN			BIT(0)
+
+/* DDR PHY registers offsets */
+#define DDRPHYC_PIR				0x004
+#define DDRPHYC_PGSR				0x00c
+#define DDRPHYC_ACDLLCR				0x014
+#define DDRPHYC_ACIOCR				0x024
+#define DDRPHYC_DXCCR				0x028
+#define DDRPHYC_DSGCR				0x02c
+#define DDRPHYC_ZQ0CR0				0x180
+#define DDRPHYC_DX0DLLCR			0x1cc
+#define DDRPHYC_DX1DLLCR			0x20c
+#define DDRPHYC_DX2DLLCR			0x24c
+#define DDRPHYC_DX3DLLCR			0x28c
+
+/* DDR PHY Register fields */
+#define DDRPHYC_PIR_INIT			BIT(0)
+#define DDRPHYC_PIR_DLLSRST			BIT(1)
+#define DDRPHYC_PIR_DLLLOCK			BIT(2)
+#define DDRPHYC_PIR_ITMSRST			BIT(4)
+
+#define DDRPHYC_PGSR_IDONE			BIT(0)
+
+#define DDRPHYC_ACDLLCR_DLLSRST			BIT(30)
+#define DDRPHYC_ACDLLCR_DLLDIS			BIT(31)
+
+#define DDRPHYC_ACIOCR_ACOE			BIT(1)
+#define DDRPHYC_ACIOCR_ACPDD			BIT(3)
+#define DDRPHYC_ACIOCR_ACPDR			BIT(4)
+#define DDRPHYC_ACIOCR_CKPDD_MASK		GENMASK(10, 8)
+#define DDRPHYC_ACIOCR_CKPDD_0			BIT(8)
+#define DDRPHYC_ACIOCR_CKPDR_MASK		GENMASK(13, 11)
+#define DDRPHYC_ACIOCR_CKPDR_0			BIT(11)
+#define DDRPHYC_ACIOCR_CSPDD_MASK		GENMASK(20, 18)
+#define DDRPHYC_ACIOCR_CSPDD_0			BIT(18)
+
+#define DDRPHYC_DXCCR_DXPDD			BIT(2)
+#define DDRPHYC_DXCCR_DXPDR			BIT(3)
+
+#define DDRPHYC_DSGCR_CKEPDD_MASK		GENMASK(19, 16)
+#define DDRPHYC_DSGCR_CKEPDD_0			BIT(16)
+#define DDRPHYC_DSGCR_ODTPDD_MASK		GENMASK(23, 20)
+#define DDRPHYC_DSGCR_ODTPDD_0			BIT(20)
+#define DDRPHYC_DSGCR_NL2PD			BIT(24)
+#define DDRPHYC_DSGCR_CKOE			BIT(28)
+
+#define DDRPHYC_ZQ0CRN_ZQPD			BIT(31)
+
+#define DDRPHYC_DXNDLLCR_DLLDIS			BIT(31)
+
+#define BOOT_API_A7_CORE0_MAGIC_NUMBER		0xca7face0
+#define BOOT_API_A7_CORE1_MAGIC_NUMBER		0xca7face1
+
+#define MPIDR_AFF0				GENMASK(7, 0)
+
+#define RCC_MP_GRSTCSETR			(STM32_RCC_BASE + 0x0404)
+#define RCC_MP_GRSTCSETR_MPSYSRST		BIT(0)
+#define RCC_MP_GRSTCSETR_MPUP0RST		BIT(4)
+#define RCC_MP_GRSTCSETR_MPUP1RST		BIT(5)
+
+/* IWDG */
+#define IWDG_KR					0x00
+#define IWDG_KR_RELOAD_KEY			0xaaaa
+#define IWDG_EWCR				0x14
+#define IWDG_EWCR_EWIC				BIT(14)
+
+#define STM32MP1_PSCI_NR_CPUS			2
+#if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS
+#error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS"
+#endif
+
+u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = {
+	 PSCI_AFFINITY_LEVEL_ON,
+	 PSCI_AFFINITY_LEVEL_OFF};
+
+static u32 __secure_data cntfrq;
+
+static u32 __secure cp15_read_cntfrq(void)
+{
+	u32 frq;
+
+	asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq));
+
+	return frq;
+}
+
+static void __secure cp15_write_cntfrq(u32 frq)
+{
+	asm volatile ("mcr p15, 0, %0, c14, c0, 0" : : "r" (frq));
+}
+
+static inline void psci_set_state(int cpu, u8 state)
+{
+	psci_state[cpu] = state;
+	dsb();
+	isb();
+}
+
+static u32 __secure stm32mp_get_gicd_base_address(void)
+{
+	u32 periphbase;
+
+	/* get the GIC base address from the CBAR register */
+	asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
+
+	return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET;
+}
+
+static void __secure stm32mp_raise_sgi0(int cpu)
+{
+	u32 gic_dist_addr;
+
+	gic_dist_addr = stm32mp_get_gicd_base_address();
+
+	/* ask cpu with SGI0 */
+	writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR);
+}
+
+void __secure psci_arch_cpu_entry(void)
+{
+	u32 cpu = psci_get_cpu_id();
+
+	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
+
+	/* write the saved cntfrq */
+	cp15_write_cntfrq(cntfrq);
+
+	/* reset magic in TAMP register */
+	writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
+}
+
+s32 __secure psci_features(u32 function_id, u32 psci_fid)
+{
+	switch (psci_fid) {
+	case ARM_PSCI_0_2_FN_PSCI_VERSION:
+	case ARM_PSCI_0_2_FN_CPU_OFF:
+	case ARM_PSCI_0_2_FN_CPU_ON:
+	case ARM_PSCI_0_2_FN_AFFINITY_INFO:
+	case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+	case ARM_PSCI_0_2_FN_SYSTEM_OFF:
+	case ARM_PSCI_0_2_FN_SYSTEM_RESET:
+	case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND:
+		return 0x0;
+	}
+	return ARM_PSCI_RET_NI;
+}
+
+u32 __secure psci_version(void)
+{
+	return ARM_PSCI_VER_1_0;
+}
+
+s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity,
+				u32  lowest_affinity_level)
+{
+	u32 cpu = target_affinity & MPIDR_AFF0;
+
+	if (lowest_affinity_level > 0)
+		return ARM_PSCI_RET_INVAL;
+
+	if (target_affinity & ~MPIDR_AFF0)
+		return ARM_PSCI_RET_INVAL;
+
+	if (cpu >= STM32MP1_PSCI_NR_CPUS)
+		return ARM_PSCI_RET_INVAL;
+
+	return psci_state[cpu];
+}
+
+u32 __secure psci_migrate_info_type(void)
+{
+	/*
+	 * in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+	 * return 2 = Trusted OS is either not present or does not require
+	 * migration, system of this type does not require the caller
+	 * to use the MIGRATE function.
+	 * MIGRATE function calls return NOT_SUPPORTED.
+	 */
+	return 2;
+}
+
+s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
+			 u32 context_id)
+{
+	u32 cpu = target_cpu & MPIDR_AFF0;
+
+	if (target_cpu & ~MPIDR_AFF0)
+		return ARM_PSCI_RET_INVAL;
+
+	if (cpu >= STM32MP1_PSCI_NR_CPUS)
+		return ARM_PSCI_RET_INVAL;
+
+	if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON)
+		return ARM_PSCI_RET_ALREADY_ON;
+
+	/* read and save cntfrq of current cpu to write on target cpu  */
+	cntfrq = cp15_read_cntfrq();
+
+	/* reset magic in TAMP register */
+	if (readl(TAMP_BACKUP_MAGIC_NUMBER))
+		writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
+	/*
+	 * ROM code need a first SGI0 after core reset
+	 * core is ready when magic is set to 0 in ROM code
+	 */
+	while (readl(TAMP_BACKUP_MAGIC_NUMBER))
+		stm32mp_raise_sgi0(cpu);
+
+	/* store target PC and context id*/
+	psci_save(cpu, pc, context_id);
+
+	/* write entrypoint in backup RAM register */
+	writel((u32)&psci_cpu_entry, TAMP_BACKUP_BRANCH_ADDRESS);
+	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING);
+
+	/* write magic number in backup register */
+	if (cpu == 0x01)
+		writel(BOOT_API_A7_CORE1_MAGIC_NUMBER,
+		       TAMP_BACKUP_MAGIC_NUMBER);
+	else
+		writel(BOOT_API_A7_CORE0_MAGIC_NUMBER,
+		       TAMP_BACKUP_MAGIC_NUMBER);
+
+	/* Generate an IT to start the core */
+	stm32mp_raise_sgi0(cpu);
+
+	return ARM_PSCI_RET_SUCCESS;
+}
+
+s32 __secure psci_cpu_off(void)
+{
+	u32 cpu;
+
+	cpu = psci_get_cpu_id();
+
+	psci_cpu_off_common();
+	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);
+
+	/* reset core: wfi is managed by BootRom */
+	if (cpu == 0x01)
+		writel(RCC_MP_GRSTCSETR_MPUP1RST, RCC_MP_GRSTCSETR);
+	else
+		writel(RCC_MP_GRSTCSETR_MPUP0RST, RCC_MP_GRSTCSETR);
+
+	/* just waiting reset */
+	while (1)
+		wfi();
+}
+
+void __secure psci_system_reset(void)
+{
+	/* System reset */
+	writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
+	/* just waiting reset */
+	while (1)
+		wfi();
+}
+
+void __secure psci_system_off(void)
+{
+	/* System Off is not managed, waiting user power off
+	 * TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
+	 */
+	while (1)
+		wfi();
+}
+
+static void __secure secure_udelay(unsigned int delay)
+{
+	u32 freq = cp15_read_cntfrq() / 1000000;
+	u64 start, end;
+
+	delay *= freq;
+
+	asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start));
+	for (;;) {
+		asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end));
+		if ((end - start) > delay)
+			break;
+	}
+}
+
+static int __secure secure_waitbits(u32 reg, u32 mask, u32 val)
+{
+	u32 freq = cp15_read_cntfrq() / 1000000;
+	u32 delay = 500 * freq;	/* 500 us */
+	u64 start, end;
+	u32 tmp;
+
+	asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start));
+	for (;;) {
+		tmp = readl(reg);
+		tmp &= mask;
+		if ((tmp & val) == val)
+			return 0;
+		asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end));
+		if ((end - start) > delay)
+			return -ETIMEDOUT;
+	}
+}
+
+static void __secure ddr_sr_mode_ssr(u32 *saved_pwrctl)
+{
+	setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
+		     RCC_DDRITFCR_DDRC1LPEN | RCC_DDRITFCR_DDRC1EN |
+		     RCC_DDRITFCR_DDRC2LPEN | RCC_DDRITFCR_DDRC2EN |
+		     RCC_DDRITFCR_DDRCAPBLPEN | RCC_DDRITFCR_DDRPHYCAPBLPEN |
+		     RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN |
+		     RCC_DDRITFCR_DDRPHYCEN);
+
+	clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
+		     RCC_DDRITFCR_AXIDCGEN | RCC_DDRITFCR_DDRCKMOD_MASK);
+
+	/* Disable HW LP interface of uMCTL2 */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_HWLPCTL,
+		     DDRCTRL_HWLPCTL_HW_LP_EN);
+
+	/* Configure Automatic LP modes of uMCTL2 */
+	clrsetbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRTMG,
+			DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK,
+			DDRCTRL_PWRTMG_SELFREF_TO_X32_0);
+
+	/* Save PWRCTL register to restart ASR after suspend (if applicable) */
+	*saved_pwrctl = readl(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL);
+
+	/*
+	 * Disable Clock disable with LP modes
+	 * (used in RUN mode for LPDDR2 with specific timing).
+	 */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
+		     DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
+
+	/* Disable automatic Self-Refresh mode */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
+		     DDRCTRL_PWRCTL_SELFREF_EN);
+}
+
+static void __secure ddr_sr_mode_restore(u32 saved_pwrctl)
+{
+	saved_pwrctl &= DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
+			DDRCTRL_PWRCTL_SELFREF_EN;
+
+	/* Restore ASR mode in case it was enabled before suspend. */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, saved_pwrctl);
+}
+
+static int __secure ddr_sw_self_refresh_in(void)
+{
+	int ret;
+
+	clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
+
+	/* Blocks AXI ports from taking anymore transactions */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0,
+		     DDRCTRL_PCTRL_N_PORT_EN);
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1,
+		     DDRCTRL_PCTRL_N_PORT_EN);
+
+	/*
+	 * Waits unit all AXI ports are idle
+	 * Poll PSTAT.rd_port_busy_n = 0
+	 * Poll PSTAT.wr_port_busy_n = 0
+	 */
+	ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_PSTAT,
+			      DDRCTRL_PSTAT_RD_PORT_BUSY_0 |
+			      DDRCTRL_PSTAT_RD_PORT_BUSY_1 |
+			      DDRCTRL_PSTAT_WR_PORT_BUSY_0 |
+			      DDRCTRL_PSTAT_WR_PORT_BUSY_1, 0);
+	if (ret)
+		goto pstat_failed;
+
+	/* SW Self-Refresh entry */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
+
+	/*
+	 * Wait operating mode change in self-refresh mode
+	 * with STAT.operating_mode[1:0]==11.
+	 * Ensure transition to self-refresh was due to software
+	 * by checking also that STAT.selfref_type[1:0]=2.
+	 */
+	ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT,
+			      DDRCTRL_STAT_OPERATING_MODE_MASK |
+			      DDRCTRL_STAT_SELFREF_TYPE_MASK,
+			      DDRCTRL_STAT_OPERATING_MODE_SR |
+			      DDRCTRL_STAT_SELFREF_TYPE_SR);
+	if (ret)
+		goto selfref_sw_failed;
+
+	/* IOs powering down (PUBL registers) */
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR);
+
+	clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
+			DDRPHYC_ACIOCR_CKPDD_MASK,
+			DDRPHYC_ACIOCR_CKPDD_0);
+
+	clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
+			DDRPHYC_ACIOCR_CKPDR_MASK,
+			DDRPHYC_ACIOCR_CKPDR_0);
+
+	clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
+			DDRPHYC_ACIOCR_CSPDD_MASK,
+			DDRPHYC_ACIOCR_CSPDD_0);
+
+	/* Disable command/address output driver */
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
+
+	clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR,
+			DDRPHYC_DSGCR_ODTPDD_MASK,
+			DDRPHYC_DSGCR_ODTPDD_0);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
+
+	clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR,
+			DDRPHYC_DSGCR_CKEPDD_MASK,
+			DDRPHYC_DSGCR_CKEPDD_0);
+
+	/* Disable PZQ cell (PUBL register) */
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
+
+	/* Set latch */
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
+
+	/* Additional delay to avoid early latch */
+	secure_udelay(10);
+
+	/* Activate sw retention in PWRCTRL */
+	setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN);
+
+	/* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
+	setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
+
+	/* Disable all DLLs: GLITCH window */
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLDIS);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	/* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */
+	clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
+
+	/* Deactivate all DDR clocks */
+	clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
+		     RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN |
+		     RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN);
+
+	return 0;
+
+selfref_sw_failed:
+	/* This bit should be cleared to restore DDR in its previous state */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
+		     DDRCTRL_PWRCTL_SELFREF_SW);
+
+pstat_failed:
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0,
+		     DDRCTRL_PCTRL_N_PORT_EN);
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1,
+		     DDRCTRL_PCTRL_N_PORT_EN);
+
+	return -EINVAL;
+};
+
+static void __secure ddr_sw_self_refresh_exit(void)
+{
+	int ret;
+
+	/* Enable all clocks */
+	setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
+		     RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN |
+		     RCC_DDRITFCR_DDRPHYCEN | RCC_DDRITFCR_DDRPHYCAPBEN |
+		     RCC_DDRITFCR_DDRCAPBEN);
+
+	/* Handshake */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
+
+	/* Mask dfi_init_complete_en */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC,
+		     DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+
+	/* Ack */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
+	ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT,
+			      DDRCTRL_SWSTAT_SW_DONE_ACK,
+			      DDRCTRL_SWSTAT_SW_DONE_ACK);
+	if (ret)
+		hang();
+
+	/* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
+	setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
+
+	/* Enable all DLLs: GLITCH window */
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR,
+		     DDRPHYC_ACDLLCR_DLLDIS);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS);
+
+	/* Additional delay to avoid early DLL clock switch */
+	secure_udelay(50);
+
+	/* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
+	clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST);
+
+	secure_udelay(10);
+
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST);
+
+	/* PHY partial init: (DLL lock and ITM reset) */
+	writel(DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK |
+	       DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT,
+	       STM32_DDRPHYC_BASE + DDRPHYC_PIR);
+
+	/* Need to wait at least 10 clock cycles before accessing PGSR */
+	secure_udelay(1);
+
+	/* Pool end of init */
+	ret = secure_waitbits(STM32_DDRPHYC_BASE + DDRPHYC_PGSR,
+			      DDRPHYC_PGSR_IDONE, DDRPHYC_PGSR_IDONE);
+	if (ret)
+		hang();
+
+	/* Handshake */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
+
+	/* Unmask dfi_init_complete_en to uMCTL2 */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+
+	/* Ack */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
+	ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT,
+			      DDRCTRL_SWSTAT_SW_DONE_ACK,
+			      DDRCTRL_SWSTAT_SW_DONE_ACK);
+	if (ret)
+		hang();
+
+	/* Deactivate sw retention in PWR */
+	clrbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN);
+
+	/* Enable PZQ cell (PUBL register) */
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
+
+	/* Enable pad drivers */
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
+
+	/* Enable command/address output driver */
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CKPDD_MASK);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CSPDD_MASK);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
+
+	/* Release latch */
+	setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_ODTPDD_MASK);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
+
+	clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKEPDD_MASK);
+
+	/* Remove selfrefresh */
+	clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
+
+	/* Wait operating_mode == normal */
+	ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT,
+			      DDRCTRL_STAT_OPERATING_MODE_MASK,
+			      DDRCTRL_STAT_OPERATING_MODE_NORMAL);
+	if (ret)
+		hang();
+
+	/* AXI ports are no longer blocked from taking transactions */
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN);
+	setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN);
+
+	setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
+}
+
+void __secure psci_system_suspend(u32 __always_unused function_id,
+				  u32 ep, u32 context_id)
+{
+	u32 saved_mcudivr, saved_pll3cr, saved_pll4cr, saved_mssckselr;
+	u32 gicd_addr = stm32mp_get_gicd_base_address();
+	bool iwdg1_wake = false;
+	bool iwdg2_wake = false;
+	bool other_wake = false;
+	u32 saved_pwrctl, reg;
+	u32 gic_enabled[8];
+	u32 irqs;
+	int i;
+
+	/* Cache enable mask of all 256 SPI */
+	for (i = 0; i < ARRAY_SIZE(gic_enabled); i++)
+		gic_enabled[i] = readl(gicd_addr + GICD_ISENABLERn + 0x4 + 4 * i);
+
+	/* Disable IO compensation */
+
+	/* Place current APSRC/ANSRC into RAPSRC/RANSRC */
+	reg = readl(STM32_SYSCFG_BASE + SYSCFG_CMPCR);
+	reg >>= 8;
+	reg &= 0xff << 16;
+	reg |= SYSCFG_CMPCR_SW_CTRL;
+	writel(reg, STM32_SYSCFG_BASE + SYSCFG_CMPCR);
+	writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENCLRR);
+
+	writel(RCC_MP_CIFR_WKUPF, STM32_RCC_BASE + RCC_MP_CIFR);
+	setbits_le32(STM32_RCC_BASE + RCC_MP_CIER, RCC_MP_CIFR_WKUPF);
+
+	setbits_le32(STM32_PWR_BASE + PWR_MPUCR,
+		     PWR_MPUCR_CSSF | PWR_MPUCR_CSTDBYDIS);
+
+	saved_mcudivr = readl(STM32_RCC_BASE + RCC_MCUDIVR);
+	saved_pll3cr = readl(STM32_RCC_BASE + RCC_PLL3CR);
+	saved_pll4cr = readl(STM32_RCC_BASE + RCC_PLL4CR);
+	saved_mssckselr = readl(STM32_RCC_BASE + RCC_MSSCKSELR);
+
+	psci_v7_flush_dcache_all();
+	ddr_sr_mode_ssr(&saved_pwrctl);
+	ddr_sw_self_refresh_in();
+	setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN);
+	writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR);
+
+	/* Ping the IWDG before entering suspend */
+	iwdg1_wake = !!(gic_enabled[4] & BIT(22));	/* SPI 150 */
+	iwdg2_wake = !!(gic_enabled[4] & BIT(23));	/* SPI 151 */
+
+	for (;;) {
+		/* Ping IWDG1 and ACK pretimer IRQ */
+		if (iwdg1_wake) {
+			writel(IWDG_KR_RELOAD_KEY, STM32_IWDG1_BASE + IWDG_KR);
+			writel(IWDG_EWCR_EWIC, STM32_IWDG1_BASE + IWDG_EWCR);
+		}
+
+		/* Ping IWDG2 and ACK pretimer IRQ */
+		if (iwdg2_wake) {
+			writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR);
+			writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR);
+		}
+
+		iwdg1_wake = false;
+		iwdg2_wake = false;
+
+		/* Zzz, enter stop mode */
+		asm volatile(
+			"isb\n"
+			"dsb\n"
+			"wfi\n");
+
+		/* Determine the wake up source */
+		for (i = 0; i < ARRAY_SIZE(gic_enabled); i++) {
+			irqs = readl(gicd_addr + GICR_IGROUPMODRn + 0x4 + 4 * i);
+			irqs &= gic_enabled[i];
+			if (!irqs)
+				continue;
+
+			/* Test whether IWDG pretimeout triggered the wake up. */
+			if (i == 4) {	/* SPI Num 128..159 */
+				iwdg1_wake = !!(irqs & BIT(22));	/* SPI 150 */
+				iwdg2_wake = !!(irqs & BIT(23));	/* SPI 151 */
+				irqs &= ~(BIT(22) | BIT(23));
+			}
+
+			/* Test whether there is any other wake up trigger. */
+			if (irqs) {
+				other_wake = true;
+				break;
+			}
+		}
+
+		/* Other wake up triggers pending, let OS deal with all of it. */
+		if (other_wake)
+			break;
+	}
+
+	writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR);
+	ddr_sw_self_refresh_exit();
+	ddr_sr_mode_restore(saved_pwrctl);
+
+	writel(saved_mcudivr, STM32_RCC_BASE + RCC_MCUDIVR);
+	writel(saved_pll3cr, STM32_RCC_BASE + RCC_PLL3CR);
+	writel(saved_pll4cr, STM32_RCC_BASE + RCC_PLL4CR);
+	writel(saved_mssckselr, STM32_RCC_BASE + RCC_MSSCKSELR);
+
+	writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENSETR);
+	clrbits_le32(STM32_SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
+}
diff --git a/arch/arm/mach-stm32mp/stm32mp1/pwr_regulator.c b/arch/arm/mach-stm32mp/stm32mp1/pwr_regulator.c
new file mode 100644
index 0000000..846637a
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/pwr_regulator.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define STM32MP_PWR_CR3 0xc
+#define STM32MP_PWR_CR3_USB33DEN BIT(24)
+#define STM32MP_PWR_CR3_USB33RDY BIT(26)
+#define STM32MP_PWR_CR3_REG18DEN BIT(28)
+#define STM32MP_PWR_CR3_REG18RDY BIT(29)
+#define STM32MP_PWR_CR3_REG11DEN BIT(30)
+#define STM32MP_PWR_CR3_REG11RDY BIT(31)
+
+struct stm32mp_pwr_reg_info {
+	u32 enable;
+	u32 ready;
+	char *name;
+};
+
+struct stm32mp_pwr_priv {
+	fdt_addr_t base;
+};
+
+static int stm32mp_pwr_write(struct udevice *dev, uint reg,
+			     const uint8_t *buff, int len)
+{
+	struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
+	u32 val = *(u32 *)buff;
+
+	if (len != 4)
+		return -EINVAL;
+
+	writel(val, priv->base + STM32MP_PWR_CR3);
+
+	return 0;
+}
+
+static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
+			    int len)
+{
+	struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
+
+	if (len != 4)
+		return -EINVAL;
+
+	*(u32 *)buff = readl(priv->base + STM32MP_PWR_CR3);
+
+	return 0;
+}
+
+static int stm32mp_pwr_of_to_plat(struct udevice *dev)
+{
+	struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr(dev);
+	if (priv->base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct pmic_child_info pwr_children_info[] = {
+	{ .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
+	{ .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
+	{ },
+};
+
+static int stm32mp_pwr_bind(struct udevice *dev)
+{
+	int children;
+
+	children = pmic_bind_children(dev, dev_ofnode(dev), pwr_children_info);
+	if (!children)
+		dev_dbg(dev, "no child found\n");
+
+	return 0;
+}
+
+static struct dm_pmic_ops stm32mp_pwr_ops = {
+	.read = stm32mp_pwr_read,
+	.write = stm32mp_pwr_write,
+};
+
+static const struct udevice_id stm32mp_pwr_ids[] = {
+	{ .compatible = "st,stm32mp1,pwr-reg" },
+	{ }
+};
+
+U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
+	.name = "stm32mp_pwr_pmic",
+	.id = UCLASS_PMIC,
+	.of_match = stm32mp_pwr_ids,
+	.bind = stm32mp_pwr_bind,
+	.ops = &stm32mp_pwr_ops,
+	.of_to_plat = stm32mp_pwr_of_to_plat,
+	.priv_auto	= sizeof(struct stm32mp_pwr_priv),
+};
+
+static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
+	.enable = STM32MP_PWR_CR3_REG11DEN,
+	.ready = STM32MP_PWR_CR3_REG11RDY,
+	.name = "reg11"
+};
+
+static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
+	.enable = STM32MP_PWR_CR3_REG18DEN,
+	.ready = STM32MP_PWR_CR3_REG18RDY,
+	.name = "reg18"
+};
+
+static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
+	.enable = STM32MP_PWR_CR3_USB33DEN,
+	.ready = STM32MP_PWR_CR3_USB33RDY,
+	.name = "usb33"
+};
+
+static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
+	&stm32mp_pwr_reg11,
+	&stm32mp_pwr_reg18,
+	&stm32mp_pwr_usb33,
+	NULL
+};
+
+static int stm32mp_pwr_regulator_probe(struct udevice *dev)
+{
+	const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos;
+	struct dm_regulator_uclass_plat *uc_pdata;
+
+	uc_pdata = dev_get_uclass_plat(dev);
+
+	while (*p) {
+		int rc;
+
+		rc = dev_read_stringlist_search(dev, "regulator-name",
+						(*p)->name);
+		if (rc >= 0) {
+			dev_dbg(dev, "found regulator %s\n", (*p)->name);
+			break;
+		} else if (rc != -ENODATA) {
+			return rc;
+		}
+		p++;
+	}
+	if (!*p) {
+		int i = 0;
+		const char *s;
+
+		dev_dbg(dev, "regulator ");
+		while (dev_read_string_index(dev, "regulator-name",
+					     i++, &s) >= 0)
+			dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
+		dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
+		return -EINVAL;
+	}
+
+	uc_pdata->type = REGULATOR_TYPE_FIXED;
+	dev_set_priv(dev, (void *)*p);
+
+	return 0;
+}
+
+static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
+{
+	struct dm_regulator_uclass_plat *uc_pdata;
+
+	uc_pdata = dev_get_uclass_plat(dev);
+	if (!uc_pdata)
+		return -ENXIO;
+
+	if (uc_pdata->min_uV != uV) {
+		dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
+{
+	struct dm_regulator_uclass_plat *uc_pdata;
+
+	uc_pdata = dev_get_uclass_plat(dev);
+	if (!uc_pdata)
+		return -ENXIO;
+
+	if (uc_pdata->min_uV != uc_pdata->max_uV) {
+		dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
+		return -EINVAL;
+	}
+
+	return uc_pdata->min_uV;
+}
+
+static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
+{
+	const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
+	int rc;
+	u32 reg;
+
+	rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+	if (rc)
+		return rc;
+
+	dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
+
+	return (reg & p->enable) != 0;
+}
+
+static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
+{
+	const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
+	int rc;
+	u32 reg;
+	u32 time_start;
+
+	dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
+
+	rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+	if (rc)
+		return rc;
+
+	/* if regulator is already in the wanted state, nothing to do */
+	if (!!(reg & p->enable) == enable)
+		return 0;
+
+	reg &= ~p->enable;
+	if (enable)
+		reg |= p->enable;
+
+	rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+	if (rc)
+		return rc;
+
+	if (!enable)
+		return 0;
+
+	/* waiting ready for enable */
+	time_start = get_timer(0);
+	while (1) {
+		rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+		if (rc)
+			return rc;
+		if (reg & p->ready)
+			break;
+		if (get_timer(time_start) > CONFIG_SYS_HZ) {
+			dev_dbg(dev, "%s: timeout\n", p->name);
+			return -ETIMEDOUT;
+		}
+	}
+	return 0;
+}
+
+static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
+	.set_value  = stm32mp_pwr_regulator_set_value,
+	.get_value  = stm32mp_pwr_regulator_get_value,
+	.get_enable = stm32mp_pwr_regulator_get_enable,
+	.set_enable = stm32mp_pwr_regulator_set_enable,
+};
+
+U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
+	.name = "stm32mp_pwr_regulator",
+	.id = UCLASS_REGULATOR,
+	.ops = &stm32mp_pwr_regulator_ops,
+	.probe = stm32mp_pwr_regulator_probe,
+};
diff --git a/arch/arm/mach-stm32mp/stm32mp1/spl.c b/arch/arm/mach-stm32mp/stm32mp1/spl.c
new file mode 100644
index 0000000..6c79259
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/spl.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <hang.h>
+#include <init.h>
+#include <log.h>
+#include <ram.h>
+#include <spl.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <mach/tzc.h>
+#include <linux/libfdt.h>
+
+u32 spl_boot_device(void)
+{
+	u32 boot_mode;
+
+	boot_mode = get_bootmode();
+
+	switch (boot_mode) {
+	case BOOT_FLASH_SD_1:
+	case BOOT_FLASH_EMMC_1:
+		return BOOT_DEVICE_MMC1;
+	case BOOT_FLASH_SD_2:
+	case BOOT_FLASH_EMMC_2:
+		return BOOT_DEVICE_MMC2;
+	case BOOT_SERIAL_UART_1:
+	case BOOT_SERIAL_UART_2:
+	case BOOT_SERIAL_UART_3:
+	case BOOT_SERIAL_UART_4:
+	case BOOT_SERIAL_UART_5:
+	case BOOT_SERIAL_UART_6:
+	case BOOT_SERIAL_UART_7:
+	case BOOT_SERIAL_UART_8:
+		return BOOT_DEVICE_UART;
+	case BOOT_SERIAL_USB_OTG:
+		return BOOT_DEVICE_DFU;
+	case BOOT_FLASH_NAND_FMC:
+		return BOOT_DEVICE_NAND;
+	case BOOT_FLASH_NOR_QSPI:
+		return BOOT_DEVICE_SPI;
+	case BOOT_FLASH_SPINAND_1:
+		return BOOT_DEVICE_NONE; /* SPINAND not supported in SPL */
+	}
+
+	return BOOT_DEVICE_MMC1;
+}
+
+u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
+{
+	return MMCSD_MODE_RAW;
+}
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+int spl_mmc_boot_partition(const u32 boot_device)
+{
+	switch (boot_device) {
+	case BOOT_DEVICE_MMC1:
+		return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION;
+	case BOOT_DEVICE_MMC2:
+		return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2;
+	default:
+		return -EINVAL;
+	}
+}
+#endif
+
+#ifdef CONFIG_SPL_DISPLAY_PRINT
+void spl_display_print(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	const char *model;
+
+	/* same code than show_board_info() but not compiled for SPL
+	 * see CONFIG_DISPLAY_BOARDINFO & common/board_info.c
+	 */
+	model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
+	if (model)
+		log_info("Model: %s\n", model);
+}
+#endif
+
+__weak int board_early_init_f(void)
+{
+	return 0;
+}
+
+uint32_t stm32mp_get_dram_size(void)
+{
+	struct ram_info ram;
+	struct udevice *dev;
+	int ret;
+
+	if (uclass_get_device(UCLASS_RAM, 0, &dev))
+		return 0;
+
+	ret = ram_get_info(dev, &ram);
+	if (ret)
+		return 0;
+
+	return ram.size;
+}
+
+static int optee_get_reserved_memory(uint32_t *start, uint32_t *size)
+{
+	fdt_addr_t fdt_mem_size;
+	fdt_addr_t fdt_start;
+	ofnode node;
+
+	node = ofnode_path("/reserved-memory/optee");
+	if (!ofnode_valid(node))
+		return 0;
+
+	fdt_start = ofnode_get_addr_size(node, "reg", &fdt_mem_size);
+	*start = fdt_start;
+	*size = fdt_mem_size;
+	return (fdt_start < 0) ? fdt_start : 0;
+}
+
+#define CFG_SHMEM_SIZE			0x200000
+#define STM32_TZC_NSID_ALL		0xffff
+#define STM32_TZC_FILTER_ALL		3
+
+void stm32_init_tzc_for_optee(void)
+{
+	const uint32_t dram_size = stm32mp_get_dram_size();
+	const uintptr_t dram_top = STM32_DDR_BASE + (dram_size - 1);
+	uint32_t optee_base, optee_size, tee_shmem_base;
+	const uintptr_t tzc = STM32_TZC_BASE;
+	int ret;
+
+	if (dram_size == 0)
+		panic("Cannot determine DRAM size from devicetree\n");
+
+	ret = optee_get_reserved_memory(&optee_base, &optee_size);
+	if (ret < 0 || optee_size <= CFG_SHMEM_SIZE)
+		panic("Invalid OPTEE reserved memory in devicetree\n");
+
+	tee_shmem_base = optee_base + optee_size - CFG_SHMEM_SIZE;
+
+	const struct tzc_region optee_config[] = {
+		{
+			.base = STM32_DDR_BASE,
+			.top = optee_base - 1,
+			.sec_mode = TZC_ATTR_SEC_NONE,
+			.nsec_id = STM32_TZC_NSID_ALL,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.base = optee_base,
+			.top = tee_shmem_base - 1,
+			.sec_mode = TZC_ATTR_SEC_RW,
+			.nsec_id = 0,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.base = tee_shmem_base,
+			.top = dram_top,
+			.sec_mode = TZC_ATTR_SEC_NONE,
+			.nsec_id = STM32_TZC_NSID_ALL,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.top = 0,
+		}
+	};
+
+	flush_dcache_all();
+
+	tzc_configure(tzc, optee_config);
+	tzc_dump_config(tzc);
+
+	dcache_disable();
+}
+
+void spl_board_prepare_for_optee(void *fdt)
+{
+	stm32_init_tzc_for_optee();
+}
+
+void board_init_f(ulong dummy)
+{
+	struct udevice *dev;
+	int ret;
+
+	arch_cpu_init();
+	mach_cpu_init();
+
+	ret = spl_early_init();
+	if (ret) {
+		log_debug("spl_early_init() failed: %d\n", ret);
+		hang();
+	}
+
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+	if (ret) {
+		log_debug("Clock init failed: %d\n", ret);
+		hang();
+	}
+
+	ret = uclass_get_device(UCLASS_RESET, 0, &dev);
+	if (ret) {
+		log_debug("Reset init failed: %d\n", ret);
+		hang();
+	}
+
+	ret = uclass_get_device(UCLASS_PINCTRL, 0, &dev);
+	if (ret) {
+		log_debug("%s: Cannot find pinctrl device\n", __func__);
+		hang();
+	}
+
+	/* enable console uart printing */
+	preloader_console_init();
+
+	ret = board_early_init_f();
+	if (ret) {
+		log_debug("board_early_init_f() failed: %d\n", ret);
+		hang();
+	}
+
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret) {
+		log_err("DRAM init failed: %d\n", ret);
+		hang();
+	}
+
+	/*
+	 * activate cache on DDR only when DDR is fully initialized
+	 * to avoid speculative access and issue in get_ram_size()
+	 */
+	if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+		mmu_set_region_dcache_behaviour(STM32_DDR_BASE,
+						CONFIG_DDR_CACHEABLE_SIZE,
+						DCACHE_DEFAULT_OPTION);
+}
+
+void spl_board_prepare_for_boot(void)
+{
+	dcache_disable();
+}
+
+void spl_board_prepare_for_linux(void)
+{
+	dcache_disable();
+}
diff --git a/arch/arm/mach-stm32mp/stm32mp1/stm32mp13x.c b/arch/arm/mach-stm32mp/stm32mp1/stm32mp13x.c
new file mode 100644
index 0000000..845d973
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/stm32mp13x.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <log.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/stm32.h>
+#include <asm/arch/sys_proto.h>
+
+/* SYSCFG register */
+#define SYSCFG_IDC_OFFSET	0x380
+#define SYSCFG_IDC_DEV_ID_MASK	GENMASK(11, 0)
+#define SYSCFG_IDC_DEV_ID_SHIFT	0
+#define SYSCFG_IDC_REV_ID_MASK	GENMASK(31, 16)
+#define SYSCFG_IDC_REV_ID_SHIFT	16
+
+/* Device Part Number (RPN) = OTP_DATA1 lower 11 bits */
+#define RPN_SHIFT	0
+#define RPN_MASK	GENMASK(11, 0)
+
+static u32 read_idc(void)
+{
+	void *syscfg = syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
+
+	return readl(syscfg + SYSCFG_IDC_OFFSET);
+}
+
+u32 get_cpu_dev(void)
+{
+	return (read_idc() & SYSCFG_IDC_DEV_ID_MASK) >> SYSCFG_IDC_DEV_ID_SHIFT;
+}
+
+u32 get_cpu_rev(void)
+{
+	return (read_idc() & SYSCFG_IDC_REV_ID_MASK) >> SYSCFG_IDC_REV_ID_SHIFT;
+}
+
+/* Get Device Part Number (RPN) from OTP */
+static u32 get_cpu_rpn(void)
+{
+	return get_otp(BSEC_OTP_RPN, RPN_SHIFT, RPN_MASK);
+}
+
+u32 get_cpu_type(void)
+{
+	return (get_cpu_dev() << 16) | get_cpu_rpn();
+}
+
+int get_eth_nb(void)
+{
+	int nb_eth = 2;
+
+	switch (get_cpu_type()) {
+	case CPU_STM32MP131Dxx:
+		fallthrough;
+	case CPU_STM32MP131Cxx:
+		fallthrough;
+	case CPU_STM32MP131Axx:
+		nb_eth = 1;
+		break;
+	default:
+		nb_eth = 2;
+		break;
+	}
+
+	return nb_eth;
+}
+
+void get_soc_name(char name[SOC_NAME_SIZE])
+{
+	char *cpu_s, *cpu_r;
+
+	/* MPUs Part Numbers */
+	switch (get_cpu_type()) {
+	case CPU_STM32MP135Fxx:
+		cpu_s = "135F";
+		break;
+	case CPU_STM32MP135Dxx:
+		cpu_s = "135D";
+		break;
+	case CPU_STM32MP135Cxx:
+		cpu_s = "135C";
+		break;
+	case CPU_STM32MP135Axx:
+		cpu_s = "135A";
+		break;
+	case CPU_STM32MP133Fxx:
+		cpu_s = "133F";
+		break;
+	case CPU_STM32MP133Dxx:
+		cpu_s = "133D";
+		break;
+	case CPU_STM32MP133Cxx:
+		cpu_s = "133C";
+		break;
+	case CPU_STM32MP133Axx:
+		cpu_s = "133A";
+		break;
+	case CPU_STM32MP131Fxx:
+		cpu_s = "131F";
+		break;
+	case CPU_STM32MP131Dxx:
+		cpu_s = "131D";
+		break;
+	case CPU_STM32MP131Cxx:
+		cpu_s = "131C";
+		break;
+	case CPU_STM32MP131Axx:
+		cpu_s = "131A";
+		break;
+	default:
+		cpu_s = "????";
+		break;
+	}
+
+	/* REVISION */
+	switch (get_cpu_rev()) {
+	case CPU_REV1:
+		cpu_r = "A";
+		break;
+	case CPU_REV1_1:
+		cpu_r = "Z";
+		break;
+	case CPU_REV1_2:
+		cpu_r = "Y";
+		break;
+	default:
+		cpu_r = "?";
+		break;
+	}
+
+	snprintf(name, SOC_NAME_SIZE, "STM32MP%s Rev.%s", cpu_s, cpu_r);
+}
diff --git a/arch/arm/mach-stm32mp/stm32mp1/stm32mp15x.c b/arch/arm/mach-stm32mp/stm32mp1/stm32mp15x.c
new file mode 100644
index 0000000..afc56b0
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/stm32mp15x.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <env.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/bsec.h>
+#include <asm/arch/stm32.h>
+#include <asm/arch/sys_proto.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+
+/* RCC register */
+#define RCC_TZCR		(STM32_RCC_BASE + 0x00)
+#define RCC_BDCR		(STM32_RCC_BASE + 0x0140)
+#define RCC_MP_APB5ENSETR	(STM32_RCC_BASE + 0x0208)
+#define RCC_MP_AHB5ENSETR	(STM32_RCC_BASE + 0x0210)
+#define RCC_DBGCFGR		(STM32_RCC_BASE + 0x080C)
+
+#define RCC_BDCR_VSWRST		BIT(31)
+#define RCC_BDCR_RTCSRC		GENMASK(17, 16)
+
+#define RCC_DBGCFGR_DBGCKEN	BIT(8)
+
+/* DBGMCU register */
+#define DBGMCU_IDC		(STM32_DBGMCU_BASE + 0x00)
+#define DBGMCU_APB4FZ1		(STM32_DBGMCU_BASE + 0x2C)
+#define DBGMCU_APB4FZ1_IWDG2	BIT(2)
+
+/* Security register */
+#define ETZPC_TZMA1_SIZE	(STM32_ETZPC_BASE + 0x04)
+#define ETZPC_DECPROT0		(STM32_ETZPC_BASE + 0x10)
+
+#define TZC_GATE_KEEPER		(STM32_TZC_BASE + 0x008)
+#define TZC_REGION_ATTRIBUTE0	(STM32_TZC_BASE + 0x110)
+#define TZC_REGION_ID_ACCESS0	(STM32_TZC_BASE + 0x114)
+
+#define TAMP_CR1		(STM32_TAMP_BASE + 0x00)
+
+#define PWR_CR1			(STM32_PWR_BASE + 0x00)
+#define PWR_MCUCR		(STM32_PWR_BASE + 0x14)
+#define PWR_CR1_DBP		BIT(8)
+#define PWR_MCUCR_SBF		BIT(6)
+
+/* GPIOZ registers */
+#define GPIOZ_SECCFGR		0x54004030
+
+/* DBGMCU register */
+#define DBGMCU_IDC		(STM32_DBGMCU_BASE + 0x00)
+#define DBGMCU_IDC_DEV_ID_MASK	GENMASK(11, 0)
+#define DBGMCU_IDC_DEV_ID_SHIFT	0
+#define DBGMCU_IDC_REV_ID_MASK	GENMASK(31, 16)
+#define DBGMCU_IDC_REV_ID_SHIFT	16
+
+/* boot interface from Bootrom
+ * - boot instance = bit 31:16
+ * - boot device = bit 15:0
+ */
+#define BOOTROM_PARAM_ADDR	0x2FFC0078
+#define BOOTROM_MODE_MASK	GENMASK(15, 0)
+#define BOOTROM_MODE_SHIFT	0
+#define BOOTROM_INSTANCE_MASK	 GENMASK(31, 16)
+#define BOOTROM_INSTANCE_SHIFT	16
+
+/* Device Part Number (RPN) = OTP_DATA1 lower 8 bits */
+#define RPN_SHIFT	0
+#define RPN_MASK	GENMASK(7, 0)
+
+/* Package = bit 27:29 of OTP16 => STM32MP15_PKG defines
+ * - 100: LBGA448 (FFI) => AA = LFBGA 18x18mm 448 balls p. 0.8mm
+ * - 011: LBGA354 (LCI) => AB = LFBGA 16x16mm 359 balls p. 0.8mm
+ * - 010: TFBGA361 (FFC) => AC = TFBGA 12x12mm 361 balls p. 0.5mm
+ * - 001: TFBGA257 (LCC) => AD = TFBGA 10x10mm 257 balls p. 0.5mm
+ * - others: Reserved
+ */
+#define PKG_SHIFT	27
+#define PKG_MASK	GENMASK(2, 0)
+
+static void security_init(void)
+{
+	/* Disable the backup domain write protection */
+	/* the protection is enable at each reset by hardware */
+	/* And must be disable by software */
+	setbits_le32(PWR_CR1, PWR_CR1_DBP);
+
+	while (!(readl(PWR_CR1) & PWR_CR1_DBP))
+		;
+
+	/* If RTC clock isn't enable so this is a cold boot then we need
+	 * to reset the backup domain
+	 */
+	if (!(readl(RCC_BDCR) & RCC_BDCR_RTCSRC)) {
+		setbits_le32(RCC_BDCR, RCC_BDCR_VSWRST);
+		while (!(readl(RCC_BDCR) & RCC_BDCR_VSWRST))
+			;
+		clrbits_le32(RCC_BDCR, RCC_BDCR_VSWRST);
+	}
+
+	/* allow non secure access in Write/Read for all peripheral */
+	writel(GENMASK(25, 0), ETZPC_DECPROT0);
+
+	/* Open SYSRAM for no secure access */
+	writel(0x0, ETZPC_TZMA1_SIZE);
+
+	/* enable TZC1 TZC2 clock */
+	writel(BIT(11) | BIT(12), RCC_MP_APB5ENSETR);
+
+	/* Region 0 set to no access by default */
+	/* bit 0 / 16 => nsaid0 read/write Enable
+	 * bit 1 / 17 => nsaid1 read/write Enable
+	 * ...
+	 * bit 15 / 31 => nsaid15 read/write Enable
+	 */
+	writel(0xFFFFFFFF, TZC_REGION_ID_ACCESS0);
+	/* bit 30 / 31 => Secure Global Enable : write/read */
+	/* bit 0 / 1 => Region Enable for filter 0/1 */
+	writel(BIT(0) | BIT(1) | BIT(30) | BIT(31), TZC_REGION_ATTRIBUTE0);
+
+	/* Enable Filter 0 and 1 */
+	setbits_le32(TZC_GATE_KEEPER, BIT(0) | BIT(1));
+
+	/* RCC trust zone deactivated */
+	writel(0x0, RCC_TZCR);
+
+	/* TAMP: deactivate the internal tamper
+	 * Bit 23 ITAMP8E: monotonic counter overflow
+	 * Bit 20 ITAMP5E: RTC calendar overflow
+	 * Bit 19 ITAMP4E: HSE monitoring
+	 * Bit 18 ITAMP3E: LSE monitoring
+	 * Bit 16 ITAMP1E: RTC power domain supply monitoring
+	 */
+	writel(0x0, TAMP_CR1);
+
+	/* GPIOZ: deactivate the security */
+	writel(BIT(0), RCC_MP_AHB5ENSETR);
+	writel(0x0, GPIOZ_SECCFGR);
+}
+
+/*
+ * Debug init
+ */
+void dbgmcu_init(void)
+{
+	/*
+	 * Freeze IWDG2 if Cortex-A7 is in debug mode
+	 * done in TF-A for TRUSTED boot and
+	 * DBGMCU access is controlled by BSEC_DENABLE.DBGSWENABLE
+	 */
+	if (bsec_dbgswenable()) {
+		setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
+		setbits_le32(DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2);
+	}
+}
+
+void spl_board_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	dbgmcu_init();
+
+	/* force probe of BSEC driver to shadow the upper OTP */
+	ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(stm32mp_bsec), &dev);
+	if (ret)
+		log_warning("BSEC probe failed: %d\n", ret);
+}
+
+/* get bootmode from ROM code boot context: saved in TAMP register */
+static void update_bootmode(void)
+{
+	u32 boot_mode;
+	u32 bootrom_itf = readl(BOOTROM_PARAM_ADDR);
+	u32 bootrom_device, bootrom_instance;
+
+	/* enable TAMP clock = RTCAPBEN */
+	writel(BIT(8), RCC_MP_APB5ENSETR);
+
+	/* read bootrom context */
+	bootrom_device =
+		(bootrom_itf & BOOTROM_MODE_MASK) >> BOOTROM_MODE_SHIFT;
+	bootrom_instance =
+		(bootrom_itf & BOOTROM_INSTANCE_MASK) >> BOOTROM_INSTANCE_SHIFT;
+	boot_mode =
+		((bootrom_device << BOOT_TYPE_SHIFT) & BOOT_TYPE_MASK) |
+		((bootrom_instance << BOOT_INSTANCE_SHIFT) &
+		 BOOT_INSTANCE_MASK);
+
+	/* save the boot mode in TAMP backup register */
+	clrsetbits_le32(TAMP_BOOT_CONTEXT,
+			TAMP_BOOT_MODE_MASK,
+			boot_mode << TAMP_BOOT_MODE_SHIFT);
+}
+
+/* weak function: STM32MP15x mach init for boot without TFA */
+void stm32mp_cpu_init(void)
+{
+	if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+		security_init();
+		update_bootmode();
+	}
+
+	/* reset copro state in SPL, when used, or in U-Boot */
+	if (!IS_ENABLED(CONFIG_SPL) || IS_ENABLED(CONFIG_SPL_BUILD)) {
+		/* Reset Coprocessor state unless it wakes up from Standby power mode */
+		if (!(readl(PWR_MCUCR) & PWR_MCUCR_SBF)) {
+			writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE);
+			writel(0, TAMP_COPRO_RSC_TBL_ADDRESS);
+		}
+	}
+}
+
+static u32 read_idc(void)
+{
+	/* DBGMCU access is controlled by BSEC_DENABLE.DBGSWENABLE */
+	if (bsec_dbgswenable()) {
+		setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
+
+		return readl(DBGMCU_IDC);
+	}
+
+	return CPU_DEV_STM32MP15; /* STM32MP15x and unknown revision */
+}
+
+u32 get_cpu_dev(void)
+{
+	return (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
+}
+
+u32 get_cpu_rev(void)
+{
+	return (read_idc() & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
+}
+
+/* Get Device Part Number (RPN) from OTP */
+static u32 get_cpu_rpn(void)
+{
+	return get_otp(BSEC_OTP_RPN, RPN_SHIFT, RPN_MASK);
+}
+
+u32 get_cpu_type(void)
+{
+	return (get_cpu_dev() << 16) | get_cpu_rpn();
+}
+
+int get_eth_nb(void)
+{
+	return 1;
+}
+
+/* Get Package options from OTP */
+u32 get_cpu_package(void)
+{
+	return get_otp(BSEC_OTP_PKG, PKG_SHIFT, PKG_MASK);
+}
+
+static const char * const soc_type[] = {
+	"????",
+	"151C", "151A", "151F", "151D",
+	"153C", "153A", "153F", "153D",
+	"157C", "157A", "157F", "157D"
+};
+
+static const char * const soc_pkg[] = { "??", "AD", "AC", "AB", "AA" };
+static const char * const soc_rev[] = { "?", "A", "B", "Z", "Y"};
+
+static void get_cpu_string_offsets(unsigned int *type, unsigned int *pkg,
+				   unsigned int *rev)
+{
+	u32 cpu_type = get_cpu_type();
+	u32 ct = cpu_type & ~(BIT(7) | BIT(0));
+	u32 cm = ((cpu_type & BIT(7)) >> 6) | (cpu_type & BIT(0));
+
+	/* Bits 0 and 7 are the ACDF, 00:C 01:A 10:F 11:D */
+	switch (ct) {
+	case CPU_STM32MP151Cxx:
+		*type = cm + 1;
+		break;
+	case CPU_STM32MP153Cxx:
+		*type = cm + 5;
+		break;
+	case CPU_STM32MP157Cxx:
+		*type = cm + 9;
+		break;
+	default:
+		*type = 0;
+		break;
+	}
+
+	/* Package */
+	*pkg = get_cpu_package();
+	if (*pkg > STM32MP15_PKG_AA_LBGA448)
+		*pkg = STM32MP15_PKG_UNKNOWN;
+
+	/* Revision */
+	switch (get_cpu_rev()) {
+	case CPU_REV1:
+		*rev = 1;
+		break;
+	case CPU_REV2:
+		*rev = 2;
+		break;
+	case CPU_REV2_1:
+		*rev = 3;
+		break;
+	case CPU_REV2_2:
+		*rev = 4;
+		break;
+	default:
+		*rev = 0;
+		break;
+	}
+}
+
+void get_soc_name(char name[SOC_NAME_SIZE])
+{
+	unsigned int type, pkg, rev;
+
+	get_cpu_string_offsets(&type, &pkg, &rev);
+
+	snprintf(name, SOC_NAME_SIZE, "STM32MP%s%s Rev.%s",
+		 soc_type[type], soc_pkg[pkg], soc_rev[rev]);
+}
+
+static void setup_soc_type_pkg_rev(void)
+{
+	unsigned int type, pkg, rev;
+
+	get_cpu_string_offsets(&type, &pkg, &rev);
+
+	env_set("soc_type", soc_type[type]);
+	env_set("soc_pkg", soc_pkg[pkg]);
+	env_set("soc_rev", soc_rev[rev]);
+}
+
+/* weak function called in arch_misc_init */
+void stm32mp_misc_init(void)
+{
+	setup_soc_type_pkg_rev();
+}
diff --git a/arch/arm/mach-stm32mp/stm32mp1/tzc400.c b/arch/arm/mach-stm32mp/stm32mp1/tzc400.c
new file mode 100644
index 0000000..cdc4a40
--- /dev/null
+++ b/arch/arm/mach-stm32mp/stm32mp1/tzc400.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simple API for configuring TrustZone memory restrictions for TZC400
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <linux/iopoll.h>
+#include <mach/tzc.h>
+
+#define TZC_TIMEOUT_US		100
+
+#define TZC_BUILD_CONFIG	0x00
+#define TZC_ACTION		0x04
+#define TZC_ACTION_NONE		0
+#define TZC_ACTION_ERR		1
+#define TZC_ACTION_INT		2
+#define TZC_ACTION_INT_ERR	3
+#define TZC_GATE_KEEPER		0x08
+
+#define TZC_REGION0_OFFSET	0x100
+#define TZC_REGION_CFG_SIZE	0x20
+#define TZC_REGION1_OFFSET	0x120
+#define TZC_REGION_BASE		0x00
+#define TZC_REGION_TOP		0x08
+#define TZC_REGION_ATTRIBUTE	0x10
+#define TZC_REGION_ACCESS	0x14
+
+static uint32_t tzc_read(uintptr_t tzc, size_t reg)
+{
+	return readl(tzc + reg);
+}
+
+static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val)
+{
+	writel(val, tzc + reg);
+}
+
+static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg)
+{
+	uint16_t active_filters = 0;
+
+	for ( ; cfg->top != 0; cfg++)
+		active_filters |= cfg->filters_mask;
+
+	return active_filters;
+}
+
+int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg)
+{
+	uintptr_t region = tzc + TZC_REGION1_OFFSET;
+	uint32_t nsid, attr_reg, active_filters;
+	int ret;
+
+	active_filters = tzc_config_get_active_filters(cfg);
+	if (active_filters == 0)
+		return -EINVAL;
+
+	ret = tzc_disable_filters(tzc, active_filters);
+	if (ret < 0)
+		return ret;
+
+	for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) {
+		attr_reg = (cfg->sec_mode & 0x03) << 30;
+		attr_reg |= (cfg->filters_mask & 0x03) << 0;
+		nsid = cfg->nsec_id & 0xffff;
+		nsid |= nsid << 16;
+
+		tzc_write(region, TZC_REGION_BASE, cfg->base);
+		tzc_write(region, TZC_REGION_TOP, cfg->top);
+		tzc_write(region, TZC_REGION_ACCESS, nsid);
+		tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg);
+	}
+
+	tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR);
+	return tzc_enable_filters(tzc, active_filters);
+}
+
+int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate &= ~filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == 0, TZC_TIMEOUT_US);
+}
+
+int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate |= filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == filter_status,
+				 TZC_TIMEOUT_US);
+}
+
+static const char *sec_access_str_from_attr(uint32_t attr)
+{
+	const char *const sec_mode[] = { "none", "RO  ", "WO  ", "RW  " };
+
+	return sec_mode[(attr >> 30) & 0x03];
+}
+
+void tzc_dump_config(uintptr_t tzc)
+{
+	uint32_t build_config, base, top, attr, nsaid;
+	int num_regions, i;
+	uintptr_t region;
+
+	build_config = tzc_read(tzc, TZC_BUILD_CONFIG);
+	num_regions = ((build_config >> 0) & 0x1f) + 1;
+
+	for (i = 0; i < num_regions; i++) {
+		region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE;
+
+		base = tzc_read(region, TZC_REGION_BASE);
+		top = tzc_read(region, TZC_REGION_TOP);
+		attr = tzc_read(region, TZC_REGION_ATTRIBUTE);
+		nsaid = tzc_read(region, TZC_REGION_ACCESS);
+
+		if (attr == 0 && nsaid == 0)
+			continue;
+
+		log_info("TZC region %u: %08x->%08x - filters 0x%x\n",
+			 i, base, top, (attr >> 0) & 0xf);
+		log_info("\t Secure access %s NSAID %08x\n",
+			 sec_access_str_from_attr(attr), nsaid);
+	}
+}