stm32mp1: Add BL32 SP_min secure monitor
authorYann Gautier <[email protected]>
Mon, 16 Jul 2018 17:36:06 +0000 (19:36 +0200)
committerYann Gautier <[email protected]>
Tue, 24 Jul 2018 15:18:32 +0000 (17:18 +0200)
Signed-off-by: Yann Gautier <[email protected]>
Signed-off-by: Mathieu Belou <[email protected]>
Signed-off-by: Lionel Debieve <[email protected]>
Signed-off-by: Etienne Carriere <[email protected]>
Signed-off-by: Nicolas Le Bayon <[email protected]>
plat/st/stm32mp1/include/platform_def.h
plat/st/stm32mp1/include/stm32mp1_private.h
plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk [new file with mode: 0644]
plat/st/stm32mp1/sp_min/sp_min_setup.c [new file with mode: 0644]
plat/st/stm32mp1/stm32mp1_common.c
plat/st/stm32mp1/stm32mp1_def.h
plat/st/stm32mp1/stm32mp1_gic.c [new file with mode: 0644]
plat/st/stm32mp1/stm32mp1_pm.c [new file with mode: 0644]
plat/st/stm32mp1/stm32mp1_security.c
plat/st/stm32mp1/stm32mp1_topology.c [new file with mode: 0644]

index 9c148ad473b22372495186f49da14fc4dbfaabf7..47e1ffcf53fad4f560d676eb3c3540cd6308dd96 100644 (file)
  ******************************************************************************/
 
 /* 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"
index 41c46e8e9846882c1a38f95958843f9ea43a8791..a789d53e6a13cf2c435a5ec5764fcd5f7a96fe9d 100644 (file)
@@ -11,8 +11,12 @@ void stm32mp1_io_setup(void);
 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 (file)
index 0000000..9fde153
--- /dev/null
@@ -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 (file)
index 0000000..1329bdb
--- /dev/null
@@ -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)
+{
+}
index e2f90d284e88cb136b0e870b1b5d85bdb6588273..68ca7db32771e25e3b5b5623a40858505de67508 100644 (file)
                                        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 @@ static const mmap_region_t stm32mp1_mmap[] = {
        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)
 {
index 5ff509cccf88f66e9015f5d9e0a20ec2256ac2a4..bb3fecf6d5943f8fbacd48fb07c11b9335369cc5 100644 (file)
@@ -71,7 +71,12 @@ enum ddr_type {
  * 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 (file)
index 0000000..11eb0a3
--- /dev/null
@@ -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 (file)
index 0000000..e24af0e
--- /dev/null
@@ -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;
+}
index 0cdf30581b2b16006e2fa2b43959ad6858e51e06..e783c14e45d29d71b17928ada6607df10bc70c89 100644 (file)
 #include <tzc400.h>
 #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.
@@ -76,3 +116,12 @@ void stm32mp1_arch_security_setup(void)
 {
        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 (file)
index 0000000..405aa33
--- /dev/null
@@ -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;
+}