feat(plat/st/stm32mp1): add STM32MP_USB_PROGRAMMER target

Add a support of USB as serial boot devices for STM32MP15x platform:
the FIP file is provide by STM32CubeProgrammer with the DFU protocol,
loaded in DDR at DWL_BUFFER_BASE address and then the io memmap is used.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Change-Id: I272c17c458ff1e9d0780f8fa22330c8a35533d19
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index 7e76083..b0314d2 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -13,6 +13,7 @@
 #include <drivers/io/io_block.h>
 #include <drivers/io/io_driver.h>
 #include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
 #include <drivers/io/io_mtd.h>
 #include <drivers/io/io_storage.h>
 #include <drivers/mmc.h>
@@ -24,6 +25,7 @@
 #include <drivers/st/stm32_fmc2_nand.h>
 #include <drivers/st/stm32_qspi.h>
 #include <drivers/st/stm32_sdmmc2.h>
+#include <drivers/usb_device.h>
 #include <lib/fconf/fconf.h>
 #include <lib/mmio.h>
 #include <lib/utils.h>
@@ -31,7 +33,9 @@
 #include <tools_share/firmware_image_package.h>
 
 #include <platform_def.h>
+#include <stm32cubeprogrammer.h>
 #include <stm32mp_fconf_getter.h>
+#include <usb_dfu.h>
 
 /* IO devices */
 uintptr_t fip_dev_handle;
@@ -95,6 +99,10 @@
 static const io_dev_connector_t *spi_dev_con;
 #endif
 
+#if STM32MP_USB_PROGRAMMER
+static const io_dev_connector_t *memmap_dev_con;
+#endif
+
 io_block_spec_t image_block_spec = {
 	.offset = 0U,
 	.length = 0U,
@@ -128,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_USB:
+		INFO("Using USB\n");
+		break;
 	default:
 		ERROR("Boot interface %u not found\n",
 		      boot_context->boot_interface_selected);
@@ -246,6 +257,32 @@
 }
 #endif /* STM32MP_SPI_NAND */
 
+#if STM32MP_USB_PROGRAMMER
+static void mmap_io_setup(void)
+{
+	int io_result __unused;
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&storage_dev_handle);
+	assert(io_result == 0);
+}
+
+static void stm32cubeprogrammer_usb(void)
+{
+	int ret __unused;
+	struct usb_handle *pdev;
+
+	/* Init USB on platform */
+	pdev = usb_dfu_plat_init();
+
+	ret = stm32cubeprog_usb_load(pdev, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+	assert(ret == 0);
+}
+#endif
+
 void stm32mp_io_setup(void)
 {
 	int io_result __unused;
@@ -297,6 +334,12 @@
 		boot_spi_nand(boot_context);
 		break;
 #endif
+#if STM32MP_USB_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+		dmbsy();
+		mmap_io_setup();
+		break;
+#endif
 
 	default:
 		ERROR("Boot interface %d not supported\n",
@@ -357,6 +400,17 @@
 		break;
 #endif
 
+#if STM32MP_USB_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+		if (image_id == FW_CONFIG_ID) {
+			stm32cubeprogrammer_usb();
+			/* FIP loaded at DWL address */
+			image_block_spec.offset = DWL_BUFFER_BASE;
+			image_block_spec.length = DWL_BUFFER_SIZE;
+		}
+		break;
+#endif
+
 	default:
 		ERROR("FIP Not found\n");
 		panic();
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index e87c529..7eaf0ed 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -490,5 +490,19 @@
 
 void bl2_el3_plat_prepare_exit(void)
 {
+	uint16_t boot_itf = stm32mp_get_boot_itf_selected();
+
+	switch (boot_itf) {
+#if STM32MP_USB_PROGRAMMER
+	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
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
 	stm32mp1_security_setup();
 }
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index c16639a..52b1d1a 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -39,6 +39,9 @@
 /* Boot occurred on QSPI NOR */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI		0x4U
 
+/* Boot occurred on USB */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB		0x6U
+
 /* Boot occurred on QSPI NAND */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI		0x7U
 
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
index 8a065bf..1e9443e 100644
--- a/plat/st/stm32mp1/include/platform_def.h
+++ b/plat/st/stm32mp1/include/platform_def.h
@@ -92,6 +92,10 @@
  */
 #define PLAT_STM32MP_NS_IMAGE_OFFSET	BL33_BASE
 
+/* Needed by STM32CubeProgrammer support */
+#define DWL_BUFFER_BASE			(STM32MP_DDR_BASE + U(0x08000000))
+#define DWL_BUFFER_SIZE			U(0x08000000)
+
 /*
  * SSBL offset in case it's stored in eMMC boot partition.
  * We can fix it to 256K because TF-A size can't be bigger than SRAM
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 14f90d4..c8c2e5f 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -53,6 +53,9 @@
 STM32MP_SPI_NOR		?=	0
 STM32MP_EMMC_BOOT	?=	0
 
+# Serial boot devices
+STM32MP_USB_PROGRAMMER	?=	0
+
 # Device tree
 DTB_FILE_NAME		?=	stm32mp157c-ev1.dtb
 ifeq ($(STM32MP_USE_STM32IMAGE),1)
@@ -127,6 +130,7 @@
 		STM32MP_SPI_NOR \
 		STM32MP_EMMC_BOOT \
 		PLAT_XLAT_TABLES_DYNAMIC \
+		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
 
@@ -147,6 +151,7 @@
 		PLAT_XLAT_TABLES_DYNAMIC \
 		STM32_TF_A_COPIES \
 		PLAT_PARTITION_MAX_ENTRIES \
+		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
 
@@ -251,6 +256,17 @@
 BL2_SOURCES		+=	plat/st/stm32mp1/stm32mp1_boot_device.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				\
+				drivers/usb/usb_device.c				\
+				plat/st/common/stm32cubeprogrammer_usb.c		\
+				plat/st/common/usb_dfu.c					\
+				plat/st/stm32mp1/stm32mp1_usb_dfu.c
+endif
+
 BL2_SOURCES		+=	drivers/st/ddr/stm32mp1_ddr.c				\
 				drivers/st/ddr/stm32mp1_ram.c
 
@@ -274,7 +290,8 @@
 	    [ ${STM32MP_SDMMC} != 1 ] && \
 	    [ ${STM32MP_RAW_NAND} != 1 ] && \
 	    [ ${STM32MP_SPI_NAND} != 1 ] && \
-	    [ ${STM32MP_SPI_NOR} != 1 ]; then \
+	    [ ${STM32MP_SPI_NOR} != 1 ] && \
+	    [ ${STM32MP_USB_PROGRAMMER} != 1 ]; then \
 		echo "No boot device driver is enabled"; \
 		false; \
 	fi