Merge "fix(plat/socionext/synquacer): initialise CNTFRQ in Non Secure CNTBaseN" into integration
diff --git a/.cz.json b/.cz.json
index 5ed24f4..5ac961e 100644
--- a/.cz.json
+++ b/.cz.json
@@ -93,12 +93,16 @@
                     "scopes": ["sve"]
                 },
                 {
+                    "title": "System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)",
+                    "scopes": ["sys-reg-trace", "sys_reg_trace"]
+                },
+                {
                     "title": "Trace Buffer Extension (FEAT_TRBE)",
                     "scopes": ["trbe"]
                 },
                 {
-                    "title": "Self-hosted Trace Extensions (FEAT_TRF)",
-                    "scopes": ["trf", "sys_reg_trace"]
+                    "title": "Self-hosted Trace Extension (FEAT_TRF)",
+                    "scopes": ["trf"]
                 }
             ]
         },
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index b65571d..a50b033 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -61,7 +61,7 @@
 |                                | Date        | after   |                                                         |
 |                                |             | Release |                                                         |
 +================================+=============+=========+=========================================================+
-|                                |             |         |                                                         |
+| STM32MP_USE_STM32IMAGE macro   |   Dec '21   |   2.7   | FIP is the recommended boot method for STM32MP          |
 +--------------------------------+-------------+---------+---------------------------------------------------------+
 
 --------------
diff --git a/docs/change-log.md b/docs/change-log.md
index f0cb352..7f36d01 100644
--- a/docs/change-log.md
+++ b/docs/change-log.md
@@ -63,15 +63,18 @@
 
     - enable SVE for the secure world ([0c5e7d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c5e7d1ce376cabcebebc43dbf238fe4482ab2dc))
 
+  - **System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)**
+
+    - enable trace system registers access from lower NS ELs ([d4582d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4582d30885673987240cf01fd4f5d2e6780e84c))
+    - initialize trap settings of trace system registers access ([2031d61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2031d6166a58623ae59034bc2353fcd2fabe9c30))
+
   - **Trace Buffer Extension (FEAT_TRBE)**
 
     - enable access to trace buffer control registers from lower NS EL ([813524e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/813524ea9d2e4138246b8f77a772299e52fb33bc))
     - initialize trap settings of trace buffer control registers access ([40ff907](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40ff90747098ed9d2a09894d1a886c10ca76cee6))
 
-  - **Self-hosted Trace Extensions (FEAT_TRF)**
+  - **Self-hosted Trace Extension (FEAT_TRF)**
 
-    - enable trace system registers access from lower NS ELs ([d4582d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4582d30885673987240cf01fd4f5d2e6780e84c))
-    - initialize trap settings of trace system registers access ([2031d61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2031d6166a58623ae59034bc2353fcd2fabe9c30))
     - enable trace filter control register access from lower NS EL ([8fcd3d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8fcd3d9600bb2cb6809c6fc68f945ce3ad89633d))
     - initialize trap settings of trace filter control registers access ([5de20ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5de20ece38f782c8459f546a08c6a97b9e0f5bc5))
 
@@ -324,6 +327,7 @@
 
     - add support for Hayes CPU ([7bd8dfb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7bd8dfb85a8bf5c22d6a39f4538b89cc748090d1))
     - add support for Hunter CPU ([fb9e5f7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb9e5f7bb76e9764b3ecd7973668c851015fa1b4))
+    - add support for Demeter CPU ([f4616ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f4616efafbc1004f1330f515b898e7617e338875))
     - workaround for Cortex A78 AE erratum 1941500 ([47d6f5f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47d6f5ff16d1f2ad009d630a381054b10fa0a06f))
     - workaround for Cortex A78 AE erratum 1951502 ([8913047](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8913047a52e646877812617a2d98cff99494487b))
 
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 93ee1a1..3af0500 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -171,7 +171,7 @@
 static inline u_register_t gicd_irouter_val_from_mpidr(u_register_t mpidr,
 						       unsigned int irm)
 {
-	return (mpidr & ~(U(0xff) << 24)) |
+	return (mpidr & MPIDR_AFFINITY_MASK) |
 		((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT);
 }
 
diff --git a/drivers/measured_boot/event_log/event_log.c b/drivers/measured_boot/event_log/event_log.c
index 1755dd9..52ed278 100644
--- a/drivers/measured_boot/event_log/event_log.c
+++ b/drivers/measured_boot/event_log/event_log.c
@@ -250,11 +250,11 @@
 	const event_log_metadata_t *metadata_ptr = plat_metadata_ptr;
 
 	/* Get the metadata associated with this image. */
-	while ((metadata_ptr->id != INVALID_ID) &&
+	while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
 		(metadata_ptr->id != data_id)) {
 		metadata_ptr++;
 	}
-	assert(metadata_ptr->id != INVALID_ID);
+	assert(metadata_ptr->id != EVLOG_INVALID_ID);
 
 	/* Calculate hash */
 	rc = crypto_mod_calc_hash((unsigned int)MBEDTLS_MD_ID,
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index d57f120..0db0dee 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -14,6 +14,7 @@
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32mp_clkfunc.h>
 
+#define DT_UART_COMPAT		"st,stm32h7-uart"
 /*
  * Get the frequency of an oscillator from its name in device tree.
  * @param name: oscillator name
@@ -297,3 +298,32 @@
 	cuint++;
 	return (int)fdt32_to_cpu(*cuint);
 }
+
+/*
+ * Get the frequency of the specified UART instance.
+ * @param instance: UART interface registers base address.
+ * @return: clock frequency on success, 0 value on failure.
+ */
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
+{
+	void *fdt;
+	int node;
+	int clk_id;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return 0UL;
+	}
+
+	/* Check for UART nodes */
+	node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
+	if (node < 0) {
+		return 0UL;
+	}
+
+	clk_id = fdt_get_clock_id(node);
+	if (clk_id < 0) {
+		return 0UL;
+	}
+
+	return stm32mp_clk_get_rate((unsigned long)clk_id);
+}
diff --git a/drivers/st/uart/stm32_uart.c b/drivers/st/uart/stm32_uart.c
new file mode 100644
index 0000000..e2e5405
--- /dev/null
+++ b/drivers/st/uart/stm32_uart.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+/* UART time-out value */
+#define STM32_UART_TIMEOUT_US	20000U
+
+/* Mask to clear ALL the configuration registers */
+
+#define STM32_UART_CR1_FIELDS \
+		(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
+		 USART_CR1_RE | USART_CR1_OVER8 | USART_CR1_FIFOEN)
+
+#define STM32_UART_CR2_FIELDS \
+		(USART_CR2_SLVEN | USART_CR2_DIS_NSS | USART_CR2_ADDM7 | \
+		 USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \
+		 USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | \
+		 USART_CR2_STOP | USART_CR2_LINEN | USART_CR2_SWAP | \
+		 USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_DATAINV | \
+		 USART_CR2_MSBFIRST | USART_CR2_ABREN | USART_CR2_ABRMODE | \
+		 USART_CR2_RTOEN | USART_CR2_ADD)
+
+#define STM32_UART_CR3_FIELDS \
+		(USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | \
+		 USART_CR3_HDSEL | USART_CR3_NACK | USART_CR3_SCEN | \
+		 USART_CR3_DMAR | USART_CR3_DMAT | USART_CR3_RTSE | \
+		 USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \
+		 USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | \
+		 USART_CR3_DEP | USART_CR3_SCARCNT | USART_CR3_WUS | \
+		 USART_CR3_WUFIE | USART_CR3_TXFTIE | USART_CR3_TCBGTIE | \
+		 USART_CR3_RXFTCFG | USART_CR3_RXFTIE | USART_CR3_TXFTCFG)
+
+#define STM32_UART_ISR_ERRORS	 \
+		(USART_ISR_ORE | USART_ISR_NE |  USART_ISR_FE | USART_ISR_PE)
+
+static const uint16_t presc_table[STM32_UART_PRESCALER_NB] = {
+	1U, 2U, 4U, 6U, 8U, 10U, 12U, 16U, 32U, 64U, 128U, 256U
+};
+
+/* @brief  BRR division operation to set BRR register in 8-bit oversampling
+ * mode.
+ * @param  clockfreq: UART clock.
+ * @param  baud_rate: Baud rate set by the user.
+ * @param  prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling8(unsigned long clockfreq,
+				   uint32_t baud_rate,
+				   uint32_t prescaler)
+{
+	uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+	return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate;
+
+}
+
+/* @brief  BRR division operation to set BRR register in 16-bit oversampling
+ * mode.
+ * @param  clockfreq: UART clock.
+ * @param  baud_rate: Baud rate set by the user.
+ * @param  prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling16(unsigned long clockfreq,
+				    uint32_t baud_rate,
+				    uint32_t prescaler)
+{
+	uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+	return (scaled_freq + (baud_rate / 2)) / baud_rate;
+
+}
+
+/*
+ * @brief  Return the UART clock frequency.
+ * @param  huart: UART handle.
+ * @retval Frequency value in Hz.
+ */
+static unsigned long uart_get_clock_freq(struct stm32_uart_handle_s *huart)
+{
+	return fdt_get_uart_clock_freq((uintptr_t)huart->base);
+}
+
+/*
+ * @brief  Configure the UART peripheral.
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+static int uart_set_config(struct stm32_uart_handle_s *huart,
+			   const struct stm32_uart_init_s *init)
+{
+	uint32_t tmpreg;
+	unsigned long clockfreq;
+	uint32_t brrtemp;
+
+	/*
+	 * ---------------------- USART CR1 Configuration --------------------
+	 * Clear M, PCE, PS, TE, RE and OVER8 bits and configure
+	 * the UART word length, parity, mode and oversampling:
+	 * - set the M bits according to init->word_length value,
+	 * - set PCE and PS bits according to init->parity value,
+	 * - set TE and RE bits according to init->mode value,
+	 * - set OVER8 bit according to init->over_sampling value.
+	 */
+	tmpreg = init->word_length |
+		 init->parity |
+		 init->mode |
+		 init->over_sampling |
+		 init->fifo_mode;
+	mmio_clrsetbits_32(huart->base + USART_CR1, STM32_UART_CR1_FIELDS, tmpreg);
+
+	/*
+	 * --------------------- USART CR2 Configuration ---------------------
+	 * Configure the UART Stop Bits: Set STOP[13:12] bits according
+	 * to init->stop_bits value.
+	 */
+	mmio_clrsetbits_32(huart->base + USART_CR2, STM32_UART_CR2_FIELDS,
+			   init->stop_bits);
+
+	/*
+	 * --------------------- USART CR3 Configuration ---------------------
+	 * Configure:
+	 * - UART HardWare Flow Control: set CTSE and RTSE bits according
+	 *   to init->hw_flow_control value,
+	 * - one-bit sampling method versus three samples' majority rule
+	 *   according to init->one_bit_sampling (not applicable to
+	 *   LPUART),
+	 * - set TXFTCFG bit according to init->tx_fifo_threshold value,
+	 * - set RXFTCFG bit according to init->rx_fifo_threshold value.
+	 */
+	tmpreg = init->hw_flow_control | init->one_bit_sampling;
+
+	if (init->fifo_mode == USART_CR1_FIFOEN) {
+		tmpreg |= init->tx_fifo_threshold |
+			  init->rx_fifo_threshold;
+	}
+
+	mmio_clrsetbits_32(huart->base + USART_CR3, STM32_UART_CR3_FIELDS, tmpreg);
+
+	/*
+	 * --------------------- USART PRESC Configuration -------------------
+	 * Configure UART Clock Prescaler : set PRESCALER according to
+	 * init->prescaler value.
+	 */
+	assert(init->prescaler < STM32_UART_PRESCALER_NB);
+	mmio_clrsetbits_32(huart->base + USART_PRESC, USART_PRESC_PRESCALER,
+			   init->prescaler);
+
+	/*---------------------- USART BRR configuration --------------------*/
+	clockfreq = uart_get_clock_freq(huart);
+	if (clockfreq == 0UL) {
+		return -ENODEV;
+	}
+
+	if (init->over_sampling == STM32_UART_OVERSAMPLING_8) {
+		uint32_t usartdiv = uart_div_sampling8(clockfreq,
+						       init->baud_rate,
+						       init->prescaler);
+
+		brrtemp = (usartdiv & USART_BRR_DIV_MANTISSA) |
+			  ((usartdiv & USART_BRR_DIV_FRACTION) >> 1);
+	} else {
+		brrtemp = uart_div_sampling16(clockfreq,
+					      init->baud_rate,
+					      init->prescaler) &
+			  (USART_BRR_DIV_FRACTION | USART_BRR_DIV_MANTISSA);
+	}
+	mmio_write_32(huart->base + USART_BRR, brrtemp);
+
+	return 0;
+}
+
+/*
+ * @brief  Handle UART communication timeout.
+ * @param  huart: UART handle.
+ * @param  flag: Specifies the UART flag to check.
+ * @retval UART status.
+ */
+static int stm32_uart_wait_flag(struct stm32_uart_handle_s *huart, uint32_t flag)
+{
+	uint64_t timeout_ref = timeout_init_us(STM32_UART_TIMEOUT_US);
+
+	while ((mmio_read_32(huart->base + USART_ISR) & flag) == 0U) {
+		if (timeout_elapsed(timeout_ref)) {
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Check the UART idle State.
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+static int stm32_uart_check_idle(struct stm32_uart_handle_s *huart)
+{
+	int ret;
+
+	/* Check if the transmitter is enabled */
+	if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_TE) == USART_CR1_TE) {
+		ret = stm32_uart_wait_flag(huart, USART_ISR_TEACK);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	/* Check if the receiver is enabled */
+	if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_RE) == USART_CR1_RE) {
+		ret = stm32_uart_wait_flag(huart, USART_ISR_REACK);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Compute RDR register mask depending on word length.
+ * @param  huart: UART handle.
+ * @retval Mask value.
+ */
+static unsigned int stm32_uart_rdr_mask(const struct stm32_uart_init_s *init)
+{
+	unsigned int mask = 0U;
+
+	switch (init->word_length) {
+	case STM32_UART_WORDLENGTH_9B:
+		mask = GENMASK(8, 0);
+		break;
+	case STM32_UART_WORDLENGTH_8B:
+		mask = GENMASK(7, 0);
+		break;
+	case STM32_UART_WORDLENGTH_7B:
+		mask = GENMASK(6, 0);
+		break;
+	default:
+		break; /* not reached */
+	}
+
+	if (init->parity != STM32_UART_PARITY_NONE) {
+		mask >>= 1;
+	}
+
+	return mask;
+}
+
+/*
+ * @brief  Check interrupt and status errors.
+ * @retval True if error detected, false otherwise.
+ */
+static bool stm32_uart_error_detected(struct stm32_uart_handle_s *huart)
+{
+	return (mmio_read_32(huart->base + USART_ISR) & STM32_UART_ISR_ERRORS) != 0U;
+}
+
+/*
+ * @brief  Clear status errors.
+ */
+static void stm32_uart_error_clear(struct stm32_uart_handle_s *huart)
+{
+	mmio_write_32(huart->base + USART_ICR, STM32_UART_ISR_ERRORS);
+}
+
+/*
+ * @brief  Stop the UART.
+ * @param  base: UART base address.
+ */
+void stm32_uart_stop(uintptr_t base)
+{
+	mmio_clrbits_32(base + USART_CR1, USART_CR1_UE);
+}
+
+/*
+ * @brief  Initialize UART.
+ * @param  huart: UART handle.
+ * @param  base_addr: base address of UART.
+ * @param  init: UART initialization parameter.
+ * @retval UART status.
+ */
+
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+		    uintptr_t base_addr,
+		    const struct stm32_uart_init_s *init)
+{
+	int ret;
+
+	if (huart == NULL || init == NULL || base_addr == 0U) {
+		return -EINVAL;
+	}
+
+	huart->base = base_addr;
+
+	/* Disable the peripheral */
+	stm32_uart_stop(huart->base);
+
+	/* Computation of UART mask to apply to RDR register */
+	huart->rdr_mask = stm32_uart_rdr_mask(init);
+
+	/* Init the peripheral */
+	ret = uart_set_config(huart, init);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Enable the peripheral */
+	mmio_setbits_32(huart->base + USART_CR1, USART_CR1_UE);
+
+	/* TEACK and/or REACK to check */
+	return stm32_uart_check_idle(huart);
+}
+
+/*
+ * @brief  Transmit one data in no blocking mode.
+ * @param  huart: UART handle.
+ * @param  c: data to sent.
+ * @retval UART status.
+ */
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c)
+{
+	int ret;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	mmio_write_32(huart->base + USART_TDR, c);
+	if (stm32_uart_error_detected(huart)) {
+		stm32_uart_error_clear(huart);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Flush TX Transmit fifo
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+int stm32_uart_flush(struct stm32_uart_handle_s *huart)
+{
+	int ret;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return stm32_uart_wait_flag(huart, USART_ISR_TC);
+}
+
+/*
+ * @brief  Receive a data in no blocking mode.
+ * @retval value if >0 or UART status.
+ */
+int stm32_uart_getc(struct stm32_uart_handle_s *huart)
+{
+	uint32_t data;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	/* Check if data is available */
+	if ((mmio_read_32(huart->base + USART_ISR) & USART_ISR_RXNE) == 0U) {
+		return -EAGAIN;
+	}
+
+	data = mmio_read_32(huart->base + USART_RDR) & huart->rdr_mask;
+
+	if (stm32_uart_error_detected(huart)) {
+		stm32_uart_error_clear(huart);
+		return -EFAULT;
+	}
+
+	return (int)data;
+}
diff --git a/include/drivers/measured_boot/event_log/event_log.h b/include/drivers/measured_boot/event_log/event_log.h
index c6eb29c..78712af 100644
--- a/include/drivers/measured_boot/event_log/event_log.h
+++ b/include/drivers/measured_boot/event_log/event_log.h
@@ -36,9 +36,9 @@
 #endif
 
 /* Number of hashing algorithms supported */
-#define HASH_ALG_COUNT	1U
+#define HASH_ALG_COUNT		1U
 
-#define	INVALID_ID	MAX_NUMBER_IDS
+#define EVLOG_INVALID_ID	MAX_NUMBER_IDS
 
 #define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
 
diff --git a/include/drivers/st/stm32_uart.h b/include/drivers/st/stm32_uart.h
new file mode 100644
index 0000000..212968f
--- /dev/null
+++ b/include/drivers/st/stm32_uart.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_UART_H
+#define STM32_UART_H
+
+/* UART word length */
+#define STM32_UART_WORDLENGTH_7B		USART_CR1_M1
+#define STM32_UART_WORDLENGTH_8B		0x00000000U
+#define STM32_UART_WORDLENGTH_9B		USART_CR1_M0
+
+/* UART number of stop bits */
+#define STM32_UART_STOPBITS_0_5			USART_CR2_STOP_0
+#define STM32_UART_STOPBITS_1			0x00000000U
+#define STM32_UART_STOPBITS_1_5			(USART_CR2_STOP_0 | USART_CR2_STOP_1)
+#define STM32_UART_STOPBITS_2			USART_CR2_STOP_1
+
+/* UART parity */
+#define STM32_UART_PARITY_NONE			0x00000000U
+#define STM32_UART_PARITY_EVEN			USART_CR1_PCE
+#define STM32_UART_PARITY_ODD			(USART_CR1_PCE | USART_CR1_PS)
+
+/* UART transfer mode */
+#define STM32_UART_MODE_RX			USART_CR1_RE
+#define STM32_UART_MODE_TX			USART_CR1_TE
+#define STM32_UART_MODE_TX_RX			(USART_CR1_TE | USART_CR1_RE)
+
+/* UART hardware flow control */
+#define STM32_UART_HWCONTROL_NONE		0x00000000U
+#define STM32_UART_HWCONTROL_RTS		USART_CR3_RTSE
+#define STM32_UART_HWCONTROL_CTS		USART_CR3_CTSE
+#define STM32_UART_HWCONTROL_RTS_CTS		(USART_CR3_RTSE | USART_CR3_CTSE)
+
+/* UART over sampling */
+#define STM32_UART_OVERSAMPLING_16		0x00000000U
+#define STM32_UART_OVERSAMPLING_8		USART_CR1_OVER8
+
+/* UART prescaler */
+#define STM32_UART_PRESCALER_DIV1		0x00000000U
+#define STM32_UART_PRESCALER_DIV2		0x00000001U
+#define STM32_UART_PRESCALER_DIV4		0x00000002U
+#define STM32_UART_PRESCALER_DIV6		0x00000003U
+#define STM32_UART_PRESCALER_DIV8		0x00000004U
+#define STM32_UART_PRESCALER_DIV10		0x00000005U
+#define STM32_UART_PRESCALER_DIV12		0x00000006U
+#define STM32_UART_PRESCALER_DIV16		0x00000007U
+#define STM32_UART_PRESCALER_DIV32		0x00000008U
+#define STM32_UART_PRESCALER_DIV64		0x00000009U
+#define STM32_UART_PRESCALER_DIV128		0x0000000AU
+#define STM32_UART_PRESCALER_DIV256		0x0000000BU
+#define STM32_UART_PRESCALER_NB			0x0000000CU
+
+/* UART fifo mode */
+#define STM32_UART_FIFOMODE_EN			USART_CR1_FIFOEN
+#define STM32_UART_FIFOMODE_DIS			0x00000000U
+
+/* UART TXFIFO threshold level */
+#define STM32_UART_TXFIFO_THRESHOLD_1EIGHTHFULL		0x00000000U
+#define STM32_UART_TXFIFO_THRESHOLD_1QUARTERFUL		USART_CR3_TXFTCFG_0
+#define STM32_UART_TXFIFO_THRESHOLD_HALFFULL		USART_CR3_TXFTCFG_1
+#define STM32_UART_TXFIFO_THRESHOLD_3QUARTERSFULL	(USART_CR3_TXFTCFG_0 | USART_CR3_TXFTCFG_1)
+#define STM32_UART_TXFIFO_THRESHOLD_7EIGHTHFULL		USART_CR3_TXFTCFG_2
+#define STM32_UART_TXFIFO_THRESHOLD_EMPTY		(USART_CR3_TXFTCFG_2 | USART_CR3_TXFTCFG_0)
+
+/* UART RXFIFO threshold level */
+#define STM32_UART_RXFIFO_THRESHOLD_1EIGHTHFULL		0x00000000U
+#define STM32_UART_RXFIFO_THRESHOLD_1QUARTERFULL	USART_CR3_RXFTCFG_0
+#define STM32_UART_RXFIFO_THRESHOLD_HALFFULL		USART_CR3_RXFTCFG_1
+#define STM32_UART_RXFIFO_THRESHOLD_3QUARTERSFULL	(USART_CR3_RXFTCFG_0 | USART_CR3_RXFTCFG_1)
+#define STM32_UART_RXFIFO_THRESHOLD_7EIGHTHFULL		USART_CR3_RXFTCFG_2
+#define STM32_UART_RXFIFO_THRESHOLD_FULL		(USART_CR3_RXFTCFG_2 | USART_CR3_RXFTCFG_0)
+
+struct stm32_uart_init_s {
+	uint32_t baud_rate;		/*
+					 * Configures the UART communication
+					 * baud rate.
+					 */
+
+	uint32_t word_length;		/*
+					 * Specifies the number of data bits
+					 * transmitted or received in a frame.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_WORDLENGTH_*.
+					 */
+
+	uint32_t stop_bits;		/*
+					 * Specifies the number of stop bits
+					 * transmitted. This parameter can be
+					 * a value of @ref STM32_UART_STOPBITS_*.
+					 */
+
+	uint32_t parity;		/*
+					 * Specifies the parity mode.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_PARITY_*.
+					 */
+
+	uint32_t mode;			/*
+					 * Specifies whether the receive or
+					 * transmit mode is enabled or
+					 * disabled. This parameter can be a
+					 * value of @ref @ref STM32_UART_MODE_*.
+					 */
+
+	uint32_t hw_flow_control;	/*
+					 * Specifies whether the hardware flow
+					 * control mode is enabled or
+					 * disabled. This parameter can be a
+					 * value of @ref STM32_UARTHWCONTROL_*.
+					 */
+
+	uint32_t over_sampling;		/*
+					 * Specifies whether the over sampling
+					 * 8 is enabled or disabled.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_OVERSAMPLING_*.
+					 */
+
+	uint32_t one_bit_sampling;	/*
+					 * Specifies whether a single sample
+					 * or three samples' majority vote is
+					 * selected. This parameter can be 0
+					 * or USART_CR3_ONEBIT.
+					 */
+
+	uint32_t prescaler;		/*
+					 * Specifies the prescaler value used
+					 * to divide the UART clock source.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_PRESCALER_*.
+					 */
+
+	uint32_t fifo_mode;		/*
+					 * Specifies if the FIFO mode will be
+					 * used. This parameter can be a value
+					 * of @ref STM32_UART_FIFOMODE_*.
+					 */
+
+	uint32_t tx_fifo_threshold;	/*
+					 * Specifies the TXFIFO threshold
+					 * level. This parameter can be a
+					 * value of @ref
+					 * STM32_UART_TXFIFO_THRESHOLD_*.
+					 */
+
+	uint32_t rx_fifo_threshold;	/*
+					 * Specifies the RXFIFO threshold
+					 * level. This parameter can be a
+					 * value of @ref
+					 * STM32_UART_RXFIFO_THRESHOLD_*.
+					 */
+};
+
+struct stm32_uart_handle_s {
+	uint32_t base;
+	uint32_t rdr_mask;
+};
+
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+		    uintptr_t base_addr,
+		    const struct stm32_uart_init_s *init);
+void stm32_uart_stop(uintptr_t base_addr);
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c);
+int stm32_uart_flush(struct stm32_uart_handle_s *huart);
+int stm32_uart_getc(struct stm32_uart_handle_s *huart);
+
+#endif /* STM32_UART_H */
diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h
index c3329cc..a282035 100644
--- a/include/drivers/st/stm32mp_clkfunc.h
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,5 +26,6 @@
 bool fdt_get_rcc_secure_status(void);
 
 int fdt_get_clock_id(int node);
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance);
 
 #endif /* STM32MP_CLKFUNC_H */
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
index df17386..38a375e 100644
--- a/lib/xlat_tables_v2/xlat_tables_utils.c
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -199,7 +200,7 @@
 					(uint64_t *)addr_inner,
 					XLAT_TABLE_ENTRIES, level + 1U);
 			} else {
-				printf("%sVA:0x%lx PA:0x%llx size:0x%zx ",
+				printf("%sVA:0x%lx PA:0x%" PRIx64 " size:0x%zx ",
 				       level_spacers[level], table_idx_va,
 				       (uint64_t)(desc & TABLE_ADDR_MASK),
 				       level_size);
diff --git a/plat/arm/board/fvp/fvp_bl1_measured_boot.c b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
index 47af1f5..5468555 100644
--- a/plat/arm/board/fvp/fvp_bl1_measured_boot.c
+++ b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
@@ -17,7 +17,8 @@
 	{ FW_CONFIG_ID, EVLOG_FW_CONFIG_STRING, PCR_0 },
 	{ TB_FW_CONFIG_ID, EVLOG_TB_FW_CONFIG_STRING, PCR_0 },
 	{ BL2_IMAGE_ID, EVLOG_BL2_STRING, PCR_0 },
-	{ INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+
+	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
 };
 
 void bl1_plat_mboot_init(void)
diff --git a/plat/arm/board/fvp/fvp_bl2_measured_boot.c b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
index 5ebfede..decf13d 100644
--- a/plat/arm/board/fvp/fvp_bl2_measured_boot.c
+++ b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
@@ -24,7 +24,8 @@
 	{ SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
 	{ SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
 	{ TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
-	{ INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+
+	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
 };
 
 void bl2_plat_mboot_init(void)
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scmi.c b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
index e2013cc..0e99256 100644
--- a/plat/socionext/synquacer/drivers/scp/sq_scmi.c
+++ b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
@@ -189,6 +189,11 @@
 /*
  * Helper function to reset the system via SCMI.
  */
+void __dead2 sq_scmi_sys_shutdown(void)
+{
+	sq_scmi_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
 void __dead2 sq_scmi_sys_reboot(void)
 {
 	sq_scmi_system_off(SCMI_SYS_PWR_COLD_RESET);
diff --git a/plat/socionext/synquacer/include/sq_common.h b/plat/socionext/synquacer/include/sq_common.h
index a985822..b09d22a 100644
--- a/plat/socionext/synquacer/include/sq_common.h
+++ b/plat/socionext/synquacer/include/sq_common.h
@@ -45,6 +45,7 @@
 /* SCMI API for power management by SCP */
 void sq_scmi_off(const struct psci_power_state *target_state);
 void sq_scmi_on(u_register_t mpidr);
+void __dead2 sq_scmi_sys_shutdown(void);
 void __dead2 sq_scmi_sys_reboot(void);
 void __dead2 sq_scmi_system_off(int state);
 /* SCMI API for vendor specific protocol */
diff --git a/plat/socionext/synquacer/sq_psci.c b/plat/socionext/synquacer/sq_psci.c
index 4168df9..3062f63 100644
--- a/plat/socionext/synquacer/sq_psci.c
+++ b/plat/socionext/synquacer/sq_psci.c
@@ -113,6 +113,9 @@
 
 void __dead2 sq_system_off(void)
 {
+#if SQ_USE_SCMI_DRIVER
+	sq_scmi_sys_shutdown();
+#else
 	volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
 
 	/* set PD[9] high to power off the system */
@@ -139,6 +142,7 @@
 	wfi();
 	ERROR("SQ System Off: operation not handled.\n");
 	panic();
+#endif
 }
 
 void __dead2 sq_system_reset(void)
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/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h
index 503d919..0f5a64d 100644
--- a/plat/st/common/include/stm32cubeprogrammer.h
+++ b/plat/st/common/include/stm32cubeprogrammer.h
@@ -24,4 +24,6 @@
 			   uintptr_t ssbl_base,
 			   size_t ssbl_len);
 
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len);
+
 #endif /* STM32CUBEPROGRAMMER_H */
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/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c
new file mode 100644
index 0000000..46ac9cf
--- /dev/null
+++ b/plat/st/common/stm32cubeprogrammer_uart.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <lib/mmio.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32cubeprogrammer.h>
+
+/* USART bootloader protocol version V4.0 */
+#define USART_BL_VERSION	0x40U
+
+/* Command definition */
+#define GET_CMD_COMMAND		0x00U
+#define GET_VER_COMMAND		0x01U
+#define GET_ID_COMMAND		0x02U
+#define PHASE_COMMAND		0x03U
+#define READ_PART_COMMAND	0x12U
+#define START_COMMAND		0x21U
+#define DOWNLOAD_COMMAND	0x31U
+
+/* Answer defines */
+#define INIT_BYTE		0x7FU
+#define ACK_BYTE		0x79U
+#define NACK_BYTE		0x1FU
+#define ABORT			0x5FU
+
+#define UNDEFINED_DOWN_ADDR	U(0xFFFFFFFF)
+#define PROGRAMMER_TIMEOUT_US	20000U
+
+static const uint8_t command_tab[] = {
+	GET_CMD_COMMAND,
+	GET_VER_COMMAND,
+	GET_ID_COMMAND,
+	PHASE_COMMAND,
+	START_COMMAND,
+	DOWNLOAD_COMMAND
+};
+
+/* STM32CubeProgrammer over UART handle */
+struct stm32prog_uart_handle_s {
+	struct stm32_uart_handle_s uart;
+	uint32_t packet;
+	uint8_t *addr;
+	uint32_t len;
+	uint8_t phase;
+	/* Error msg buffer: max 255 in UART protocol, reduced in TF-A */
+	uint8_t error[64];
+} handle;
+
+/* Trace and handle unrecoverable UART protocol error */
+#define STM32PROG_ERROR(...) \
+	{ \
+		ERROR(__VA_ARGS__); \
+		if (handle.phase != PHASE_RESET) { \
+			snprintf((char *)&handle.error, sizeof(handle.error), __VA_ARGS__); \
+			handle.phase = PHASE_RESET; \
+			handle.addr = (uint8_t *)UNDEFINED_DOWN_ADDR; \
+			handle.len = 0U; \
+			handle.packet = 0U; \
+		} \
+	}
+
+static int uart_write(const uint8_t *addr, uint16_t size)
+{
+	while (size != 0U) {
+		if (stm32_uart_putc(&handle.uart, *addr) != 0) {
+			return -EIO;
+		}
+		size--;
+		addr++;
+	}
+
+	return 0;
+}
+
+static int uart_write_8(uint8_t byte)
+{
+	return stm32_uart_putc(&handle.uart, byte);
+}
+
+static int uart_write_32(uint32_t value)
+{
+	return uart_write((uint8_t *)&value, 4U);
+}
+
+static int uart_read_8(uint8_t *byte)
+{
+	int ret;
+	uint64_t timeout_ref = timeout_init_us(PROGRAMMER_TIMEOUT_US);
+
+	do {
+		ret = stm32_uart_getc(&handle.uart);
+		if (ret == -EAGAIN) {
+			if (timeout_elapsed(timeout_ref)) {
+				return -ETIMEDOUT;
+			}
+		} else if (ret < 0) {
+			return ret;
+		}
+	} while (ret == -EAGAIN);
+
+	*byte = (uint8_t)ret;
+
+	return 0;
+}
+
+static int uart_send_result(uint8_t byte)
+{
+	int ret;
+
+	/* Always flush fifo before to send result = read all pending data */
+	do {
+		ret = stm32_uart_getc(&handle.uart);
+	} while (ret >= 0);
+
+	return uart_write_8(byte);
+}
+
+static bool is_valid_header(fip_toc_header_t *header)
+{
+	return (header->name == TOC_HEADER_NAME) &&
+	       (header->serial_number != 0U);
+}
+
+static int uart_receive_command(uint8_t *command)
+{
+	uint8_t byte = 0U;
+	uint8_t xor = 0U;
+	unsigned int count;
+	bool found = false;
+	int ret;
+
+	/* Repeat read until something is received */
+	do {
+		stm32_iwdg_refresh();
+		ret = uart_read_8(&byte);
+	} while (ret == -ETIMEDOUT);
+
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Handle reconnection request */
+	if (byte == INIT_BYTE) {
+		*command = byte;
+		return 0;
+	}
+
+	for (count = 0U; count < ARRAY_SIZE(command_tab); count++) {
+		if (command_tab[count] == byte) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		VERBOSE("UART: Command unknown (byte=0x%x)\n", byte);
+		return -EPROTO;
+	}
+
+	ret = uart_read_8(&xor);
+	if (ret != 0) {
+		return ret;
+	}
+	if ((byte ^ xor) != 0xFF) {
+		VERBOSE("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n",
+			byte, xor);
+		return -EPROTO;
+	}
+
+	*command = byte;
+
+	return 0;
+}
+
+static int get_cmd_command(void)
+{
+	const uint8_t msg[2] = {
+		sizeof(command_tab), /* Length of data - 1 */
+		USART_BL_VERSION
+	};
+	int ret;
+
+	ret = uart_write(msg, sizeof(msg));
+	if (ret != 0) {
+		return ret;
+	}
+
+	return uart_write(command_tab, sizeof(command_tab));
+}
+
+static int get_version_command(void)
+{
+	return uart_write_8(STM32_TF_VERSION);
+}
+
+static int get_id_command(void)
+{
+	uint8_t msg[3] = {
+		sizeof(msg) - 1 /* Length of data - 1 */
+	};
+	uint32_t chip_id = stm32mp_get_chip_dev_id();
+
+	be16enc(&msg[1], chip_id);
+
+	return uart_write(msg, sizeof(msg));
+}
+
+static int uart_send_phase(uint32_t address)
+{
+	int ret;
+	uint8_t msg_size = 5U; /* Length of data - 1 */
+	uint8_t error_size = 0U;
+
+	/* Additional information only for RESET phase */
+	if (handle.phase == PHASE_RESET) {
+		error_size = strnlen((char *)&handle.error, sizeof(handle.error));
+	}
+	ret = uart_write_8(msg_size + error_size);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Send the ID of next partition */
+	ret = uart_write_8(handle.phase);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Destination address */
+	ret = uart_write_32(address);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = uart_write_8(error_size);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Additional information: message error */
+	if (error_size > 0U) {
+		ret = uart_write(handle.error, error_size);
+	}
+
+	return ret;
+}
+
+static int uart_download_part(void)
+{
+	uint8_t operation = 0U;
+	uint8_t xor;
+	uint8_t byte = 0U;
+	uint32_t packet_number = 0U;
+	uint32_t packet_size = 0U;
+	uint32_t i = 0U;
+	int ret;
+
+	/* Get operation number */
+	ret = uart_read_8(&operation);
+	if (ret != 0) {
+		return ret;
+	}
+
+	xor = operation;
+
+	/* Get packet number */
+	for (i = 3U; i != 0U; i--) {
+		ret = uart_read_8(&byte);
+		if (ret != 0) {
+			return ret;
+		}
+
+		xor ^= byte;
+		packet_number = (packet_number << 8) | byte;
+	}
+
+	if (packet_number != handle.packet) {
+		WARN("UART: Bad packet number receive: %u, expected %u\n",
+		     packet_number, handle.packet);
+		return -EPROTO;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+	if (xor != byte) {
+		VERBOSE("UART: Download Command checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	ret = uart_send_result(ACK_BYTE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+	xor = byte;
+	packet_size = byte + 1U;
+	if (handle.len < packet_size) {
+		STM32PROG_ERROR("Download overflow at %p\n", handle.addr + packet_size);
+		return 0;
+	}
+
+	for (i = 0U; i < packet_size; i++) {
+		ret = uart_read_8(&byte);
+		if (ret != 0) {
+			return ret;
+		}
+
+		*(handle.addr + i) = byte;
+		xor ^= byte;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte) != 0;
+	if (ret != 0) {
+		return ret;
+	}
+	if (xor != byte) {
+		VERBOSE("UART: Download Data checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	/* Packet treated */
+	handle.packet++;
+	handle.addr += packet_size;
+	handle.len -= packet_size;
+
+	return 0;
+}
+
+static int uart_start_cmd(uintptr_t buffer)
+{
+	uint8_t byte = 0U;
+	uint8_t xor = 0U;
+	uint32_t i;
+	uint32_t start_address = 0U;
+	int ret;
+
+	/* Get address */
+	for (i = 4U; i != 0U; i--) {
+		ret = uart_read_8(&byte);
+		if (ret != 0U) {
+			return ret;
+		}
+
+		xor ^= byte;
+		start_address = (start_address << 8) | byte;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (xor != byte) {
+		VERBOSE("UART: Start Command checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	if (start_address != UNDEFINED_DOWN_ADDR) {
+		STM32PROG_ERROR("Invalid start at %x, for phase %u\n",
+				start_address, handle.phase);
+		return 0;
+	}
+
+	if (!is_valid_header((fip_toc_header_t *)buffer)) {
+		STM32PROG_ERROR("FIP Header check failed %lx, for phase %u\n",
+				buffer, handle.phase);
+		return -EIO;
+	}
+	VERBOSE("FIP header looks OK.\n");
+
+	return 0;
+}
+
+static int uart_read(uint8_t id, uintptr_t buffer, size_t length)
+{
+	bool start_done = false;
+	int ret;
+	uint8_t command = 0U;
+
+	handle.phase = id;
+	handle.packet = 0U;
+	handle.addr = (uint8_t *)buffer;
+	handle.len = length;
+
+	INFO("UART: read phase %u at 0x%lx size 0x%x\n",
+	     id, buffer, length);
+	while (!start_done) {
+		ret = uart_receive_command(&command);
+		if (ret != 0) {
+			/* Delay to wait STM32CubeProgrammer end of transmission */
+			mdelay(3);
+
+			ret = uart_send_result(NACK_BYTE);
+			if (ret != 0U) {
+				return ret;
+			}
+
+			continue;
+		}
+
+		uart_send_result(ACK_BYTE);
+
+		switch (command) {
+		case INIT_BYTE:
+			INFO("UART: Connected\n");
+			/* Nothing to do */
+			continue;
+
+		case GET_CMD_COMMAND:
+			ret = get_cmd_command();
+			break;
+
+		case GET_VER_COMMAND:
+			ret = get_version_command();
+			break;
+
+		case GET_ID_COMMAND:
+			ret = get_id_command();
+			break;
+
+		case PHASE_COMMAND:
+			ret = uart_send_phase((uint32_t)buffer);
+			if ((ret == 0) && (handle.phase == PHASE_RESET)) {
+				start_done = true;
+				INFO("UART: Reset\n");
+			}
+			break;
+
+		case DOWNLOAD_COMMAND:
+			ret = uart_download_part();
+			break;
+
+		case START_COMMAND:
+			ret = uart_start_cmd(buffer);
+			if ((ret == 0) && (handle.phase == id)) {
+				INFO("UART: Start phase %u\n", handle.phase);
+				start_done = true;
+			}
+			break;
+
+		default:
+			WARN("UART: Unknown command\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret == 0) {
+			ret = uart_send_result(ACK_BYTE);
+		} else {
+			ret = uart_send_result(NACK_BYTE);
+		}
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* Init UART: 115200, 8bit 1stop parity even and enable FIFO mode */
+const struct stm32_uart_init_s init = {
+	.baud_rate = U(115200),
+	.word_length = STM32_UART_WORDLENGTH_9B,
+	.stop_bits = STM32_UART_STOPBITS_1,
+	.parity = STM32_UART_PARITY_EVEN,
+	.hw_flow_control = STM32_UART_HWCONTROL_NONE,
+	.mode = STM32_UART_MODE_TX_RX,
+	.over_sampling = STM32_UART_OVERSAMPLING_16,
+	.fifo_mode = STM32_UART_FIFOMODE_EN,
+};
+
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len)
+{
+	int ret;
+
+	if (stm32_uart_init(&handle.uart, instance, &init) != 0) {
+		return -EIO;
+	}
+
+	/*
+	 * The following NACK_BYTE is written because STM32CubeProgrammer has
+	 * already sent its command before TF-A has reached this point, and
+	 * because FIFO was not configured by BootROM.
+	 * The byte in the UART_RX register is then the checksum and not the
+	 * command. NACK_BYTE has to be written, so that the programmer will
+	 * re-send the good command.
+	 */
+	ret = uart_send_result(NACK_BYTE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return uart_read(PHASE_SSBL, base, len);
+}
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;