feat(plat/st): add STM32MP_UART_PROGRAMMER target

Handle boot from UART with STM32CubeProgammer based on mmap io
for STM32MP15.

Depends-On: Iba84e8dfd67b9f30416efb0f6778e48ba1f75dad
Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
Change-Id: Ibd719dd46a11da78633728675ef6639635b6cf67
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index b0314d2..6069e5f 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -99,7 +99,7 @@
 static const io_dev_connector_t *spi_dev_con;
 #endif
 
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
 static const io_dev_connector_t *memmap_dev_con;
 #endif
 
@@ -136,6 +136,9 @@
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
 		INFO("Using SPI NAND\n");
 		break;
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+		INFO("Using UART\n");
+		break;
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		INFO("Using USB\n");
 		break;
@@ -257,7 +260,7 @@
 }
 #endif /* STM32MP_SPI_NAND */
 
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
 static void mmap_io_setup(void)
 {
 	int io_result __unused;
@@ -270,6 +273,21 @@
 	assert(io_result == 0);
 }
 
+#if STM32MP_UART_PROGRAMMER
+static void stm32cubeprogrammer_uart(void)
+{
+	int ret __unused;
+	boot_api_context_t *boot_context =
+		(boot_api_context_t *)stm32mp_get_boot_ctx_address();
+	uintptr_t uart_base;
+
+	uart_base = get_uart_address(boot_context->boot_interface_instance);
+	ret = stm32cubeprog_uart_load(uart_base, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+	assert(ret == 0);
+}
+#endif
+
+#if STM32MP_USB_PROGRAMMER
 static void stm32cubeprogrammer_usb(void)
 {
 	int ret __unused;
@@ -282,6 +300,8 @@
 	assert(ret == 0);
 }
 #endif
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
+
 
 void stm32mp_io_setup(void)
 {
@@ -334,8 +354,13 @@
 		boot_spi_nand(boot_context);
 		break;
 #endif
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+#endif
 #if STM32MP_USB_PROGRAMMER
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+#endif
 		dmbsy();
 		mmap_io_setup();
 		break;
@@ -400,6 +425,16 @@
 		break;
 #endif
 
+#if STM32MP_UART_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+		if (image_id == FW_CONFIG_ID) {
+			stm32cubeprogrammer_uart();
+			/* FIP loaded at DWL address */
+			image_block_spec.offset = DWL_BUFFER_BASE;
+			image_block_spec.length = DWL_BUFFER_SIZE;
+		}
+		break;
+#endif
 #if STM32MP_USB_PROGRAMMER
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		if (image_id == FW_CONFIG_ID) {
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index 8a5fe48..6183964 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -48,6 +48,11 @@
 uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags);
 #endif
 
+#if STM32MP_UART_PROGRAMMER
+/* Get the UART address from its instance number */
+uintptr_t get_uart_address(uint32_t instance_nb);
+#endif
+
 /*
  * Platform util functions for the GPIO driver
  * @bank: Target GPIO bank ID as per DT bindings
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index 7eaf0ed..218f28d 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -493,12 +493,13 @@
 	uint16_t boot_itf = stm32mp_get_boot_itf_selected();
 
 	switch (boot_itf) {
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		/* Invalidate the downloaded buffer used with io_memmap */
 		inv_dcache_range(DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
 		break;
-#endif
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
 	default:
 		/* Do nothing in default case */
 		break;
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index 52b1d1a..198ffa9 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -39,6 +39,9 @@
 /* Boot occurred on QSPI NOR */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI		0x4U
 
+/* Boot occurred on UART */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART		0x5U
+
 /* Boot occurred on USB */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB		0x6U
 
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index badc926..2a4ab78 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -55,6 +55,7 @@
 
 # Serial boot devices
 STM32MP_USB_PROGRAMMER	?=	0
+STM32MP_UART_PROGRAMMER	?=	0
 
 # Device tree
 DTB_FILE_NAME		?=	stm32mp157c-ev1.dtb
@@ -130,6 +131,7 @@
 		STM32MP_SPI_NOR \
 		STM32MP_EMMC_BOOT \
 		PLAT_XLAT_TABLES_DYNAMIC \
+		STM32MP_UART_PROGRAMMER \
 		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
@@ -138,10 +140,12 @@
 	$(sort \
 		STM32_TF_A_COPIES \
 		PLAT_PARTITION_MAX_ENTRIES \
+		STM32_TF_VERSION \
 )))
 
 $(eval $(call add_defines,\
 	$(sort \
+		STM32_TF_VERSION \
 		STM32MP_EMMC \
 		STM32MP_SDMMC \
 		STM32MP_RAW_NAND \
@@ -151,6 +155,7 @@
 		PLAT_XLAT_TABLES_DYNAMIC \
 		STM32_TF_A_COPIES \
 		PLAT_PARTITION_MAX_ENTRIES \
+		STM32MP_UART_PROGRAMMER \
 		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
@@ -260,11 +265,19 @@
 BL2_SOURCES		+=	plat/st/stm32mp1/stm32mp1_boot_device.c
 endif
 
+ifneq ($(filter 1,${STM32MP_UART_PROGRAMMER} ${STM32MP_USB_PROGRAMMER}),)
+BL2_SOURCES		+=	drivers/io/io_memmap.c
+endif
+
+ifeq (${STM32MP_UART_PROGRAMMER},1)
+BL2_SOURCES		+=	drivers/st/uart/stm32_uart.c				\
+				plat/st/common/stm32cubeprogrammer_uart.c
+endif
+
 ifeq (${STM32MP_USB_PROGRAMMER},1)
 #The DFU stack uses only one end point, reduce the USB stack footprint
 $(eval $(call add_define_val,CONFIG_USBD_EP_NB,1U))
-BL2_SOURCES		+=	drivers/io/io_memmap.c					\
-				drivers/st/usb/stm32mp1_usb.c				\
+BL2_SOURCES		+=	drivers/st/usb/stm32mp1_usb.c				\
 				drivers/usb/usb_device.c				\
 				plat/st/common/stm32cubeprogrammer_usb.c		\
 				plat/st/common/usb_dfu.c					\
@@ -295,6 +308,7 @@
 	    [ ${STM32MP_RAW_NAND} != 1 ] && \
 	    [ ${STM32MP_SPI_NAND} != 1 ] && \
 	    [ ${STM32MP_SPI_NOR} != 1 ] && \
+	    [ ${STM32MP_UART_PROGRAMMER} != 1 ] && \
 	    [ ${STM32MP_USB_PROGRAMMER} != 1 ]; then \
 		echo "No boot device driver is enabled"; \
 		false; \
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index e4065c1..0165cfe 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -153,6 +153,32 @@
 	}
 }
 
+#if STM32MP_UART_PROGRAMMER
+/*
+ * UART Management
+ */
+static const uintptr_t stm32mp1_uart_addresses[8] = {
+	USART1_BASE,
+	USART2_BASE,
+	USART3_BASE,
+	UART4_BASE,
+	UART5_BASE,
+	USART6_BASE,
+	UART7_BASE,
+	UART8_BASE,
+};
+
+uintptr_t get_uart_address(uint32_t instance_nb)
+{
+	if ((instance_nb == 0U) ||
+	    (instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses))) {
+		return 0U;
+	}
+
+	return stm32mp1_uart_addresses[instance_nb - 1U];
+}
+#endif
+
 uint32_t stm32mp_get_chip_version(void)
 {
 	uint32_t version = 0U;