feat(stm32mp2): add BL31 device tree support

BL31 will need to access a device tree for several configurations (UART,
GIC, OTP mapping...).
Create a BL31 device tree (SOC_FW_CONFIG). It is loaded in DDR, in a
spare area.

Signed-off-by: Yann Gautier <yann.gautier@foss.st.com>
Signed-off-by: Maxime Méré <maxime.mere@foss.st.com>
Change-Id: I320a05859e1aa3dd8db9a274e7201075a8c250c2
diff --git a/fdts/stm32mp25-bl2.dtsi b/fdts/stm32mp25-bl2.dtsi
index e250e3f..e6662d0 100644
--- a/fdts/stm32mp25-bl2.dtsi
+++ b/fdts/stm32mp25-bl2.dtsi
@@ -31,6 +31,7 @@
 			bl32_extra2_uuid = "8ea87bb1-cfa2-3f4d-85fd-e7bba50220d9";
 			bl33_uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4";
 			hw_cfg_uuid = "08b8f1d9-c9cf-9349-a962-6fbc6b7265cc";
+			soc_fw_cfg_uuid = "9979814b-0376-fb46-8c8e-8d267f7859e0";
 			tos_fw_cfg_uuid = "26257c1a-dbc6-7f47-8d96-c4c4b0248021";
 			nt_fw_cfg_uuid = "28da9815-93e8-7e44-ac66-1aaf801550f9";
 		};
diff --git a/fdts/stm32mp25-bl31.dtsi b/fdts/stm32mp25-bl31.dtsi
new file mode 100644
index 0000000..fa63f63
--- /dev/null
+++ b/fdts/stm32mp25-bl31.dtsi
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
+/*
+ * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
+ */
+
+/ {
+	soc@0 {
+		rifsc@42080000 {
+			/delete-node/ mmc@48220000;
+			/delete-node/ mmc@48230000;
+		};
+	};
+};
diff --git a/fdts/stm32mp25-fw-config.dtsi b/fdts/stm32mp25-fw-config.dtsi
index 102980d..2f83f24 100644
--- a/fdts/stm32mp25-fw-config.dtsi
+++ b/fdts/stm32mp25-fw-config.dtsi
@@ -31,6 +31,10 @@
 			id = <BL31_IMAGE_ID>;
 		};
 
+		soc_fw-config {
+			id = <SOC_FW_CONFIG_ID>;
+		};
+
 		tos_fw {
 			id = <BL32_IMAGE_ID>;
 		};
diff --git a/fdts/stm32mp257f-ev1-ca35tdcid-fw-config.dtsi b/fdts/stm32mp257f-ev1-ca35tdcid-fw-config.dtsi
index e41c6b9..5bfcf8d 100644
--- a/fdts/stm32mp257f-ev1-ca35tdcid-fw-config.dtsi
+++ b/fdts/stm32mp257f-ev1-ca35tdcid-fw-config.dtsi
@@ -11,6 +11,10 @@
 
 / {
 	dtb-registry {
+		soc_fw-config {
+			load-address = <0x0 0x81ff0000>;
+			max-size = <0x10000>;
+		};
 		tos_fw {
 			load-address = <0x0 0x82000000>;
 			max-size = <0x2000000>;
diff --git a/plat/st/common/stm32mp_fconf_io.c b/plat/st/common/stm32mp_fconf_io.c
index 1aecece..644275e 100644
--- a/plat/st/common/stm32mp_fconf_io.c
+++ b/plat/st/common/stm32mp_fconf_io.c
@@ -77,7 +77,7 @@
 #define DEFAULT_UUID_NUMBER	U(7)
 
 #ifdef __aarch64__
-#define BL31_UUID_NUMBER	U(1)
+#define BL31_UUID_NUMBER	U(2)
 #else
 #define BL31_UUID_NUMBER	U(0)
 #endif
@@ -115,6 +115,7 @@
 	{FW_CONFIG_ID, "fw_cfg_uuid"},
 #ifdef __aarch64__
 	{BL31_IMAGE_ID, "bl31_uuid"},
+	{SOC_FW_CONFIG_ID, "soc_fw_cfg_uuid"},
 #endif
 	{BL32_IMAGE_ID, "bl32_uuid"},
 	{BL32_EXTRA1_IMAGE_ID, "bl32_extra1_uuid"},
diff --git a/plat/st/stm32mp2/bl2_plat_setup.c b/plat/st/stm32mp2/bl2_plat_setup.c
index 345850b..2fabc41 100644
--- a/plat/st/stm32mp2/bl2_plat_setup.c
+++ b/plat/st/stm32mp2/bl2_plat_setup.c
@@ -280,6 +280,7 @@
 	unsigned int i;
 	const unsigned int image_ids[] = {
 		BL31_IMAGE_ID,
+		SOC_FW_CONFIG_ID,
 		BL32_IMAGE_ID,
 		BL33_IMAGE_ID,
 		HW_CONFIG_ID,
@@ -345,6 +346,7 @@
 				break;
 
 			case HW_CONFIG_ID:
+			case SOC_FW_CONFIG_ID:
 				break;
 
 			default:
diff --git a/plat/st/stm32mp2/bl31_plat_setup.c b/plat/st/stm32mp2/bl31_plat_setup.c
index dbf1371..eb3bcfc 100644
--- a/plat/st/stm32mp2/bl31_plat_setup.c
+++ b/plat/st/stm32mp2/bl31_plat_setup.c
@@ -8,12 +8,16 @@
 #include <stdint.h>
 
 #include <common/bl_common.h>
+#include <drivers/generic_delay_timer.h>
 #include <drivers/st/stm32_console.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 
 #include <platform_def.h>
 
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 				u_register_t arg2, u_register_t arg3)
 {
@@ -31,6 +35,12 @@
 			BL_CODE_END - BL_CODE_BASE,
 			MT_CODE | MT_SECURE);
 
+	/*
+	 * Map soc_fw_config device tree with secure property, i.e. default region.
+	 * DDR region definitions will be finalized at BL32 level.
+	 */
+	mmap_add_region(arg1, arg1, STM32MP_SOC_FW_CONFIG_MAX_SIZE, MT_RO_DATA | MT_SECURE);
+
 #if USE_COHERENT_MEM
 	/* Map coherent memory */
 	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
@@ -40,6 +50,20 @@
 
 	configure_mmu();
 
+	ret = dt_open_and_check(arg1);
+	if (ret < 0) {
+		EARLY_ERROR("%s: failed to open DT (%d)\n", __func__, ret);
+		panic();
+	}
+
+	ret = stm32mp2_clk_init();
+	if (ret < 0) {
+		EARLY_ERROR("%s: failed init clocks (%d)\n", __func__, ret);
+		panic();
+	}
+
+	(void)stm32mp_uart_console_setup();
+
 	/*
 	 * Map upper SYSRAM where bl_params_t are stored in BL2
 	 */
@@ -60,6 +84,31 @@
 	bl_params_node_t *bl_params = params_from_bl2->head;
 
 	while (bl_params != NULL) {
+		/*
+		 * Copy BL33 entry point information.
+		 * They are stored in Secure RAM, in BL2's address space.
+		 */
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			bl33_image_ep_info = *bl_params->ep_info;
+			/*
+			 *  Check if hw_configuration is given to BL32 and
+			 *  share it to BL33
+			 */
+			if (arg2 != 0U) {
+				bl33_image_ep_info.args.arg0 = 0U;
+				bl33_image_ep_info.args.arg1 = 0U;
+				bl33_image_ep_info.args.arg2 = arg2;
+			}
+		}
+
+		if (bl_params->image_id == BL32_IMAGE_ID) {
+			bl32_image_ep_info = *bl_params->ep_info;
+
+			if (arg2 != 0U) {
+				bl32_image_ep_info.args.arg3 = arg2;
+			}
+		}
+
 		bl_params = bl_params->next_params_info;
 	}
 
@@ -81,5 +130,27 @@
 
 entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
 {
-	return NULL;
+	entry_point_info_t *next_image_info = NULL;
+
+	assert(sec_state_is_valid(type));
+
+	switch (type) {
+	case NON_SECURE:
+		next_image_info = &bl33_image_ep_info;
+		break;
+
+	case SECURE:
+		next_image_info = &bl32_image_ep_info;
+		break;
+
+	default:
+		break;
+	}
+
+	/* None of the next images on ST platforms can have 0x0 as the entrypoint */
+	if ((next_image_info == NULL) || (next_image_info->pc == 0UL)) {
+		return NULL;
+	}
+
+	return next_image_info;
 }
diff --git a/plat/st/stm32mp2/plat_bl2_mem_params_desc.c b/plat/st/stm32mp2/plat_bl2_mem_params_desc.c
index ecad0b4..2513180 100644
--- a/plat/st/stm32mp2/plat_bl2_mem_params_desc.c
+++ b/plat/st/stm32mp2/plat_bl2_mem_params_desc.c
@@ -70,6 +70,21 @@
 		.next_handoff_image_id = BL32_IMAGE_ID,
 	},
 
+	/* Fill SoC FW config related information */
+	{
+		.image_id = SOC_FW_CONFIG_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
 	/* Fill BL32 related information */
 	{
 		.image_id = BL32_IMAGE_ID,
diff --git a/plat/st/stm32mp2/platform.mk b/plat/st/stm32mp2/platform.mk
index c12e512..df1cacd 100644
--- a/plat/st/stm32mp2/platform.mk
+++ b/plat/st/stm32mp2/platform.mk
@@ -48,6 +48,8 @@
 # Device tree
 BL2_DTSI			:=	stm32mp25-bl2.dtsi
 FDT_SOURCES			:=	$(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl2.dts,$(DTB_FILE_NAME)))
+BL31_DTSI			:=	stm32mp25-bl31.dtsi
+FDT_SOURCES			+=	$(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl31.dts,$(DTB_FILE_NAME)))
 
 # Macros and rules to build TF binary
 STM32_TF_STM32			:=	$(addprefix ${BUILD_PLAT}/tf-a-, $(patsubst %.dtb,%.stm32,$(DTB_FILE_NAME)))
@@ -56,6 +58,7 @@
 
 STM32MP_FW_CONFIG_NAME		:=	$(patsubst %.dtb,%-fw-config.dtb,$(DTB_FILE_NAME))
 STM32MP_FW_CONFIG		:=	${BUILD_PLAT}/fdts/$(STM32MP_FW_CONFIG_NAME)
+STM32MP_SOC_FW_CONFIG		:=	$(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl31.dtb,$(DTB_FILE_NAME)))
 ifeq (${STM32MP_DDR_FIP_IO_STORAGE},1)
 STM32MP_DDR_FW_PATH		?=	drivers/st/ddr/phy/firmware/bin/stm32mp2
 STM32MP_DDR_FW_NAME		:=	${DDR_TYPE}_pmu_train.bin
@@ -64,6 +67,8 @@
 FDT_SOURCES			+=	$(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32MP_FW_CONFIG_NAME)))
 # Add the FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_FW_CONFIG},--fw-config))
+# Add the SOC_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_IMG,STM32MP_SOC_FW_CONFIG,--soc-fw-config))
 ifeq (${STM32MP_DDR_FIP_IO_STORAGE},1)
 # Add the FW_DDR to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_IMG,STM32MP_DDR_FW,--ddr-fw))
@@ -198,4 +203,11 @@
 		false; \
 	fi
 
+# Create DTB file for BL31
+${BUILD_PLAT}/fdts/%-bl31.dts: fdts/%.dts fdts/${BL31_DTSI} | $$(@D)/
+	@echo '#include "$(patsubst fdts/%,%,$<)"' > $@
+	@echo '#include "${BL31_DTSI}"' >> $@
+
+${BUILD_PLAT}/fdts/%-bl31.dtb: ${BUILD_PLAT}/fdts/%-bl31.dts
+
 include plat/st/common/common_rules.mk
diff --git a/plat/st/stm32mp2/stm32mp2_def.h b/plat/st/stm32mp2/stm32mp2_def.h
index 73116db..b441502 100644
--- a/plat/st/stm32mp2/stm32mp2_def.h
+++ b/plat/st/stm32mp2/stm32mp2_def.h
@@ -138,7 +138,11 @@
  * MAX_MMAP_REGIONS is usually:
  * BL stm32mp2_mmap size + mmap regions in *_plat_arch_setup
  */
+#if defined(IMAGE_BL31)
+#define MAX_MMAP_REGIONS			7
+#else
 #define MAX_MMAP_REGIONS			6
+#endif
 
 /* DTB initialization value */
 #define STM32MP_BL2_DTB_SIZE			U(0x00006000)	/* 24 KB for DTB */
@@ -166,6 +170,7 @@
 #define STM32MP_HW_CONFIG_BASE			(STM32MP_BL33_BASE + \
 						STM32MP_BL33_MAX_SIZE)
 #define STM32MP_HW_CONFIG_MAX_SIZE		U(0x40000)
+#define STM32MP_SOC_FW_CONFIG_MAX_SIZE		U(0x10000) /* 64kB for BL31 DT */
 
 /*******************************************************************************
  * STM32MP2 device/io map related constants (used for MMU)
diff --git a/plat/st/stm32mp2/stm32mp2_private.c b/plat/st/stm32mp2/stm32mp2_private.c
index 7ad974f..5be4c5a 100644
--- a/plat/st/stm32mp2/stm32mp2_private.c
+++ b/plat/st/stm32mp2/stm32mp2_private.c
@@ -117,6 +117,33 @@
 	return CK_BUS_GPIOA + (bank - GPIO_BANK_A);
 }
 
+#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2)
+/*
+ * UART Management
+ */
+static const uintptr_t stm32mp2_uart_addresses[STM32MP_NB_OF_UART] = {
+	USART1_BASE,
+	USART2_BASE,
+	USART3_BASE,
+	UART4_BASE,
+	UART5_BASE,
+	USART6_BASE,
+	UART7_BASE,
+	UART8_BASE,
+	UART9_BASE,
+};
+
+uintptr_t get_uart_address(uint32_t instance_nb)
+{
+	if ((instance_nb == 0U) ||
+	    (instance_nb > STM32MP_NB_OF_UART)) {
+		return 0U;
+	}
+
+	return stm32mp2_uart_addresses[instance_nb - 1U];
+}
+#endif
+
 uint32_t stm32mp_get_chip_version(void)
 {
 	static uint32_t rev;