stm32mp1: Add BL32 SP_min secure monitor

Signed-off-by: Yann Gautier <yann.gautier@st.com>
Signed-off-by: Mathieu Belou <mathieu.belou@st.com>
Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com>
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
index 9c148ad..47e1ffc 100644
--- a/plat/st/stm32mp1/include/platform_def.h
+++ b/plat/st/stm32mp1/include/platform_def.h
@@ -18,7 +18,11 @@
  ******************************************************************************/
 
 /* Size of cacheable stacks */
+#if defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE		0x600
+#else
 #define PLATFORM_STACK_SIZE		0xC00
+#endif
 
 /* SSBL = second stage boot loader */
 #define BL33_IMAGE_NAME			"ssbl"
diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h
index 41c46e8..a789d53 100644
--- a/plat/st/stm32mp1/include/stm32mp1_private.h
+++ b/plat/st/stm32mp1/include/stm32mp1_private.h
@@ -11,8 +11,12 @@
 void configure_mmu(void);
 
 void stm32mp1_arch_security_setup(void);
+void stm32mp1_security_setup(void);
 
 void stm32mp1_save_boot_ctx_address(uintptr_t address);
 uintptr_t stm32mp1_get_boot_ctx_address(void);
 
+void stm32mp1_gic_pcpu_init(void);
+void stm32mp1_gic_init(void);
+
 #endif /* __STM32MP1_PRIVATE_H__ */
diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
new file mode 100644
index 0000000..9fde153
--- /dev/null
+++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SP_MIN_WITH_SECURE_FIQ	:=	1
+
+BL32_SOURCES		+=	plat/common/aarch32/platform_mp_stack.S		\
+				plat/st/stm32mp1/sp_min/sp_min_setup.c		\
+				plat/st/stm32mp1/stm32mp1_pm.c			\
+				plat/st/stm32mp1/stm32mp1_topology.c
+# Generic GIC v2
+BL32_SOURCES		+=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				plat/common/plat_gicv2.c		\
+				plat/st/stm32mp1/stm32mp1_gic.c
+
+# Generic PSCI
+BL32_SOURCES		+=	plat/common/plat_psci_common.c
diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
new file mode 100644
index 0000000..1329bdb
--- /dev/null
+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <generic_delay_timer.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <platform_sp_min.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_dt.h>
+#include <stm32mp1_private.h>
+#include <string.h>
+#include <tzc400.h>
+#include <xlat_tables_v2.h>
+
+/******************************************************************************
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL32 from BL2.
+ ******************************************************************************/
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Interrupt handler for FIQ (secure IRQ)
+ ******************************************************************************/
+void sp_min_plat_fiq_handler(uint32_t id)
+{
+	switch (id) {
+	case STM32MP1_IRQ_TZC400:
+		ERROR("STM32MP1_IRQ_TZC400 generated\n");
+		panic();
+		break;
+	case STM32MP1_IRQ_AXIERRIRQ:
+		ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n");
+		panic();
+		break;
+	default:
+		ERROR("SECURE IT handler not define for it : %i", id);
+		break;
+	}
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = &bl33_image_ep_info;
+
+	if (next_image_info->pc == 0U) {
+		return NULL;
+	}
+
+	return next_image_info;
+}
+
+/*******************************************************************************
+ * Perform any BL32 specific platform actions.
+ ******************************************************************************/
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				  u_register_t arg2, u_register_t arg3)
+{
+	struct dt_node_info dt_dev_info;
+	int result;
+	bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
+
+	/* Imprecise aborts can be masked in NonSecure */
+	write_scr(read_scr() | SCR_AW_BIT);
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params != NULL) {
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			bl33_image_ep_info = *bl_params->ep_info;
+			break;
+		}
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (dt_open_and_check() < 0) {
+		panic();
+	}
+
+	if (stm32mp1_clk_probe() < 0) {
+		panic();
+	}
+
+	result = dt_get_stdout_uart_info(&dt_dev_info);
+
+	if ((result > 0) && dt_dev_info.status) {
+		if (console_init(dt_dev_info.base, 0, STM32MP1_UART_BAUDRATE)
+		    == 0) {
+			panic();
+		}
+	}
+}
+
+/*******************************************************************************
+ * Initialize the MMU, security and the GIC.
+ ******************************************************************************/
+void sp_min_platform_setup(void)
+{
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+
+	configure_mmu();
+
+	/* Initialize tzc400 after DDR initialization */
+	stm32mp1_security_setup();
+
+	generic_delay_timer_init();
+
+	stm32mp1_gic_init();
+}
+
+void sp_min_plat_arch_setup(void)
+{
+}
diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c
index e2f90d2..68ca7db 100644
--- a/plat/st/stm32mp1/stm32mp1_common.c
+++ b/plat/st/stm32mp1/stm32mp1_common.c
@@ -43,6 +43,14 @@
 					MT_SECURE | \
 					MT_EXECUTE_NEVER)
 
+#define MAP_DDR_NS	MAP_REGION_FLAT(STM32MP1_DDR_BASE, \
+					STM32MP1_DDR_MAX_SIZE, \
+					MT_MEMORY | \
+					MT_RW | \
+					MT_NS | \
+					MT_EXECUTE_NEVER)
+
+#if defined(IMAGE_BL2)
 static const mmap_region_t stm32mp1_mmap[] = {
 	MAP_SRAM,
 	MAP_DEVICE1,
@@ -50,6 +58,16 @@
 	MAP_DDR,
 	{0}
 };
+#endif
+#if defined(IMAGE_BL32)
+static const mmap_region_t stm32mp1_mmap[] = {
+	MAP_SRAM,
+	MAP_DEVICE1,
+	MAP_DEVICE2,
+	MAP_DDR_NS,
+	{0}
+};
+#endif
 
 void configure_mmu(void)
 {
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index 5ff509c..bb3fecf 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -71,7 +71,12 @@
  * MAX_MMAP_REGIONS is usually:
  * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
  */
-#define MAX_MMAP_REGIONS		11
+#if defined(IMAGE_BL2)
+  #define MAX_MMAP_REGIONS		11
+#endif
+#if defined(IMAGE_BL32)
+  #define MAX_MMAP_REGIONS		6
+#endif
 
 /* DTB initialization value */
 #define STM32MP1_DTB_SIZE		U(0x00004000)	/* 16Ko for DTB */
diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c
new file mode 100644
index 0000000..11eb0a3
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_gic.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl_common.h>
+#include <gicv2.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <utils.h>
+
+#include <stm32mp1_private.h>
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t stm32mp1_interrupt_props[] = {
+	PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+	PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const gicv2_driver_data_t platform_gic_data = {
+	.gicd_base = STM32MP1_GICD_BASE,
+	.gicc_base = STM32MP1_GICC_BASE,
+	.interrupt_props = stm32mp1_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+void stm32mp1_gic_init(void)
+{
+	gicv2_driver_init(&platform_gic_data);
+	gicv2_distif_init();
+
+	stm32mp1_gic_pcpu_init();
+}
+
+void stm32mp1_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+	gicv2_cpuif_enable();
+}
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
new file mode 100644
index 0000000..e24af0e
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <boot_api.h>
+#include <debug.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <errno.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <platform.h>
+#include <psci.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_private.h>
+#include <stm32mp1_rcc.h>
+
+static uint32_t stm32_sec_entrypoint;
+static uint32_t cntfrq_core0;
+
+#define SEND_SECURE_IT_TO_CORE_1	0x20000U
+
+/*******************************************************************************
+ * STM32MP1 handler called when a CPU is about to enter standby.
+ * call by core 1 to enter in wfi
+ ******************************************************************************/
+static void stm32_cpu_standby(plat_local_state_t cpu_state)
+{
+	uint32_t interrupt = GIC_SPURIOUS_INTERRUPT;
+
+	assert(cpu_state == ARM_LOCAL_STATE_RET);
+
+	/*
+	 * Enter standby state
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	while (interrupt == GIC_SPURIOUS_INTERRUPT) {
+		wfi();
+
+		/* Acknoledge IT */
+		interrupt = gicv2_acknowledge_interrupt();
+		/* If Interrupt == 1022 it will be acknowledged by non secure */
+		if ((interrupt != PENDING_G1_INTID) &&
+		    (interrupt != GIC_SPURIOUS_INTERRUPT)) {
+			gicv2_end_of_interrupt(interrupt);
+		}
+	}
+}
+
+/*******************************************************************************
+ * STM32MP1 handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ * call by core  0 to activate core 1
+ ******************************************************************************/
+static int stm32_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned long current_cpu_mpidr = read_mpidr_el1();
+	uint32_t tamp_clk_off = 0;
+	uint32_t bkpr_core1_addr =
+		tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
+	uint32_t bkpr_core1_magic =
+		tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
+
+	if (mpidr == current_cpu_mpidr) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) ||
+	    (stm32_sec_entrypoint > (STM32MP1_SRAM_BASE +
+				     (STM32MP1_SRAM_SIZE - 1)))) {
+		return PSCI_E_INVALID_ADDRESS;
+	}
+
+	if (!stm32mp1_clk_is_enabled(RTCAPB)) {
+		tamp_clk_off = 1;
+		if (stm32mp1_clk_enable(RTCAPB) != 0) {
+			panic();
+		}
+	}
+
+	cntfrq_core0 = read_cntfrq_el0();
+
+	/* Write entrypoint in backup RAM register */
+	mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint);
+
+	/* Write magic number in backup register */
+	mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER);
+
+	if (tamp_clk_off != 0U) {
+		if (stm32mp1_clk_disable(RTCAPB) != 0) {
+			panic();
+		}
+	}
+
+	/* Generate an IT to core 1 */
+	mmio_write_32(STM32MP1_GICD_BASE + GICD_SGIR,
+		      SEND_SECURE_IT_TO_CORE_1 | ARM_IRQ_SEC_SGI_0);
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * STM32MP1 handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+static void stm32_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	/* Nothing to do */
+}
+
+/*******************************************************************************
+ * STM32MP1 handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	/* Nothing to do, power domain is not disabled */
+}
+
+/*******************************************************************************
+ * STM32MP1 handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ * call by core 1 just after wake up
+ ******************************************************************************/
+static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	stm32mp1_gic_pcpu_init();
+
+	write_cntfrq_el0(cntfrq_core0);
+}
+
+/*******************************************************************************
+ * STM32MP1 handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ ******************************************************************************/
+static void stm32_pwr_domain_suspend_finish(const psci_power_state_t
+					    *target_state)
+{
+	/* Nothing to do, power domain is not disabled */
+}
+
+static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t
+						  *target_state)
+{
+	ERROR("stm32mpu1 Power Down WFI: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 stm32_system_off(void)
+{
+	ERROR("stm32mpu1 System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 stm32_system_reset(void)
+{
+	mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST);
+
+	/* Loop in case system reset is not immediately caught */
+	for ( ; ; ) {
+		;
+	}
+}
+
+static int stm32_validate_power_state(unsigned int power_state,
+				      psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+
+	if (pstate != 0) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (psci_get_pstate_pwrlvl(power_state)) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (psci_get_pstate_id(power_state)) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET;
+	req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int stm32_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/* The non-secure entry point must be in DDR */
+	if (entrypoint < STM32MP1_DDR_BASE) {
+		return PSCI_E_INVALID_ADDRESS;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+static int stm32_node_hw_state(u_register_t target_cpu,
+			       unsigned int power_level)
+{
+	/*
+	 * The format of 'power_level' is implementation-defined, but 0 must
+	 * mean a CPU. Only allow level 0.
+	 */
+	if (power_level != MPIDR_AFFLVL0) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	/*
+	 * From psci view the CPU 0 is always ON,
+	 * CPU 1 can be SUSPEND or RUNNING.
+	 * Therefore do not manage POWER OFF state and always return HW_ON.
+	 */
+
+	return (int)HW_ON;
+}
+
+/*******************************************************************************
+ * Export the platform handlers. The ARM Standard platform layer will take care
+ * of registering the handlers with PSCI.
+ ******************************************************************************/
+static const plat_psci_ops_t stm32_psci_ops = {
+	.cpu_standby = stm32_cpu_standby,
+	.pwr_domain_on = stm32_pwr_domain_on,
+	.pwr_domain_off = stm32_pwr_domain_off,
+	.pwr_domain_suspend = stm32_pwr_domain_suspend,
+	.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
+	.system_off = stm32_system_off,
+	.system_reset = stm32_system_reset,
+	.validate_power_state = stm32_validate_power_state,
+	.validate_ns_entrypoint = stm32_validate_ns_entrypoint,
+	.get_node_hw_state = stm32_node_hw_state
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	stm32_sec_entrypoint = sec_entrypoint;
+	*psci_ops = &stm32_psci_ops;
+
+	return 0;
+}
diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c
index 0cdf305..e783c14 100644
--- a/plat/st/stm32mp1/stm32mp1_security.c
+++ b/plat/st/stm32mp1/stm32mp1_security.c
@@ -16,6 +16,46 @@
 #include "platform_def.h"
 
 /*******************************************************************************
+ * Initialize the TrustZone Controller. Configure Region 0 with Secure RW access
+ * and allow Non-Secure masters full access.
+ ******************************************************************************/
+static void init_tzc400(void)
+{
+	unsigned long long region_base, region_top;
+	unsigned long long ddr_base = STM32MP1_DDR_BASE;
+	unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size();
+
+	tzc400_init(STM32MP1_TZC_BASE);
+
+	tzc400_disable_filters();
+
+	/* Region 1 set to cover all DRAM at 0xC000_0000. Apply the
+	 * same configuration to all filters in the TZC.
+	 */
+	region_base = ddr_base;
+	region_top = ddr_base + (ddr_size - 1U);
+	tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1,
+			region_base,
+			region_top,
+			TZC_REGION_S_RDWR,
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID));
+
+	/* Raise an exception if a NS device tries to access secure memory */
+	tzc400_set_action(TZC_ACTION_ERR);
+
+	tzc400_enable_filters();
+}
+
+/*******************************************************************************
  * Initialize the TrustZone Controller.
  * Early initialization create only one region with full access to secure.
  * This setting is used before and during DDR initialization.
@@ -76,3 +116,12 @@
 {
 	early_init_tzc400();
 }
+
+/*******************************************************************************
+ * Initialize the secure environment. At this moment only the TrustZone
+ * Controller is initialized.
+ ******************************************************************************/
+void stm32mp1_security_setup(void)
+{
+	init_tzc400();
+}
diff --git a/plat/st/stm32mp1/stm32mp1_topology.c b/plat/st/stm32mp1/stm32mp1_topology.c
new file mode 100644
index 0000000..405aa33
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_topology.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+#include <platform.h>
+#include <psci.h>
+
+/* 1 cluster, all cores into */
+static const unsigned char stm32mp1_power_domain_tree_desc[] = {
+	PLATFORM_CLUSTER_COUNT,
+	PLATFORM_CORE_COUNT,
+};
+
+/* This function returns the platform topology */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return stm32mp1_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+	u_register_t mpidr_copy = mpidr;
+
+	mpidr_copy &= MPIDR_AFFINITY_MASK;
+
+	if ((mpidr_copy & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0U) {
+		return -1;
+	}
+
+	cluster_id = (mpidr_copy >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr_copy >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+		return -1;
+	}
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in one
+	 * of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT) {
+		return -1;
+	}
+
+	return (int)cpu_id;
+}