Merge changes from topic "db/exception_pstate" into integration

* changes:
  test(el3-runtime): dit is retained on world switch
  fix(el3-runtime): set unset pstate bits to default
  refactor(el3-runtime): add prepare_el3_entry func
diff --git a/changelog.yaml b/changelog.yaml
index 1bb542a..c4ed59b 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -348,6 +348,9 @@
             deprecated:
               - plat/qti/sc7280
 
+          - title: MSM8916
+            scope: msm8916
+
       - title: Raspberry Pi
         scope: rpi
 
@@ -446,10 +449,10 @@
 
     subsections:
       - title: FF-A
-        scope: ffa
+        scope: ff-a
 
         deprecated:
-          - ff-a
+          - ffa
 
       - title: RME
         scope: rme
@@ -461,7 +464,9 @@
           - spmc
           - spmd
           - SPMD
-          - spm_mm
+
+      - title: SPM MM
+        scope: spm-mm
 
   - title: Libraries
 
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index e0a7587..94c63f4 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -580,6 +580,15 @@
 :|F|: docs/plat/qti.rst
 :|F|: plat/qti/
 
+QTI MSM8916 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Stephan Gerhold <stephan@gerhold.net>
+:|G|: `stephan-gh`_
+:|M|: Nikita Travkin <nikita@trvn.ru>
+:|G|: `TravMurav`_
+:|F|: docs/plat/qti-msm8916.rst
+:|F|: plat/qti/msm8916/
+
 Raspberry Pi 3 platform port
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
@@ -797,9 +806,11 @@
 .. _smaeul: https://github.com/smaeul
 .. _soby-mathew: https://github.com/soby-mathew
 .. _sreekare: https://github.com/sreekare
+.. _stephan-gh: https://github.com/stephan-gh
 .. _thloh85-intel: https://github.com/thloh85-intel
 .. _thomas-arm: https://github.com/thomas-arm
 .. _TonyXie06: https://github.com/TonyXie06
+.. _TravMurav: https://github.com/TravMurav
 .. _vwadekar: https://github.com/vwadekar
 .. _venkatesh: https://github.com/vabbarap
 .. _Yann-lms: https://github.com/Yann-lms
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 57cc488..0cef16a 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -32,6 +32,7 @@
    qemu
    qemu-sbsa
    qti
+   qti-msm8916
    rpi3
    rpi4
    rcar-gen3
diff --git a/docs/plat/qti-msm8916.rst b/docs/plat/qti-msm8916.rst
new file mode 100644
index 0000000..09a79b7
--- /dev/null
+++ b/docs/plat/qti-msm8916.rst
@@ -0,0 +1,116 @@
+Qualcomm Snapdragon 410 (MSM8916/APQ8016)
+=========================================
+
+The `Qualcomm Snapdragon 410`_ is Qualcomm's first 64-bit SoC, released in 2014
+with four ARM Cortex-A53 cores. There are differents variants (MSM8916,
+APQ8016(E), ...) that are all very similar. A popular device based on APQ8016E
+is the `DragonBoard 410c`_ single-board computer, but the SoC is also used in
+various mid-range smartphones/tablets.
+
+The TF-A/BL31 port for MSM8916 provides a minimal, community-maintained
+EL3 firmware. It is primarily based on information from the public
+`Snapdragon 410E Technical Reference Manual`_ combined with a lot of
+trial and error to actually make it work.
+
+.. note::
+	Unlike the :doc:`QTI SC7180/SC7280 <qti>` ports, this port does **not**
+	make use of a proprietary binary components (QTISECLIB). It is fully
+	open-source but therefore limited to publicly documented hardware
+	components.
+
+Functionality
+-------------
+
+The BL31 port is much more minimal compared to the original firmware and
+therefore expects the non-secure world (e.g. Linux) to manage more hardware,
+such as the SMMUs and all remote processors (RPM, WCNSS, Venus, Modem).
+Everything except modem is currently functional with a slightly modified version
+of mainline Linux.
+
+.. warning::
+	This port is **not secure**. There is no special secure memory and the
+	used DRAM is available from both the non-secure and secure worlds.
+	Unfortunately, the hardware used for memory protection is not described
+	in the APQ8016E documentation.
+
+The port is primarily intended as a minimal PSCI implementation (without a
+separate secure world) where this limitation is not a big problem. Booting
+secondary CPU cores (PSCI ``CPU_ON``) is supported. Basic CPU core power
+management (``CPU_SUSPEND``) is functional but still work-in-progress and
+will be added later once ready.
+
+Boot Flow
+---------
+BL31 replaces the original ``tz`` firmware in the boot flow::
+
+	Boot ROM (PBL) -> SBL -> BL31 (EL3) -> U-Boot (EL2) -> Linux (EL2)
+
+By default, BL31 enters the non-secure world in EL2 AArch64 state at address
+``0x8f600000``. The original hypervisor firmware (``hyp``) is not used, you can
+use KVM or another hypervisor. The entry address is fixed in the BL31 binary
+but can be changed using the ``PRELOADED_BL33_BASE`` make file parameter.
+
+Using an AArch64 bootloader (such as `U-Boot for DragonBoard 410c`_) is
+recommended. AArch32 bootloaders (such as the original Little Kernel bootloader
+from Qualcomm) are not directly supported, although it is possible to use an EL2
+shim loader to temporarily switch to AArch32 state.
+
+Installation
+------------
+First, setup the cross compiler for AArch64 and build TF-A for ``msm8916``::
+
+	$ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=msm8916
+
+The BL31 ELF image is generated in ``build/msm8916/release/bl31/bl31.elf``.
+This image must be "signed" before flashing it, even if the board has secure
+boot disabled. In this case the signature does not provide any security,
+but it provides the firmware with required metadata.
+
+The `DragonBoard 410c`_ does not have secure boot enabled by default. In this
+case you can simply sign the ELF image using a randomly generated key. You can
+use e.g. `qtestsign`_::
+
+	$ ./qtestsign.py tz build/msm8916/release/bl31/bl31.elf
+
+Then install the resulting ``build/msm8916/release/bl31/bl31-test-signed.mbn``
+to the ``tz`` partition on the device. BL31 should be running after a reboot.
+
+.. warning::
+	Do not flash incorrectly signed firmware on devices that have secure
+	boot enabled! Make sure that you have a way to recover the board in case
+	of problems (e.g. using EDL).
+
+Boot Trace
+----------
+BL31 prints some lines on the debug console UART2, which will usually look like
+this (with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown)::
+
+	...
+	S - DDR Frequency, 400 MHz
+	NOTICE:  BL31: v2.6(debug):v2.6
+	NOTICE:  BL31: Built : 20:00:00, Dec 01 2021
+	INFO:    BL31: Platform setup start
+	INFO:    ARM GICv2 driver initialized
+	INFO:    BL31: Platform setup done
+	INFO:    BL31: Initializing runtime services
+	INFO:    BL31: cortex_a53: CPU workaround for 819472 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 824069 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 826319 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 827319 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 835769 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for disable_non_temporal_hint was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 843419 was applied
+	INFO:    BL31: cortex_a53: CPU workaround for 1530924 was applied
+	INFO:    BL31: Preparing for EL3 exit to normal world
+	INFO:    Entry point address = 0x8f600000
+	INFO:    SPSR = 0x3c9
+
+	U-Boot 2021.10 (Dec 01 2021 - 20:00:00 +0000)
+	Qualcomm-DragonBoard 410C
+	...
+
+.. _Qualcomm Snapdragon 410: https://www.qualcomm.com/products/snapdragon-processors-410
+.. _DragonBoard 410c: https://www.96boards.org/product/dragonboard410c/
+.. _Snapdragon 410E Technical Reference Manual: https://developer.qualcomm.com/download/sd410/snapdragon-410e-technical-reference-manual.pdf
+.. _U-Boot for DragonBoard 410c: https://u-boot.readthedocs.io/en/latest/board/qualcomm/dragonboard410c.html
+.. _qtestsign: https://github.com/msm8916-mainline/qtestsign
diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c
index 3537fbe..399115c 100644
--- a/drivers/scmi-msg/entry.c
+++ b/drivers/scmi-msg/entry.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-3-Clause
 /*
- * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2020, Linaro Limited
  */
 
@@ -84,7 +84,7 @@
 		return;
 	}
 
-	ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported",
+	ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported\n",
 	      msg->agent_id, msg->protocol_id, msg->message_id);
 
 	scmi_status_response(msg, SCMI_NOT_SUPPORTED);
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec2.c
similarity index 63%
rename from drivers/st/bsec/bsec.c
rename to drivers/st/bsec/bsec2.c
index 01c369e..68d3a5b 100644
--- a/drivers/st/bsec/bsec.c
+++ b/drivers/st/bsec/bsec2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,18 +7,19 @@
 #include <assert.h>
 #include <limits.h>
 
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
 #include <libfdt.h>
 
 #include <platform_def.h>
 
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <drivers/st/bsec.h>
-#include <lib/mmio.h>
-#include <lib/spinlock.h>
-
-#define BSEC_IP_VERSION_1_0	0x10
-#define BSEC_COMPAT		"st,stm32mp15-bsec"
+#define BSEC_IP_VERSION_1_1	U(0x11)
+#define BSEC_IP_VERSION_2_0	U(0x20)
+#define BSEC_IP_ID_2		U(0x100032)
 
 #define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
 
@@ -44,11 +45,23 @@
 	}
 }
 
+static bool is_otp_invalid_mode(void)
+{
+	bool ret = ((bsec_get_status() & BSEC_MODE_INVALID) == BSEC_MODE_INVALID);
+
+	if (ret) {
+		ERROR("OTP mode is OTP-INVALID\n");
+	}
+
+	return ret;
+}
+
+#if defined(IMAGE_BL32)
 static int bsec_get_dt_node(struct dt_node_info *info)
 {
 	int node;
 
-	node = dt_get_node(info, -1, BSEC_COMPAT);
+	node = dt_get_node(info, -1, DT_BSEC_COMPAT);
 	if (node < 0) {
 		return -FDT_ERR_NOTFOUND;
 	}
@@ -56,7 +69,6 @@
 	return node;
 }
 
-#if defined(IMAGE_BL32)
 static void enable_non_secure_access(uint32_t otp)
 {
 	otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
@@ -69,79 +81,74 @@
 static bool non_secure_can_access(uint32_t otp)
 {
 	return (otp_nsec_access[otp / __WORD_BIT] &
-		BIT(otp % __WORD_BIT)) != 0;
+		BIT(otp % __WORD_BIT)) != 0U;
 }
 
-static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
+static void bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
 {
 	int bsec_subnode;
 
 	fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
 		const fdt32_t *cuint;
-		uint32_t reg;
+		uint32_t otp;
 		uint32_t i;
 		uint32_t size;
-		uint8_t status;
+		uint32_t offset;
+		uint32_t length;
 
 		cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
 		if (cuint == NULL) {
 			panic();
 		}
 
-		reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
-		if (reg < STM32MP1_UPPER_OTP_START) {
+		offset = fdt32_to_cpu(*cuint);
+		cuint++;
+		length = fdt32_to_cpu(*cuint);
+
+		otp = offset / sizeof(uint32_t);
+
+		if (otp < STM32MP1_UPPER_OTP_START) {
+			unsigned int otp_end = round_up(offset + length,
+						       sizeof(uint32_t)) /
+					       sizeof(uint32_t);
+
+			if (otp_end > STM32MP1_UPPER_OTP_START) {
+				/*
+				 * OTP crosses Lower/Upper boundary, consider
+				 * only the upper part.
+				 */
+				otp = STM32MP1_UPPER_OTP_START;
+				length -= (STM32MP1_UPPER_OTP_START *
+					   sizeof(uint32_t)) - offset;
+				offset = STM32MP1_UPPER_OTP_START *
+					 sizeof(uint32_t);
+
+				WARN("OTP crosses Lower/Upper boundary\n");
+			} else {
+				continue;
+			}
+		}
+
+		if ((fdt_getprop(fdt, bsec_subnode,
+				 "st,non-secure-otp", NULL)) == NULL) {
 			continue;
 		}
 
-		status = fdt_get_status(bsec_subnode);
-		if ((status & DT_NON_SECURE) == 0U)  {
-			continue;
+		if (((offset % sizeof(uint32_t)) != 0U) ||
+		    ((length % sizeof(uint32_t)) != 0U)) {
+			ERROR("Unaligned non-secure OTP\n");
+			panic();
 		}
 
-		size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
+		size = length / sizeof(uint32_t);
 
-		if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
-			size++;
-		}
-
-		for (i = reg; i < (reg + size); i++) {
+		for (i = otp; i < (otp + size); i++) {
 			enable_non_secure_access(i);
 		}
 	}
-
-	return 0;
-}
-#endif
-
-static uint32_t otp_bank_offset(uint32_t otp)
-{
-	assert(otp <= STM32MP1_OTP_MAX_ID);
-
-	return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
-	       sizeof(uint32_t);
 }
 
-static uint32_t bsec_check_error(uint32_t otp)
-{
-	uint32_t bit = BIT(otp & BSEC_OTP_MASK);
-	uint32_t bank = otp_bank_offset(otp);
-
-	if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
-		return BSEC_DISTURBED;
-	}
-
-	if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
-		return BSEC_ERROR;
-	}
-
-	return BSEC_OK;
-}
-
-/*
- * bsec_probe: initialize BSEC driver.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_probe(void)
+static void bsec_late_init(void)
 {
 	void *fdt;
 	int node;
@@ -156,10 +163,67 @@
 		panic();
 	}
 
-	bsec_base = bsec_info.base;
+	assert(bsec_base == bsec_info.base);
+
+	bsec_dt_otp_nsec_access(fdt, node);
+}
+#endif
+
+static uint32_t otp_bank_offset(uint32_t otp)
+{
+	assert(otp <= STM32MP1_OTP_MAX_ID);
+
+	return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+	       sizeof(uint32_t);
+}
+
+/*
+ * bsec_check_error: check BSEC error status.
+ * otp: OTP number.
+ * check_disturbed: check only error (false),
+ *	or error and disturbed status (true).
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
+{
+	uint32_t bit = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank = otp_bank_offset(otp);
+
+	if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+		return BSEC_ERROR;
+	}
+
+	if (!check_disturbed) {
+		return BSEC_OK;
+	}
+
+	if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+		return BSEC_DISTURBED;
+	}
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+	bsec_base = BSEC_BASE;
+
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
+
+	if ((((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_1_1) &&
+	     ((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_2_0)) ||
+	    (bsec_get_id() != BSEC_IP_ID_2)) {
+		panic();
+	}
 
 #if defined(IMAGE_BL32)
-	bsec_dt_otp_nsec_access(fdt, node);
+	bsec_late_init();
 #endif
 	return BSEC_OK;
 }
@@ -180,7 +244,11 @@
 uint32_t bsec_set_config(struct bsec_config *cfg)
 {
 	uint32_t value;
-	int32_t result;
+	uint32_t result;
+
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
 
 	value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
 						BSEC_CONF_FRQ_MASK) |
@@ -259,15 +327,21 @@
 uint32_t bsec_shadow_register(uint32_t otp)
 {
 	uint32_t result;
+	bool value;
 	bool power_up = false;
 
-	if (otp > STM32MP1_OTP_MAX_ID) {
-		return BSEC_INVALID_PARAM;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
 	}
 
-	/* Check if shadowing of OTP is locked */
-	if (bsec_read_sr_lock(otp)) {
-		VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
+	result = bsec_read_sr_lock(otp, &value);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
+		return result;
+	}
+
+	if (value) {
+		VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n",
 			otp);
 	}
 
@@ -283,14 +357,13 @@
 
 	bsec_lock();
 
-	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
 	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
 
 	while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
 		;
 	}
 
-	result = bsec_check_error(otp);
+	result = bsec_check_error(otp, true);
 
 	bsec_unlock();
 
@@ -311,22 +384,18 @@
  */
 uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
 {
-	uint32_t result;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
 
 	if (otp > STM32MP1_OTP_MAX_ID) {
 		return BSEC_INVALID_PARAM;
 	}
 
-	bsec_lock();
-
 	*val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
 			    (otp * sizeof(uint32_t)));
 
-	result = bsec_check_error(otp);
-
-	bsec_unlock();
-
-	return result;
+	return BSEC_OK;
 }
 
 /*
@@ -338,24 +407,29 @@
 uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
 {
 	uint32_t result;
+	bool value;
 
-	if (otp > STM32MP1_OTP_MAX_ID) {
-		return BSEC_INVALID_PARAM;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
 	}
 
-	/* Check if programming of OTP is locked */
-	if (bsec_read_sw_lock(otp)) {
-		VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
+	result = bsec_read_sw_lock(otp, &value);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result);
+		return result;
+	}
+
+	if (value) {
+		VERBOSE("BSEC: OTP %u is locked and write will be ignored\n",
 			otp);
 	}
 
+	/* Ensure integrity of each register access sequence */
 	bsec_lock();
 
 	mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
 		      (otp * sizeof(uint32_t)), val);
 
-	result = bsec_check_error(otp);
-
 	bsec_unlock();
 
 	return result;
@@ -372,14 +446,28 @@
 {
 	uint32_t result;
 	bool power_up = false;
+	bool sp_lock;
+	bool perm_lock;
 
-	if (otp > STM32MP1_OTP_MAX_ID) {
-		return BSEC_INVALID_PARAM;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
 	}
 
-	/* Check if programming of OTP is locked */
-	if (bsec_read_sp_lock(otp)) {
+	result = bsec_read_sp_lock(otp, &sp_lock);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
+		return result;
+	}
+
+	result = bsec_read_permanent_lock(otp, &perm_lock);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u permanent bit read Error %u\n", otp, result);
+		return result;
+	}
+
+	if (sp_lock || perm_lock) {
 		WARN("BSEC: OTP locked, prog will be ignored\n");
+		return BSEC_PROG_FAIL;
 	}
 
 	if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
@@ -399,10 +487,8 @@
 
 	bsec_lock();
 
-	/* Set value in write register */
 	mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
 
-	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
 	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
 
 	while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
@@ -412,7 +498,7 @@
 	if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
 		result = BSEC_PROG_FAIL;
 	} else {
-		result = bsec_check_error(otp);
+		result = bsec_check_error(otp, true);
 	}
 
 	bsec_unlock();
@@ -438,6 +524,10 @@
 	uint32_t data;
 	uint32_t addr;
 
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
+
 	if (otp > STM32MP1_OTP_MAX_ID) {
 		return BSEC_INVALID_PARAM;
 	}
@@ -464,10 +554,8 @@
 
 	bsec_lock();
 
-	/* Set value in write register */
 	mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
 
-	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
 	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
 		      addr | BSEC_WRITE | BSEC_LOCK);
 
@@ -478,7 +566,7 @@
 	if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
 		result = BSEC_PROG_FAIL;
 	} else {
-		result = bsec_check_error(otp);
+		result = bsec_check_error(otp, false);
 	}
 
 	bsec_unlock();
@@ -493,31 +581,24 @@
 }
 
 /*
- * bsec_write_debug_conf: write value in debug feature
+ * bsec_write_debug_conf: write value in debug feature.
  *	to enable/disable debug service.
  * val: value to write.
- * return value: BSEC_OK if no error.
+ * return value: none.
  */
-uint32_t bsec_write_debug_conf(uint32_t val)
+void bsec_write_debug_conf(uint32_t val)
 {
-	uint32_t result = BSEC_ERROR;
-	uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
-
-	bsec_lock();
-
-	mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
-
-	if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
-		result = BSEC_OK;
+	if (is_otp_invalid_mode()) {
+		return;
 	}
 
+	bsec_lock();
+	mmio_write_32(bsec_base + BSEC_DEN_OFF, val & BSEC_DEN_ALL_MSK);
 	bsec_unlock();
-
-	return result;
 }
 
 /*
- * bsec_read_debug_conf: read debug configuration.
+ * bsec_read_debug_conf: return debug configuration register value.
  */
 uint32_t bsec_read_debug_conf(void)
 {
@@ -525,6 +606,34 @@
 }
 
 /*
+ * bsec_write_scratch: write value in scratch register.
+ * val: value to write.
+ * return value: none.
+ */
+void bsec_write_scratch(uint32_t val)
+{
+#if defined(IMAGE_BL32)
+	if (is_otp_invalid_mode()) {
+		return;
+	}
+
+	bsec_lock();
+	mmio_write_32(bsec_base + BSEC_SCRATCH_OFF, val);
+	bsec_unlock();
+#else
+	mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
+#endif
+}
+
+/*
+ * bsec_read_scratch: return scratch register value.
+ */
+uint32_t bsec_read_scratch(void)
+{
+	return mmio_read_32(bsec_base + BSEC_SCRATCH_OFF);
+}
+
+/*
  * bsec_get_status: return status register value.
  */
 uint32_t bsec_get_status(void)
@@ -533,7 +642,7 @@
 }
 
 /*
- * bsec_get_hw_conf: return hardware configuration.
+ * bsec_get_hw_conf: return hardware configuration register value.
  */
 uint32_t bsec_get_hw_conf(void)
 {
@@ -541,7 +650,7 @@
 }
 
 /*
- * bsec_get_version: return BSEC version.
+ * bsec_get_version: return BSEC version register value.
  */
 uint32_t bsec_get_version(void)
 {
@@ -549,7 +658,7 @@
 }
 
 /*
- * bsec_get_id: return BSEC ID.
+ * bsec_get_id: return BSEC ID register value.
  */
 uint32_t bsec_get_id(void)
 {
@@ -557,7 +666,7 @@
 }
 
 /*
- * bsec_get_magic_id: return BSEC magic number.
+ * bsec_get_magic_id: return BSEC magic number register value.
  */
 uint32_t bsec_get_magic_id(void)
 {
@@ -565,229 +674,194 @@
 }
 
 /*
- * bsec_write_sr_lock: write shadow-read lock.
+ * bsec_set_sr_lock: set shadow-read lock.
  * otp: OTP number.
- * value: value to write in the register.
- *	Must be always 1.
- * return: true if OTP is locked, else false.
+ * return value: BSEC_OK if no error.
  */
-bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
+uint32_t bsec_set_sr_lock(uint32_t otp)
 {
-	bool result = false;
 	uint32_t bank = otp_bank_offset(otp);
-	uint32_t bank_value;
 	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
 
-	bsec_lock();
-
-	bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
-
-	if ((bank_value & otp_mask) == value) {
-		/*
-		 * In case of write don't need to write,
-		 * the lock is already set.
-		 */
-		if (value != 0U) {
-			result = true;
-		}
-	} else {
-		if (value != 0U) {
-			bank_value = bank_value | otp_mask;
-		} else {
-			bank_value = bank_value & ~otp_mask;
-		}
-
-		/*
-		 * We can write 0 in all other OTP
-		 * if the lock is activated in one of other OTP.
-		 * Write 0 has no effect.
-		 */
-		mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
-		result = true;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
 	}
 
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bsec_lock();
+	mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, otp_mask);
 	bsec_unlock();
 
-	return result;
+	return BSEC_OK;
 }
 
 /*
  * bsec_read_sr_lock: read shadow-read lock.
  * otp: OTP number.
- * return: true if otp is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
  */
-bool bsec_read_sr_lock(uint32_t otp)
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
 {
 	uint32_t bank = otp_bank_offset(otp);
 	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
-	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
-
-	return (bank_value & otp_mask) != 0U;
-}
-
-/*
- * bsec_write_sw_lock: write shadow-write lock.
- * otp: OTP number.
- * value: Value to write in the register.
- *	Must be always 1.
- * return: true if OTP is locked, else false.
- */
-bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
-{
-	bool result = false;
-	uint32_t bank = otp_bank_offset(otp);
-	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
 	uint32_t bank_value;
 
-	bsec_lock();
-
-	bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
-
-	if ((bank_value & otp_mask) == value) {
-		/*
-		 * In case of write don't need to write,
-		 * the lock is already set.
-		 */
-		if (value != 0U) {
-			result = true;
-		}
-	} else {
-		if (value != 0U) {
-			bank_value = bank_value | otp_mask;
-		} else {
-			bank_value = bank_value & ~otp_mask;
-		}
-
-		/*
-		 * We can write 0 in all other OTP
-		 * if the lock is activated in one of other OTP.
-		 * Write 0 has no effect.
-		 */
-		mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
-		result = true;
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
 	}
 
+	bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+	*value = ((bank_value & otp_mask) != 0U);
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_set_sw_lock: set shadow-write lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sw_lock(uint32_t otp)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bsec_lock();
+	mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, otp_mask);
 	bsec_unlock();
 
-	return result;
+	return BSEC_OK;
 }
 
 /*
  * bsec_read_sw_lock: read shadow-write lock.
  * otp: OTP number.
- * return: true if OTP is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
  */
-bool bsec_read_sw_lock(uint32_t otp)
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
 {
 	uint32_t bank = otp_bank_offset(otp);
 	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
-	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+	uint32_t bank_value;
 
-	return (bank_value & otp_mask) != 0U;
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+	*value = ((bank_value & otp_mask) != 0U);
+
+	return BSEC_OK;
 }
 
 /*
- * bsec_write_sp_lock: write shadow-program lock.
+ * bsec_set_sp_lock: set shadow-program lock.
  * otp: OTP number.
- * value: Value to write in the register.
- *	Must be always 1.
- * return: true if OTP is locked, else false.
+ * return value: BSEC_OK if no error.
  */
-bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
+uint32_t bsec_set_sp_lock(uint32_t otp)
 {
-	bool result = false;
 	uint32_t bank = otp_bank_offset(otp);
-	uint32_t bank_value;
 	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
 
-	bsec_lock();
-
-	bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
-
-	if ((bank_value & otp_mask) == value) {
-		/*
-		 * In case of write don't need to write,
-		 * the lock is already set.
-		 */
-		if (value != 0U) {
-			result = true;
-		}
-	} else {
-		if (value != 0U) {
-			bank_value = bank_value | otp_mask;
-		} else {
-			bank_value = bank_value & ~otp_mask;
-		}
-
-		/*
-		 * We can write 0 in all other OTP
-		 * if the lock is activated in one of other OTP.
-		 * Write 0 has no effect.
-		 */
-		mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
-		result = true;
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
 	}
 
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bsec_lock();
+	mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, otp_mask);
 	bsec_unlock();
 
-	return result;
+	return BSEC_OK;
 }
 
 /*
  * bsec_read_sp_lock: read shadow-program lock.
  * otp: OTP number.
- * return: true if OTP is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
  */
-bool bsec_read_sp_lock(uint32_t otp)
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
 {
 	uint32_t bank = otp_bank_offset(otp);
 	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
-	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+	uint32_t bank_value;
 
-	return (bank_value & otp_mask) != 0U;
-}
-
-/*
- * bsec_wr_lock: Read permanent lock status.
- * otp: OTP number.
- * return: true if OTP is locked, else false.
- */
-bool bsec_wr_lock(uint32_t otp)
-{
-	uint32_t bank = otp_bank_offset(otp);
-	uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
-
-	if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
-	     lock_bit) != 0U) {
-		/*
-		 * In case of write don't need to write,
-		 * the lock is already set.
-		 */
-		return true;
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
 	}
 
-	return false;
+	bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+	*value = ((bank_value & otp_mask) != 0U);
+
+	return BSEC_OK;
 }
 
 /*
- * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable
- * service: Service to lock see header file.
- * value: Value to write must always set to 1 (only use for debug purpose).
- * return: BSEC_OK if succeed.
+ * bsec_read_permanent_lock: Read permanent lock status.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
  */
-uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank_value;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bank_value = mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank);
+
+	*value = ((bank_value & otp_mask) != 0U);
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_otp_lock: Lock Upper OTP or Global Programming or Debug Enable.
+ * service: Service to lock, see header file.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_otp_lock(uint32_t service)
 {
 	uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
 
+	if (is_otp_invalid_mode()) {
+		return BSEC_ERROR;
+	}
+
 	switch (service) {
 	case BSEC_LOCK_UPPER_OTP:
-		mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
+		mmio_write_32(reg, BIT(BSEC_LOCK_UPPER_OTP));
 		break;
 	case BSEC_LOCK_DEBUG:
-		mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
+		mmio_write_32(reg, BIT(BSEC_LOCK_DEBUG));
 		break;
 	case BSEC_LOCK_PROGRAM:
-		mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
+		mmio_write_32(reg, BIT(BSEC_LOCK_PROGRAM));
 		break;
 	default:
 		return BSEC_INVALID_PARAM;
@@ -799,7 +873,7 @@
 /*
  * bsec_power_safmem: Activate or deactivate SAFMEM power.
  * power: true to power up, false to power down.
- * return: BSEC_OK if succeed.
+ * return value: BSEC_OK if no error.
  */
 static uint32_t bsec_power_safmem(bool power)
 {
@@ -818,7 +892,6 @@
 
 	mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
 
-	/* Waiting loop */
 	if (power) {
 		while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
 		       (timeout != 0U)) {
@@ -841,7 +914,7 @@
 }
 
 /*
- * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value.
  * otp_value: read value.
  * word: OTP number.
  * return value: BSEC_OK if no error.
@@ -852,13 +925,13 @@
 
 	result = bsec_shadow_register(word);
 	if (result != BSEC_OK) {
-		ERROR("BSEC: %u Shadowing Error %i\n", word, result);
+		ERROR("BSEC: %u Shadowing Error %u\n", word, result);
 		return result;
 	}
 
 	result = bsec_read_otp(otp_value, word);
 	if (result != BSEC_OK) {
-		ERROR("BSEC: %u Read Error %i\n", word, result);
+		ERROR("BSEC: %u Read Error %u\n", word, result);
 	}
 
 	return result;
@@ -867,7 +940,7 @@
 /*
  * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
  * otp: OTP number.
- * return: BSEC_OK if authorized access.
+ * return value: BSEC_OK if authorized access.
  */
 uint32_t bsec_check_nsec_access_rights(uint32_t otp)
 {
@@ -877,11 +950,8 @@
 	}
 
 	if (otp >= STM32MP1_UPPER_OTP_START) {
-		/* Check if BSEC is in OTP-SECURED closed_device state. */
-		if (stm32mp_is_closed_device()) {
-			if (!non_secure_can_access(otp)) {
-				return BSEC_ERROR;
-			}
+		if (!non_secure_can_access(otp)) {
+			return BSEC_ERROR;
 		}
 	}
 #endif
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index af8b71e..f525741 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -1837,11 +1837,6 @@
 		return -FDT_ERR_NOTFOUND;
 	}
 
-	/* Check status field to disable security */
-	if (!fdt_get_rcc_secure_status()) {
-		mmio_write_32(rcc_base + RCC_TZCR, 0);
-	}
-
 	ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
 					clksrc);
 	if (ret < 0) {
@@ -2358,6 +2353,12 @@
 
 int stm32mp1_clk_probe(void)
 {
+#if defined(IMAGE_BL32)
+	if (!fdt_get_rcc_secure_state()) {
+		mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
+	}
+#endif
+
 	stm32mp1_osc_init();
 
 	sync_earlyboot_clocks_state();
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index a013a82..80c2f41 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -250,24 +250,22 @@
 }
 
 /*
- * Get the secure status for rcc node in device tree.
- * @return: true if rcc is available from secure world, false if not.
+ * Get the secure state for rcc node in device tree.
+ * @return: true if rcc is configured for secure world access, false if not.
  */
-bool fdt_get_rcc_secure_status(void)
+bool fdt_get_rcc_secure_state(void)
 {
-	int node;
 	void *fdt;
 
 	if (fdt_get_address(&fdt) == 0) {
 		return false;
 	}
 
-	node = fdt_get_rcc_node(fdt);
-	if (node < 0) {
+	if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
 		return false;
 	}
 
-	return !!(fdt_get_status(node) & DT_SECURE);
+	return true;
 }
 
 /*
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
index 5c54762..708989f 100644
--- a/drivers/st/gpio/stm32_gpio.c
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,10 +8,6 @@
 #include <errno.h>
 #include <stdbool.h>
 
-#include <libfdt.h>
-
-#include <platform_def.h>
-
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <drivers/clk.h>
@@ -19,6 +15,9 @@
 #include <drivers/st/stm32mp_clkfunc.h>
 #include <lib/mmio.h>
 #include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
 
 #define DT_GPIO_BANK_SHIFT	12
 #define DT_GPIO_BANK_MASK	GENMASK(16, 12)
@@ -26,6 +25,10 @@
 #define DT_GPIO_PIN_MASK	GENMASK(11, 8)
 #define DT_GPIO_MODE_MASK	GENMASK(7, 0)
 
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+		     uint32_t speed, uint32_t pull, uint32_t od,
+		     uint32_t alternate, uint8_t status);
+
 /*******************************************************************************
  * This function gets GPIO bank node in DT.
  * Returns node offset if status is okay in DT, else return 0
@@ -100,6 +103,8 @@
 		uint32_t pin;
 		uint32_t mode;
 		uint32_t alternate = GPIO_ALTERNATE_(0);
+		uint32_t type;
+		uint32_t od = GPIO_OD_OUTPUT_LOW;
 		int bank_node;
 		int clk;
 
@@ -129,7 +134,23 @@
 		}
 
 		if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
-			mode |= GPIO_OPEN_DRAIN;
+			type = GPIO_TYPE_OPEN_DRAIN;
+		} else {
+			type = GPIO_TYPE_PUSH_PULL;
+		}
+
+		if (fdt_getprop(fdt, node, "output-high", NULL) != NULL) {
+			if (mode == GPIO_MODE_INPUT) {
+				mode = GPIO_MODE_OUTPUT;
+				od = GPIO_OD_OUTPUT_HIGH;
+			}
+		}
+
+		if (fdt_getprop(fdt, node, "output-low", NULL) != NULL) {
+			if (mode == GPIO_MODE_INPUT) {
+				mode = GPIO_MODE_OUTPUT;
+				od = GPIO_OD_OUTPUT_LOW;
+			}
 		}
 
 		bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
@@ -146,7 +167,7 @@
 		/* Platform knows the clock: assert it is okay */
 		assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank));
 
-		set_gpio(bank, pin, mode, speed, pull, alternate, status);
+		set_gpio(bank, pin, mode, type, speed, pull, od, alternate, status);
 	}
 
 	return 0;
@@ -160,7 +181,7 @@
 int dt_set_pinctrl_config(int node)
 {
 	const fdt32_t *cuint;
-	int lenp = 0;
+	int lenp;
 	uint32_t i;
 	uint8_t status;
 	void *fdt;
@@ -201,8 +222,9 @@
 	return 0;
 }
 
-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
-	      uint32_t pull, uint32_t alternate, uint8_t status)
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+		     uint32_t speed, uint32_t pull, uint32_t od,
+		     uint32_t alternate, uint8_t status)
 {
 	uintptr_t base = stm32_get_gpio_bank_base(bank);
 	unsigned long clock = stm32_get_gpio_bank_clock(bank);
@@ -211,41 +233,42 @@
 
 	clk_enable(clock);
 
-	mmio_clrbits_32(base + GPIO_MODE_OFFSET,
-			((uint32_t)GPIO_MODE_MASK << (pin << 1)));
-	mmio_setbits_32(base + GPIO_MODE_OFFSET,
-			(mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
+	mmio_clrsetbits_32(base + GPIO_MODE_OFFSET,
+			   (uint32_t)GPIO_MODE_MASK << (pin << 1),
+			   mode << (pin << 1));
 
-	if ((mode & GPIO_OPEN_DRAIN) != 0U) {
-		mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
-	} else {
-		mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
-	}
+	mmio_clrsetbits_32(base + GPIO_TYPE_OFFSET,
+			   (uint32_t)GPIO_TYPE_MASK << pin,
+			   type << pin);
 
-	mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
-			((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
-	mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
+	mmio_clrsetbits_32(base + GPIO_SPEED_OFFSET,
+			   (uint32_t)GPIO_SPEED_MASK << (pin << 1),
+			   speed << (pin << 1));
 
-	mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
-			((uint32_t)GPIO_PULL_MASK << (pin << 1)));
-	mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
+	mmio_clrsetbits_32(base + GPIO_PUPD_OFFSET,
+			   (uint32_t)GPIO_PULL_MASK << (pin << 1),
+			   pull << (pin << 1));
 
 	if (pin < GPIO_ALT_LOWER_LIMIT) {
-		mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
-				((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
-		mmio_setbits_32(base + GPIO_AFRL_OFFSET,
-				alternate << (pin << 2));
+		mmio_clrsetbits_32(base + GPIO_AFRL_OFFSET,
+				   (uint32_t)GPIO_ALTERNATE_MASK << (pin << 2),
+				   alternate << (pin << 2));
 	} else {
-		mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
-				((uint32_t)GPIO_ALTERNATE_MASK <<
-				 ((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
-		mmio_setbits_32(base + GPIO_AFRH_OFFSET,
-				alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
-					      2));
+		size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
+
+		mmio_clrsetbits_32(base + GPIO_AFRH_OFFSET,
+				   (uint32_t)GPIO_ALTERNATE_MASK << shift,
+				   alternate << shift);
 	}
 
+	mmio_clrsetbits_32(base + GPIO_OD_OFFSET,
+			   (uint32_t)GPIO_OD_MASK << pin,
+			   od << pin);
+
 	VERBOSE("GPIO %u mode set to 0x%x\n", bank,
 		mmio_read_32(base + GPIO_MODE_OFFSET));
+	VERBOSE("GPIO %u type set to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_TYPE_OFFSET));
 	VERBOSE("GPIO %u speed set to 0x%x\n", bank,
 		mmio_read_32(base + GPIO_SPEED_OFFSET));
 	VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
@@ -254,16 +277,22 @@
 		mmio_read_32(base + GPIO_AFRL_OFFSET));
 	VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
 		mmio_read_32(base + GPIO_AFRH_OFFSET));
+	VERBOSE("GPIO %u output data set to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_OD_OFFSET));
 
 	clk_disable(clock);
 
 	if (status == DT_SECURE) {
 		stm32mp_register_secure_gpio(bank, pin);
+#if !IMAGE_BL2
 		set_gpio_secure_cfg(bank, pin, true);
+#endif
 
 	} else {
 		stm32mp_register_non_secure_gpio(bank, pin);
+#if !IMAGE_BL2
 		set_gpio_secure_cfg(bank, pin, false);
+#endif
 	}
 }
 
@@ -287,7 +316,8 @@
 
 void set_gpio_reset_cfg(uint32_t bank, uint32_t pin)
 {
-	set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_SPEED_LOW,
-		 GPIO_NO_PULL, GPIO_ALTERNATE_(0), DT_DISABLED);
+	set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_TYPE_PUSH_PULL,
+		 GPIO_SPEED_LOW, GPIO_NO_PULL, GPIO_OD_OUTPUT_LOW,
+		 GPIO_ALTERNATE_(0), DT_DISABLED);
 	set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank));
 }
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index edac46a..5c20932 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -726,7 +726,6 @@
 	       (ufs_params.desc_base != 0) &&
 	       (ufs_params.desc_size >= UFS_DESC_SIZE));
 
-	memset((void *)buf, 0, size);
 	get_utrd(&utrd);
 	ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
 	ufs_send_request(utrd.task_tag);
diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi
index ca93f0c..454e124 100644
--- a/fdts/stm32mp151.dtsi
+++ b/fdts/stm32mp151.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
- * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
  * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
  */
 #include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -19,9 +19,31 @@
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <0>;
+			nvmem-cells = <&part_number_otp>;
+			nvmem-cell-names = "part_number";
 		};
 	};
 
+	nvmem_layout: nvmem_layout@0 {
+		compatible = "st,stm32-nvmem-layout";
+
+		nvmem-cells = <&cfg0_otp>,
+			      <&part_number_otp>,
+			      <&monotonic_otp>,
+			      <&nand_otp>,
+			      <&uid_otp>,
+			      <&package_otp>,
+			      <&hw2_otp>;
+
+		nvmem-cell-names = "cfg0_otp",
+				   "part_number_otp",
+				   "monotonic_otp",
+				   "nand_otp",
+				   "uid_otp",
+				   "package_otp",
+				   "hw2_otp";
+	};
+
 	psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
@@ -457,12 +479,38 @@
 			reg = <0x5c005000 0x400>;
 			#address-cells = <1>;
 			#size-cells = <1>;
+
+			cfg0_otp: cfg0_otp@0 {
+				reg = <0x0 0x1>;
+			};
+			part_number_otp: part_number_otp@4 {
+				reg = <0x4 0x1>;
+			};
+			monotonic_otp: monotonic_otp@10 {
+				reg = <0x10 0x4>;
+			};
+			nand_otp: nand_otp@24 {
+				reg = <0x24 0x4>;
+			};
+			uid_otp: uid_otp@34 {
+				reg = <0x34 0xc>;
+			};
+			package_otp: package_otp@40 {
+				reg = <0x40 0x4>;
+			};
+			hw2_otp: hw2_otp@48 {
+				reg = <0x48 0x4>;
+			};
 			ts_cal1: calib@5c {
 				reg = <0x5c 0x2>;
 			};
 			ts_cal2: calib@5e {
 				reg = <0x5e 0x2>;
 			};
+			mac_addr: mac_addr@e4 {
+				reg = <0xe4 0x8>;
+				st,non-secure-otp;
+			};
 		};
 
 		etzpc: etzpc@5c007000 {
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
index 5c9818f..44c7016 100644
--- a/fdts/stm32mp157c-ed1.dts
+++ b/fdts/stm32mp157c-ed1.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
- * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
  * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
  */
 /dts-v1/;
@@ -33,8 +33,7 @@
 &bsec {
 	board_id: board_id@ec {
 		reg = <0xec 0x4>;
-		status = "okay";
-		secure-status = "okay";
+		st,non-secure-otp;
 	};
 };
 
@@ -196,6 +195,26 @@
 	status = "okay";
 };
 
+&nvmem_layout {
+	nvmem-cells = <&cfg0_otp>,
+		      <&part_number_otp>,
+		      <&monotonic_otp>,
+		      <&nand_otp>,
+		      <&uid_otp>,
+		      <&package_otp>,
+		      <&hw2_otp>,
+		      <&board_id>;
+
+	nvmem-cell-names = "cfg0_otp",
+			   "part_number_otp",
+			   "monotonic_otp",
+			   "nand_otp",
+			   "uid_otp",
+			   "package_otp",
+			   "hw2_otp",
+			   "board_id";
+};
+
 &pwr_regulators {
 	vdd-supply = <&vdd>;
 	vdd_3v3_usbfs-supply = <&vdd_usb>;
diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi
index 975d749..2eb3a57 100644
--- a/fdts/stm32mp15xx-dkx.dtsi
+++ b/fdts/stm32mp15xx-dkx.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
- * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
  * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
@@ -183,6 +183,26 @@
 	secure-status = "okay";
 };
 
+&nvmem_layout {
+	nvmem-cells = <&cfg0_otp>,
+		      <&part_number_otp>,
+		      <&monotonic_otp>,
+		      <&nand_otp>,
+		      <&uid_otp>,
+		      <&package_otp>,
+		      <&hw2_otp>,
+		      <&board_id>;
+
+	nvmem-cell-names = "cfg0_otp",
+			   "part_number_otp",
+			   "monotonic_otp",
+			   "nand_otp",
+			   "uid_otp",
+			   "package_otp",
+			   "hw2_otp",
+			   "board_id";
+};
+
 &pwr_regulators {
 	vdd-supply = <&vdd>;
 	vdd_3v3_usbfs-supply = <&vdd_usb>;
diff --git a/fdts/tc.dts b/fdts/tc.dts
index 6e119ce..7c0e842 100644
--- a/fdts/tc.dts
+++ b/fdts/tc.dts
@@ -17,7 +17,6 @@
 	};
 
 	chosen {
-		bootargs = "console=ttyAMA0 debug user_debug=31 earlycon=pl011,0x7ff80000 loglevel=9 androidboot.hardware=total_compute androidboot.boot_devices=1c050000.mmci ip=dhcp androidboot.selinux=permissive allow_mismatched_32bit_el0";
 		stdout-path = "serial0:115200n8";
 	};
 
@@ -207,6 +206,13 @@
 		#size-cells = <2>;
 		ranges;
 
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0x8000000>;
+			linux,cma-default;
+		};
+
 		optee@0xfce00000 {
 			reg = <0x00000000 0xfce00000 0 0x00200000>;
 			no-map;
@@ -435,6 +441,26 @@
 		clock-names = "mclk", "apb_pclk";
 	};
 
+	gpu: gpu@2d000000 {
+		compatible = "arm,mali-midgard";
+		reg = <0x0 0x2d000000 0x0 0x200000>;
+		interrupts = <0 66 4>, <0 67 4>, <0 65 4>;
+		interrupt-names = "JOB", "MMU", "GPU";
+		clocks = <&soc_refclk100mhz>;
+		clock-names = "clk_mali";
+		operating-points = <
+			/* KHz uV */
+			50000 820000
+		>;
+	};
+
+	smmu: smmu@2ce00000 {
+		#iommu-cells = <1>;
+		compatible = "arm,smmu-v3";
+		reg = <0x0 0x2ce00000 0x0 0x20000>;
+		status = "okay";
+	};
+
 	dp0: display@2cc00000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -444,6 +470,9 @@
 		interrupt-names = "DPU";
 		clocks = <&scmi_clk 0>;
 		clock-names = "aclk";
+		iommus = <&smmu 0>, <&smmu 1>, <&smmu 2>, <&smmu 3>,
+			<&smmu 4>, <&smmu 5>, <&smmu 6>, <&smmu 7>,
+			<&smmu 8>, <&smmu 9>;
 		pl0: pipeline@0 {
 			reg = <0>;
 			clocks = <&scmi_clk 1>;
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
index ebcb216..b960194 100644
--- a/include/drivers/arm/gicv2.h
+++ b/include/drivers/arm/gicv2.h
@@ -8,6 +8,7 @@
 #define GICV2_H
 
 #include <drivers/arm/gic_common.h>
+#include <platform_def.h>
 
 /*******************************************************************************
  * GICv2 miscellaneous definitions
@@ -30,7 +31,14 @@
 #define GICD_SGIR		U(0xF00)
 #define GICD_CPENDSGIR		U(0xF10)
 #define GICD_SPENDSGIR		U(0xF20)
+
+/*
+ * Some GICv2 implementations violate the specification and have this register
+ * at a different address. Allow overriding it in platform_def.h as workaround.
+ */
+#ifndef GICD_PIDR2_GICV2
 #define GICD_PIDR2_GICV2	U(0xFE8)
+#endif
 
 #define ITARGETSR_SHIFT		2
 #define GIC_TARGET_CPU_MASK	U(0xff)
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
index d833e7a..60dcf3c 100644
--- a/include/drivers/st/bsec.h
+++ b/include/drivers/st/bsec.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,13 +19,6 @@
 #define BSEC_OTP_BANK_SHIFT		5
 #define BSEC_TIMEOUT_VALUE		0xFFFF
 
-#define ADDR_LOWER_OTP_PERLOCK_SHIFT	0x03
-#define DATA_LOWER_OTP_PERLOCK_BIT	0x03U /* 2 significants bits are used */
-#define DATA_LOWER_OTP_PERLOCK_MASK	GENMASK(2, 0)
-#define ADDR_UPPER_OTP_PERLOCK_SHIFT	0x04
-#define DATA_UPPER_OTP_PERLOCK_BIT	0x01U /* 1 significants bits are used */
-#define DATA_UPPER_OTP_PERLOCK_MASK	GENMASK(3, 0)
-
 /*
  * Return status
  */
@@ -35,110 +28,34 @@
 #define BSEC_INVALID_PARAM		0xFFFFFFFCU
 #define BSEC_PROG_FAIL			0xFFFFFFFBU
 #define BSEC_LOCK_FAIL			0xFFFFFFFAU
-#define BSEC_WRITE_FAIL			0xFFFFFFF9U
-#define BSEC_SHADOW_FAIL		0xFFFFFFF8U
-#define BSEC_TIMEOUT			0xFFFFFFF7U
+#define BSEC_TIMEOUT			0xFFFFFFF9U
+#define BSEC_RETRY			0xFFFFFFF8U
+#define BSEC_NOT_SUPPORTED		0xFFFFFFF7U
+#define BSEC_WRITE_LOCKED		0xFFFFFFF6U
+#define BSEC_ERROR_INVALID_FVR		0xFFFFFFF5U
 
 /*
- * BSEC REGISTER OFFSET (base relative)
+ * OTP MODE
  */
-#define BSEC_OTP_CONF_OFF		0x000U
-#define BSEC_OTP_CTRL_OFF		0x004U
-#define BSEC_OTP_WRDATA_OFF		0x008U
-#define BSEC_OTP_STATUS_OFF		0x00CU
-#define BSEC_OTP_LOCK_OFF		0x010U
-#define BSEC_DEN_OFF			0x014U
-#define BSEC_DISTURBED_OFF		0x01CU
-#define BSEC_DISTURBED1_OFF		0x020U
-#define BSEC_DISTURBED2_OFF		0x024U
-#define BSEC_ERROR_OFF			0x034U
-#define BSEC_ERROR1_OFF			0x038U
-#define BSEC_ERROR2_OFF			0x03CU
-#define BSEC_WRLOCK_OFF			0x04CU /* Safmem permanent lock */
-#define BSEC_WRLOCK1_OFF		0x050U
-#define BSEC_WRLOCK2_OFF		0x054U
-#define BSEC_SPLOCK_OFF			0x064U /* Program safmem sticky lock */
-#define BSEC_SPLOCK1_OFF		0x068U
-#define BSEC_SPLOCK2_OFF		0x06CU
-#define BSEC_SWLOCK_OFF			0x07CU /* Write in OTP sticky lock */
-#define BSEC_SWLOCK1_OFF		0x080U
-#define BSEC_SWLOCK2_OFF		0x084U
-#define BSEC_SRLOCK_OFF			0x094U /* Shadowing sticky lock */
-#define BSEC_SRLOCK1_OFF		0x098U
-#define BSEC_SRLOCK2_OFF		0x09CU
-#define BSEC_JTAG_IN_OFF		0x0ACU
-#define BSEC_JTAG_OUT_OFF		0x0B0U
-#define BSEC_SCRATCH_OFF		0x0B4U
-#define BSEC_OTP_DATA_OFF		0x200U
-#define BSEC_IPHW_CFG_OFF		0xFF0U
-#define BSEC_IPVR_OFF			0xFF4U
-#define BSEC_IP_ID_OFF			0xFF8U
-#define BSEC_IP_MAGIC_ID_OFF		0xFFCU
+#define BSEC_MODE_OPEN1			0x00U
+#define BSEC_MODE_SECURED		0x01U
+#define BSEC_MODE_OPEN2			0x02U
+#define BSEC_MODE_INVALID		0x04U
 
 /*
- * BSEC_CONFIGURATION Register
- */
-#define BSEC_CONF_POWER_UP_MASK		BIT(0)
-#define BSEC_CONF_POWER_UP_SHIFT	0
-#define BSEC_CONF_FRQ_MASK		GENMASK(2, 1)
-#define BSEC_CONF_FRQ_SHIFT		1
-#define BSEC_CONF_PRG_WIDTH_MASK	GENMASK(6, 3)
-#define BSEC_CONF_PRG_WIDTH_SHIFT	3
-#define BSEC_CONF_TREAD_MASK		GENMASK(8, 7)
-#define BSEC_CONF_TREAD_SHIFT		7
-
-/*
- * BSEC_CONTROL Register
- */
-#define BSEC_READ			0x000U
-#define BSEC_WRITE			0x100U
-#define BSEC_LOCK			0x200U
-
-/*
- * BSEC_OTP_LOCK register
- */
-#define UPPER_OTP_LOCK_MASK		BIT(0)
-#define UPPER_OTP_LOCK_SHIFT		0
-#define DENREG_LOCK_MASK		BIT(2)
-#define DENREG_LOCK_SHIFT		2
-#define GPLOCK_LOCK_MASK		BIT(4)
-#define GPLOCK_LOCK_SHIFT		4
-
-/*
- * BSEC_OTP_STATUS Register
- */
-#define BSEC_MODE_STATUS_MASK		GENMASK(2, 0)
-#define BSEC_MODE_BUSY_MASK		BIT(3)
-#define BSEC_MODE_PROGFAIL_MASK		BIT(4)
-#define BSEC_MODE_PWR_MASK		BIT(5)
-#define BSEC_MODE_BIST1_LOCK_MASK	BIT(6)
-#define BSEC_MODE_BIST2_LOCK_MASK	BIT(7)
-
-/* OTP MODE*/
-#define BSEC_MODE_OPEN1			0x00
-#define BSEC_MODE_SECURED		0x01
-#define BSEC_MODE_OPEN2			0x02
-#define BSEC_MODE_INVALID		0x04
-
-/* BSEC_DENABLE Register */
-#define BSEC_HDPEN			BIT(4)
-#define BSEC_SPIDEN			BIT(5)
-#define BSEC_SPINDEN			BIT(6)
-#define BSEC_DBGSWGEN			BIT(10)
-#define BSEC_DEN_ALL_MSK		GENMASK(10, 0)
-
-/* BSEC_FENABLE Register */
-#define BSEC_FEN_ALL_MSK		GENMASK(14, 0)
-
-/*
- * OTP Lock services definition
- * Value must corresponding to the bit number in the register
+ * OTP Lock services definition.
+ * Value must corresponding to the bit number in the register.
+ * Special case: (bit number << 1) for BSEC3.
  */
 #define BSEC_LOCK_UPPER_OTP		0x00
+#define BSEC_LOCK_GWLOCK		0x01
 #define BSEC_LOCK_DEBUG			0x02
 #define BSEC_LOCK_PROGRAM		0x03
+#define BSEC_LOCK_KVLOCK		0x04
 
-/* Values for struct bsec_config::freq */
+/*
+ * Values for struct bsec_config::freq
+ */
 #define FREQ_10_20_MHZ			0x0
 #define FREQ_20_30_MHZ			0x1
 #define FREQ_30_45_MHZ			0x2
@@ -146,22 +63,28 @@
 
 /*
  * Device info structure, providing device-specific functions and a means of
- * adding driver-specific state
+ * adding driver-specific state.
  */
 struct bsec_config {
+	uint8_t den_lock;	/*
+				 * Debug enable sticky lock
+				 * 1 debug enable is locked until next reset
+				 */
+
+	/*  BSEC2 only */
 	uint8_t tread;		/* SAFMEM Reading current level default 0 */
 	uint8_t pulse_width;	/* SAFMEM Programming pulse width default 1 */
-	uint8_t freq;		/* SAFMEM CLOCK see freq value define
+	uint8_t freq;		/*
+				 * SAFMEM CLOCK see freq value define
 				 * default FREQ_45_67_MHZ
 				 */
 	uint8_t power;		/* Power up SAFMEM. 1 power up, 0 power off */
-	uint8_t prog_lock;	/* Programming Sticky lock
+	uint8_t prog_lock;	/*
+				 * Programming Sticky lock
 				 * 1 programming is locked until next reset
 				 */
-	uint8_t den_lock;	/* Debug enable sticky lock
-				 * 1 debug enable is locked until next reset
-				 */
-	uint8_t upper_otp_lock;	/* Shadowing of upper OTP sticky lock
+	uint8_t upper_otp_lock;	/*
+				 * Shadowing of upper OTP sticky lock
 				 * 1 shadowing of upper OTP is locked
 				 * until next reset
 				 */
@@ -179,10 +102,11 @@
 uint32_t bsec_program_otp(uint32_t val, uint32_t otp);
 uint32_t bsec_permanent_lock_otp(uint32_t otp);
 
-uint32_t bsec_write_debug_conf(uint32_t val);
+void bsec_write_debug_conf(uint32_t val);
 uint32_t bsec_read_debug_conf(void);
-uint32_t bsec_write_feature_conf(uint32_t val);
-uint32_t bsec_read_feature_conf(uint32_t *val);
+
+void bsec_write_scratch(uint32_t val);
+uint32_t bsec_read_scratch(void);
 
 uint32_t bsec_get_status(void);
 uint32_t bsec_get_hw_conf(void);
@@ -190,14 +114,14 @@
 uint32_t bsec_get_id(void);
 uint32_t bsec_get_magic_id(void);
 
-bool bsec_write_sr_lock(uint32_t otp, uint32_t value);
-bool bsec_read_sr_lock(uint32_t otp);
-bool bsec_write_sw_lock(uint32_t otp, uint32_t value);
-bool bsec_read_sw_lock(uint32_t otp);
-bool bsec_write_sp_lock(uint32_t otp, uint32_t value);
-bool bsec_read_sp_lock(uint32_t otp);
-bool bsec_wr_lock(uint32_t otp);
-uint32_t bsec_otp_lock(uint32_t service, uint32_t value);
+uint32_t bsec_set_sr_lock(uint32_t otp);
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sw_lock(uint32_t otp);
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sp_lock(uint32_t otp);
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value);
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value);
+uint32_t bsec_otp_lock(uint32_t service);
 
 uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
 uint32_t bsec_check_nsec_access_rights(uint32_t otp);
diff --git a/include/drivers/st/bsec2_reg.h b/include/drivers/st/bsec2_reg.h
new file mode 100644
index 0000000..f895020
--- /dev/null
+++ b/include/drivers/st/bsec2_reg.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC2_REG_H
+#define BSEC2_REG_H
+
+#include <lib/utils_def.h>
+
+/* IP configuration */
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT	0x03
+#define DATA_LOWER_OTP_PERLOCK_BIT	0x03U /* 2 significants bits are used */
+#define DATA_LOWER_OTP_PERLOCK_MASK	GENMASK(2, 0)
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT	0x04
+#define DATA_UPPER_OTP_PERLOCK_BIT	0x01U /* 1 significants bits are used */
+#define DATA_UPPER_OTP_PERLOCK_MASK	GENMASK(3, 0)
+
+/* BSEC REGISTER OFFSET (base relative) */
+#define BSEC_OTP_CONF_OFF		U(0x000)
+#define BSEC_OTP_CTRL_OFF		U(0x004)
+#define BSEC_OTP_WRDATA_OFF		U(0x008)
+#define BSEC_OTP_STATUS_OFF		U(0x00C)
+#define BSEC_OTP_LOCK_OFF		U(0x010)
+#define BSEC_DEN_OFF			U(0x014)
+#define BSEC_DISTURBED_OFF		U(0x01C)
+#define BSEC_DISTURBED1_OFF		U(0x020)
+#define BSEC_DISTURBED2_OFF		U(0x024)
+#define BSEC_ERROR_OFF			U(0x034)
+#define BSEC_ERROR1_OFF			U(0x038)
+#define BSEC_ERROR2_OFF			U(0x03C)
+#define BSEC_WRLOCK_OFF			U(0x04C) /* Safmem permanent lock */
+#define BSEC_WRLOCK1_OFF		U(0x050)
+#define BSEC_WRLOCK2_OFF		U(0x054)
+#define BSEC_SPLOCK_OFF			U(0x064) /* Program safmem sticky lock */
+#define BSEC_SPLOCK1_OFF		U(0x068)
+#define BSEC_SPLOCK2_OFF		U(0x06C)
+#define BSEC_SWLOCK_OFF			U(0x07C) /* Write in OTP sticky lock */
+#define BSEC_SWLOCK1_OFF		U(0x080)
+#define BSEC_SWLOCK2_OFF		U(0x084)
+#define BSEC_SRLOCK_OFF			U(0x094) /* Shadowing sticky lock */
+#define BSEC_SRLOCK1_OFF		U(0x098)
+#define BSEC_SRLOCK2_OFF		U(0x09C)
+#define BSEC_JTAG_IN_OFF		U(0x0AC)
+#define BSEC_JTAG_OUT_OFF		U(0x0B0)
+#define BSEC_SCRATCH_OFF		U(0x0B4)
+#define BSEC_OTP_DATA_OFF		U(0x200)
+#define BSEC_IPHW_CFG_OFF		U(0xFF0)
+#define BSEC_IPVR_OFF			U(0xFF4)
+#define BSEC_IP_ID_OFF			U(0xFF8)
+#define BSEC_IP_MAGIC_ID_OFF		U(0xFFC)
+
+#define BSEC_WRLOCK(n)			(BSEC_WRLOCK_OFF + U(0x04) * (n))
+#define BSEC_SPLOCK(n)			(BSEC_SPLOCK_OFF + U(0x04) * (n))
+#define BSEC_SWLOCK(n)			(BSEC_SWLOCK_OFF + U(0x04) * (n))
+#define BSEC_SRLOCK(n)			(BSEC_SRLOCK_OFF + U(0x04) * (n))
+
+/* BSEC_CONFIGURATION Register */
+#define BSEC_CONF_POWER_UP_MASK		BIT(0)
+#define BSEC_CONF_POWER_UP_SHIFT	0
+#define BSEC_CONF_FRQ_MASK		GENMASK(2, 1)
+#define BSEC_CONF_FRQ_SHIFT		1
+#define BSEC_CONF_PRG_WIDTH_MASK	GENMASK(6, 3)
+#define BSEC_CONF_PRG_WIDTH_SHIFT	3
+#define BSEC_CONF_TREAD_MASK		GENMASK(8, 7)
+#define BSEC_CONF_TREAD_SHIFT		7
+
+/* BSEC_CONTROL Register */
+#define BSEC_READ			0U
+#define BSEC_WRITE			BIT(8)
+#define BSEC_LOCK			BIT(9)
+
+/* BSEC_OTP_LOCK register */
+#define UPPER_OTP_LOCK_MASK		BIT(0)
+#define UPPER_OTP_LOCK_SHIFT		0
+#define DENREG_LOCK_MASK		BIT(2)
+#define DENREG_LOCK_SHIFT		2
+#define GPLOCK_LOCK_MASK		BIT(4)
+#define GPLOCK_LOCK_SHIFT		4
+
+/* BSEC_OTP_STATUS Register */
+#define BSEC_MODE_STATUS_MASK		GENMASK(2, 0)
+#define BSEC_MODE_SECURE_MASK		BIT(0)
+#define BSEC_MODE_FULLDBG_MASK		BIT(1)
+#define BSEC_MODE_INVALID_MASK		BIT(2)
+#define BSEC_MODE_BUSY_MASK		BIT(3)
+#define BSEC_MODE_PROGFAIL_MASK		BIT(4)
+#define BSEC_MODE_PWR_MASK		BIT(5)
+#define BSEC_MODE_BIST1_LOCK_MASK	BIT(6)
+#define BSEC_MODE_BIST2_LOCK_MASK	BIT(7)
+
+/* BSEC_DENABLE Register */
+#define BSEC_HDPEN			BIT(4)
+#define BSEC_SPIDEN			BIT(5)
+#define BSEC_SPINDEN			BIT(6)
+#define BSEC_DBGSWGEN			BIT(10)
+#define BSEC_DEN_ALL_MSK		GENMASK(10, 0)
+
+/* BSEC_FENABLE Register */
+#define BSEC_FEN_ALL_MSK		GENMASK(14, 0)
+
+/* BSEC_IPVR Register */
+#define BSEC_IPVR_MSK			GENMASK(7, 0)
+
+#endif /* BSEC2_REG_H */
diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h
index b072345..eeef9da 100644
--- a/include/drivers/st/stm32_gpio.h
+++ b/include/drivers/st/stm32_gpio.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2015-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,7 @@
 #define GPIO_TYPE_OFFSET	U(0x04)
 #define GPIO_SPEED_OFFSET	U(0x08)
 #define GPIO_PUPD_OFFSET	U(0x0C)
+#define GPIO_OD_OFFSET		U(0x14)
 #define GPIO_BSRR_OFFSET	U(0x18)
 #define GPIO_AFRL_OFFSET	U(0x20)
 #define GPIO_AFRH_OFFSET	U(0x24)
@@ -26,31 +27,35 @@
 #define GPIO_ALTERNATE_(_x)	U(_x)
 #define GPIO_ALTERNATE_MASK	U(0x0F)
 
-#define GPIO_MODE_INPUT		0x00
-#define GPIO_MODE_OUTPUT	0x01
-#define GPIO_MODE_ALTERNATE	0x02
-#define GPIO_MODE_ANALOG	0x03
+#define GPIO_MODE_INPUT		U(0x00)
+#define GPIO_MODE_OUTPUT	U(0x01)
+#define GPIO_MODE_ALTERNATE	U(0x02)
+#define GPIO_MODE_ANALOG	U(0x03)
 #define GPIO_MODE_MASK		U(0x03)
 
-#define GPIO_OPEN_DRAIN		U(0x10)
+#define GPIO_TYPE_PUSH_PULL	U(0x00)
+#define GPIO_TYPE_OPEN_DRAIN	U(0x01)
+#define GPIO_TYPE_MASK		U(0x01)
 
-#define GPIO_SPEED_LOW		0x00
-#define GPIO_SPEED_MEDIUM	0x01
-#define GPIO_SPEED_HIGH		0x02
-#define GPIO_SPEED_VERY_HIGH	0x03
+#define GPIO_SPEED_LOW		U(0x00)
+#define GPIO_SPEED_MEDIUM	U(0x01)
+#define GPIO_SPEED_HIGH		U(0x02)
+#define GPIO_SPEED_VERY_HIGH	U(0x03)
 #define GPIO_SPEED_MASK		U(0x03)
 
-#define GPIO_NO_PULL		0x00
-#define GPIO_PULL_UP		0x01
-#define GPIO_PULL_DOWN		0x02
+#define GPIO_NO_PULL		U(0x00)
+#define GPIO_PULL_UP		U(0x01)
+#define GPIO_PULL_DOWN		U(0x02)
 #define GPIO_PULL_MASK		U(0x03)
 
+#define GPIO_OD_OUTPUT_LOW	U(0x00)
+#define GPIO_OD_OUTPUT_HIGH	U(0x01)
+#define GPIO_OD_MASK		U(0x01)
+
 #ifndef __ASSEMBLER__
 #include <stdint.h>
 
 int dt_set_pinctrl_config(int node);
-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
-	      uint32_t pull, uint32_t alternate, uint8_t status);
 void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure);
 void set_gpio_reset_cfg(uint32_t bank, uint32_t pin);
 #endif /*__ASSEMBLER__*/
diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h
index 9df38d6..61286b2 100644
--- a/include/drivers/st/stm32mp_clkfunc.h
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -23,7 +23,7 @@
 			      uint32_t *array);
 int fdt_rcc_subnode_offset(const char *name);
 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp);
-bool fdt_get_rcc_secure_status(void);
+bool fdt_get_rcc_secure_state(void);
 
 int fdt_get_clock_id(int node);
 unsigned long fdt_get_uart_clock_freq(uintptr_t instance);
diff --git a/plat/arm/board/rdn2/include/platform_def.h b/plat/arm/board/rdn2/include/platform_def.h
index 194814f..e4015f7 100644
--- a/plat/arm/board/rdn2/include/platform_def.h
+++ b/plat/arm/board/rdn2/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,8 @@
 
 #if (CSS_SGI_PLATFORM_VARIANT == 1)
 #define PLAT_ARM_CLUSTER_COUNT		U(8)
+#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#define PLAT_ARM_CLUSTER_COUNT		U(4)
 #else
 #define PLAT_ARM_CLUSTER_COUNT		U(16)
 #endif
@@ -34,6 +36,8 @@
 
 #if (CSS_SGI_PLATFORM_VARIANT == 1)
 #define TZC400_COUNT			U(2)
+#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#define TZC400_COUNT			U(4)
 #else
 #define TZC400_COUNT			U(8)
 #endif
@@ -64,8 +68,15 @@
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#define PLAT_PHY_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+						CSS_SGI_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+						CSS_SGI_CHIP_COUNT)
+#else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 42)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 42)
+#endif
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
@@ -75,6 +86,9 @@
 #define PLAT_ARM_GICD_BASE		UL(0x30000000)
 #define PLAT_ARM_GICC_BASE		UL(0x2C000000)
 
+/* Virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xC0000000)
+
 #if (CSS_SGI_PLATFORM_VARIANT == 1)
 #define PLAT_ARM_GICR_BASE		UL(0x30100000)
 #else
diff --git a/plat/arm/board/rdn2/platform.mk b/plat/arm/board/rdn2/platform.mk
index 5b24c32..753ba32 100644
--- a/plat/arm/board/rdn2/platform.mk
+++ b/plat/arm/board/rdn2/platform.mk
@@ -3,9 +3,27 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+RD_N2_VARIANTS	:= 0 1 2
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),\
+	$(filter $(CSS_SGI_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-N2 should be 0, 1 or 2, currently set \
+     to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
+
+$(eval $(call CREATE_SEQ,SEQ,4))
+ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ $(error  "Chip count for RD-N2-MC should be either $(SEQ) \
+ currently it is set to ${CSS_SGI_CHIP_COUNT}.")
+endif
+
 # RD-N2 platform uses GIC-700 which is based on GICv4.1
 GIC_ENABLE_V4_EXTN	:=	1
 
+#Enable GIC Multichip Extension only for Multichip Platforms
+ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+GICV3_IMPL_GIC600_MULTICHIP	:=	1
+endif
+
 include plat/arm/css/sgi/sgi-common.mk
 
 RDN2_BASE		=	plat/arm/board/rdn2
@@ -39,6 +57,13 @@
 BL2_SOURCES		+=	${RDN2_BASE}/rdn2_trusted_boot.c
 endif
 
+ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+BL31_SOURCES	+=	drivers/arm/gic/v3/gic600_multichip.c
+
+# Enable dynamic addition of MMAP regions in BL31
+BL31_CFLAGS		+=	-DPLAT_XLAT_TABLES_DYNAMIC
+endif
+
 # Add the FDT_SOURCES and options for Dynamic Config
 FDT_SOURCES		+=	${RDN2_BASE}/fdts/${PLAT}_fw_config.dts	\
 				${RDN2_BASE}/fdts/${PLAT}_tb_fw_config.dts
@@ -58,10 +83,3 @@
 
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 override ENABLE_AMU			:= 1
-
-RD_N2_VARIANTS	:= 0 1
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),\
-	$(filter $(CSS_SGI_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-N2 should be 0 or 1, currently set \
-     to ${CSS_SGI_PLATFORM_VARIANT}.")
-endif
diff --git a/plat/arm/board/rdn2/rdn2_plat.c b/plat/arm/board/rdn2/rdn2_plat.c
index 5bf14e3..8cf1929 100644
--- a/plat/arm/board/rdn2/rdn2_plat.c
+++ b/plat/arm/board/rdn2/rdn2_plat.c
@@ -1,12 +1,87 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <common/debug.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
+#include <sgi_soc_platform_def_v2.h>
 #include <sgi_plat.h>
 
+#if defined(IMAGE_BL31)
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static const mmap_region_t rdn2mc_dynamic_mmap[] = {
+#if CSS_SGI_CHIP_COUNT > 1
+	ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+	ARM_MAP_SHARED_RAM_REMOTE_CHIP(2),
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	ARM_MAP_SHARED_RAM_REMOTE_CHIP(3),
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+};
+#endif
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static struct gic600_multichip_data rdn2mc_multichip_data __init = {
+	.rt_owner_base = PLAT_ARM_GICD_BASE,
+	.rt_owner = 0,
+	.chip_count = CSS_SGI_CHIP_COUNT,
+	.chip_addrs = {
+		PLAT_ARM_GICD_BASE >> 16,
+#if CSS_SGI_CHIP_COUNT > 1
+		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+#endif
+	},
+	.spi_ids = {
+		{32, 479},
+	#if CSS_SGI_CHIP_COUNT > 1
+		{0, 0},
+	#endif
+	#if CSS_SGI_CHIP_COUNT > 2
+		{0, 0},
+	#endif
+	#if CSS_SGI_CHIP_COUNT > 3
+		{0, 0},
+	#endif
+	}
+};
+#endif
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static uintptr_t rdn2mc_multichip_gicr_frames[] = {
+	/* Chip 0's GICR Base */
+	PLAT_ARM_GICR_BASE,
+#if CSS_SGI_CHIP_COUNT > 1
+	/* Chip 1's GICR BASE */
+	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+	/* Chip 2's GICR BASE */
+	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	/* Chip 3's GICR BASE */
+	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+	UL(0)	/* Zero Termination */
+};
+#endif
+#endif /* IMAGE_BL31 */
+
 unsigned int plat_arm_sgi_get_platform_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
@@ -25,7 +100,39 @@
 			     SID_MULTI_CHIP_MODE_SHIFT;
 }
 
+#if defined(IMAGE_BL31)
 void bl31_platform_setup(void)
 {
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+	int ret;
+	unsigned int i;
+
+	if (plat_arm_sgi_get_multi_chip_mode() == 0) {
+		ERROR("Chip Count is set to %u but multi-chip mode is not "
+			"enabled\n", CSS_SGI_CHIP_COUNT);
+		panic();
+	} else {
+		INFO("Enabling multi-chip support for RD-N2 variant\n");
+
+		for (i = 0; i < ARRAY_SIZE(rdn2mc_dynamic_mmap); i++) {
+			ret = mmap_add_dynamic_region(
+					rdn2mc_dynamic_mmap[i].base_pa,
+					rdn2mc_dynamic_mmap[i].base_va,
+					rdn2mc_dynamic_mmap[i].size,
+					rdn2mc_dynamic_mmap[i].attr);
+			if (ret != 0) {
+				ERROR("Failed to add dynamic mmap entry for"
+					" i: %d " "(ret=%d)\n", i, ret);
+				panic();
+			}
+		}
+
+		plat_arm_override_gicr_frames(
+			rdn2mc_multichip_gicr_frames);
+		gic600_multichip_init(&rdn2mc_multichip_data);
+	}
+#endif
+
 	sgi_bl31_common_platform_setup();
 }
+#endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn2/rdn2_security.c b/plat/arm/board/rdn2/rdn2_security.c
index 9568b60..dff6a19 100644
--- a/plat/arm/board/rdn2/rdn2_security.c
+++ b/plat/arm/board/rdn2/rdn2_security.c
@@ -1,25 +1,63 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <common/debug.h>
 #include <plat/arm/common/plat_arm.h>
 #include <platform_def.h>
 
-
 static const arm_tzc_regions_info_t tzc_regions[] = {
 	ARM_TZC_REGIONS_DEF,
 	{}
 };
 
+#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
+static const arm_tzc_regions_info_t tzc_regions_mc[][CSS_SGI_CHIP_COUNT - 1] = {
+	{
+		/* TZC memory regions for second chip */
+		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
+		{}
+	},
+#if CSS_SGI_CHIP_COUNT > 2
+	{
+		/* TZC memory regions for third chip */
+		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
+		{}
+	},
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	{
+		/* TZC memory regions for fourth chip */
+		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
+		{}
+	},
+#endif
+};
+#endif /* CSS_SGI_PLATFORM_VARIANT && CSS_SGI_CHIP_COUNT */
+
 /* Initialize the secure environment */
 void plat_arm_security_setup(void)
 {
+	unsigned int i;
 
-	int i;
+	INFO("Configuring TrustZone Controller for Chip 0\n");
 
-	for (i = 0; i < TZC400_COUNT; i++)
+	for (i = 0; i < TZC400_COUNT; i++) {
 		arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+	}
 
+#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
+	unsigned int j;
+
+	for (i = 1; i < CSS_SGI_CHIP_COUNT; i++) {
+		INFO("Configuring TrustZone Controller for Chip %u\n", i);
+
+		for (j = 0; j < TZC400_COUNT; j++) {
+			arm_tzc400_setup(CSS_SGI_REMOTE_CHIP_MEM_OFFSET(i)
+				+ TZC400_BASE(j), tzc_regions_mc[i-1]);
+		}
+	}
+#endif
 }
diff --git a/plat/arm/board/rdn2/rdn2_topology.c b/plat/arm/board/rdn2/rdn2_topology.c
index cad6c37..89300f8 100644
--- a/plat/arm/board/rdn2/rdn2_topology.c
+++ b/plat/arm/board/rdn2/rdn2_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,20 +11,24 @@
  * The power domain tree descriptor.
  ******************************************************************************/
 const unsigned char rd_n2_pd_tree_desc[] = {
-	PLAT_ARM_CLUSTER_COUNT,
+	(PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_PLATFORM_VARIANT != 2 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1))
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-#if (CSS_SGI_PLATFORM_VARIANT == 0)
+#endif
+#if (CSS_SGI_PLATFORM_VARIANT == 0 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 2))
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+#if (CSS_SGI_PLATFORM_VARIANT == 0 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 3))
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
@@ -44,6 +48,32 @@
  * The array mapping platform core position (implemented by plat_my_core_pos())
  * to the SCMI power domain ID implemented by SCP.
  ******************************************************************************/
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+#if (CSS_SGI_CHIP_COUNT > 1)
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 2)
+	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+};
+#else
 const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
@@ -64,3 +94,4 @@
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xF)),
 #endif
 };
+#endif
diff --git a/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h b/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
index bebc597..639b687 100644
--- a/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
+++ b/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
@@ -92,6 +92,12 @@
 						SOC_MEMCNTRL_SIZE,		\
 						MT_DEVICE | MT_RW | MT_SECURE)
 
+#define SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(n)					\
+		MAP_REGION_FLAT(						\
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + SOC_MEMCNTRL_BASE,	\
+			SOC_MEMCNTRL_SIZE,					\
+			MT_DEVICE | MT_RW | MT_SECURE)
+
 /*
  * The bootsec_bridge controls access to a bunch of peripherals, e.g. the UARTs.
  */
diff --git a/plat/arm/css/sgi/sgi_plat_v2.c b/plat/arm/css/sgi/sgi_plat_v2.c
index 131cdf2..1a2a966 100644
--- a/plat/arm/css/sgi/sgi_plat_v2.c
+++ b/plat/arm/css/sgi/sgi_plat_v2.c
@@ -42,6 +42,15 @@
 	SOC_PLATFORM_PERIPH_MAP_DEVICE,
 	SOC_SYSTEM_PERIPH_MAP_DEVICE,
 	ARM_MAP_NS_DRAM1,
+#if CSS_SGI_CHIP_COUNT > 1
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
 #if ARM_BL31_IN_DRAM
 	ARM_MAP_BL31_SEC_DRAM,
 #endif
diff --git a/plat/qti/msm8916/aarch64/msm8916_helpers.S b/plat/qti/msm8916/aarch64/msm8916_helpers.S
new file mode 100644
index 0000000..dad9968
--- /dev/null
+++ b/plat/qti/msm8916/aarch64/msm8916_helpers.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <msm8916_mmap.h>
+
+#define APCS_TCM_START_ADDR	0x10
+#define APCS_TCM_REDIRECT_EN_0	BIT_32(0)
+
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_panic_handler
+	.globl	plat_my_core_pos
+	.globl	plat_get_my_entrypoint
+	.globl	plat_reset_handler
+	.globl	platform_mem_init
+	.globl	msm8916_entry_point
+
+	/* -------------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Initialize the crash console.
+	 * Out: x0 - 1 on success, 0 on error
+	 * Clobber list : x0 - x4
+	 * -------------------------------------------------
+	 */
+func plat_crash_console_init
+	mov	x1, #BLSP_UART2_BASE
+
+	/*
+	 * If the non-secure world has been actively using the UART there might
+	 * be still some characters left to be sent in the FIFO. In that case,
+	 * resetting the transmitter too early might cause all output to become
+	 * corrupted. To avoid that, try to flush (wait until FIFO empty) first.
+	 */
+	mov	x4, lr
+	bl	console_uartdm_core_flush
+	mov	lr, x4
+
+	mov	x0, #1
+	b	console_uartdm_core_init
+endfunc plat_crash_console_init
+
+	/* -------------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Print a character on the crash console.
+	 * In : w0 - character to be printed
+	 * Out: w0 - printed character on success
+	 * Clobber list : x1, x2
+	 * -------------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov	x1, #BLSP_UART2_BASE
+	b	console_uartdm_core_putc
+endfunc plat_crash_console_putc
+
+	/* -------------------------------------------------
+	 * void plat_crash_console_flush(void)
+	 * Force a write of all buffered data that has not
+	 * been output.
+	 * Clobber list : x1, x2
+	 * -------------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov	x1, #BLSP_UART2_BASE
+	b	console_uartdm_core_flush
+endfunc plat_crash_console_flush
+
+	/* -------------------------------------------------
+	 * void plat_panic_handler(void) __dead
+	 * Called when an unrecoverable error occurs.
+	 * -------------------------------------------------
+	 */
+func plat_panic_handler
+	/* Try to shutdown/reset */
+	mov_imm	x0, MPM_PS_HOLD
+	str	wzr, [x0]
+1:	b	1b
+endfunc plat_panic_handler
+
+	/* -------------------------------------------------
+	 * unsigned int plat_my_core_pos(void)
+	 * Out: x0 - index of the calling CPU
+	 * -------------------------------------------------
+	 */
+func plat_my_core_pos
+	/* There is just a single cluster so this is very simple */
+	mrs	x0, mpidr_el1
+	and	x0, x0, #MPIDR_CPU_MASK
+	ret
+endfunc plat_my_core_pos
+
+	/* -------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint(void)
+	 * Distinguish cold and warm boot and return warm boot
+	 * entry address if available.
+	 * Out: x0 - warm boot entry point or 0 on cold boot
+	 * -------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	ldr	x0, msm8916_entry_point
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* -------------------------------------------------
+	 * void plat_reset_handler(void)
+	 * Perform additional initialization after reset.
+	 * Clobber list : x0 - x18, x30
+	 * -------------------------------------------------
+	 */
+func plat_reset_handler
+	/*
+	 * Check if the CPU is running at the correct address.
+	 * During cold boot the CPU enters here at the wrong address
+	 * using the "boot remapper". (It remaps the BL31_BASE to
+	 * the CPU reset address 0x0).
+	 */
+	mov	x0, #BL31_BASE
+	adr	x1, bl31_entrypoint
+	cmp	x0, x1
+	b.ne	_remapped_cold_boot
+	/* Already running at correct address, just return directly */
+	ret
+
+_remapped_cold_boot:
+	/*
+	 * The previous boot stage seems to use the L2 cache as TCM.
+	 * Disable the TCM redirect before enabling caches to avoid
+	 * strange crashes.
+	 */
+	mov	x2, #APCS_CFG
+	ldr	w3, [x2, #APCS_TCM_START_ADDR]
+	and	w3, w3, #~APCS_TCM_REDIRECT_EN_0
+	str	w3, [x2, #APCS_TCM_START_ADDR]
+
+	/* Enter BL31 again at the real address */
+	br	x0
+endfunc plat_reset_handler
+
+	/* -------------------------------------------------
+	 * void platform_mem_init(void)
+	 * Performs additional memory initialization early
+	 * in the boot process.
+	 * -------------------------------------------------
+	 */
+func platform_mem_init
+	/* Nothing to do here, all memory is already initialized */
+	ret
+endfunc platform_mem_init
+
+	.data
+	.align	3
+
+	/* -------------------------------------------------
+	 * Warm boot entry point for CPU. Set by PSCI code.
+	 * -------------------------------------------------
+	 */
+msm8916_entry_point:
+	.quad	0
diff --git a/plat/qti/msm8916/aarch64/uartdm_console.S b/plat/qti/msm8916/aarch64/uartdm_console.S
new file mode 100644
index 0000000..c69c193
--- /dev/null
+++ b/plat/qti/msm8916/aarch64/uartdm_console.S
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * Based on aarch64/skeleton_console.S:
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <console_macros.S>
+
+/* UART DM registers */
+#define UART_DM_DMEN		0x03c		/* DMA / data packing */
+#define UART_DM_SR		0x0a4		/* status register */
+#define UART_DM_CR		0x0a8		/* command register */
+#define UART_DM_TF		0x100		/* transmit FIFO */
+
+#define UART_DM_DMEN_TX_SC	BIT_32(4)	/* TX single character mode */
+
+#define UART_DM_SR_TXRDY_BIT	2		/* TX FIFO has space */
+#define UART_DM_SR_TXEMT_BIT	3		/* TX FIFO is empty */
+
+#define UART_DM_CR_RESET_RX	(U(0x01) << 4)	/* reset receiver */
+#define UART_DM_CR_RESET_TX	(U(0x02) << 4)	/* reset transmitter */
+#define UART_DM_CR_TX_ENABLE	BIT_32(2)	/* enable transmitter */
+
+	.globl	console_uartdm_register
+	.globl	console_uartdm_core_init
+	.globl	console_uartdm_putc
+	.globl	console_uartdm_core_putc
+	.globl	console_uartdm_flush
+	.globl	console_uartdm_core_flush
+
+	/* -----------------------------------------------------------
+	 * int console_uartdm_register(console_t *console,
+	 * 	uintptr_t base_addr)
+	 * Function to initialize and register the console. The caller
+	 * needs to pass an empty console_t structure in which *MUST*
+	 * be allocated in persistent memory (e.g. a global or static
+	 * local variable, *NOT* on the stack).
+	 * In : x0 - pointer to empty console_t structure
+	 *      x1 - base address
+	 * Out: x0 - 1 on success, 0 on error
+	 * Clobber list : x0 - x7
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_register
+	str	x1, [x0, #CONSOLE_T_BASE]
+	mov	x7, lr
+	bl	console_uartdm_core_init
+	mov	lr, x7
+
+	/* Register the new console */
+	finish_console_register uartdm putc=1, flush=1
+endfunc console_uartdm_register
+
+	/* -----------------------------------------------------------
+	 * void console_uartdm_core_init(unused, uintptr_t base_addr)
+	 * Function to initialize the console.
+	 * In : x0 - unused
+	 *      x1 - base address
+	 * Out: void
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_core_init
+	/* Reset receiver */
+	mov	w3, #UART_DM_CR_RESET_RX
+	str	w3, [x1, #UART_DM_CR]
+
+	/* Reset transmitter */
+	mov	w3, #UART_DM_CR_RESET_TX
+	str	w3, [x1, #UART_DM_CR]
+
+	/*
+	 * Disable BAM/DMA modes but enable single-character mode for TX.
+	 * The single character mode allows simplifying the putc implementation
+	 * since characters can be written directly to the FIFO instead of
+	 * having to initiate a new transfer and waiting for its completion.
+	 */
+	mov	w3, #UART_DM_DMEN_TX_SC
+	str	w3, [x1, #UART_DM_DMEN]
+
+	/* Enable transmitter */
+	mov	w3, #UART_DM_CR_TX_ENABLE
+	str	w3, [x1, #UART_DM_CR]
+
+	ret
+endfunc console_uartdm_core_init
+
+	/* -----------------------------------------------------------
+	 * int console_uartdm_putc(int c, console_t *console)
+	 * Function to output a character over the console.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t struct
+	 * Out: w0 - printed character on success, < 0 on error.
+	 * Clobber list : x0, x1, x2
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_putc
+	ldr	x1, [x1, #CONSOLE_T_BASE]
+	b	console_uartdm_core_putc
+endfunc console_uartdm_putc
+
+	/* -----------------------------------------------------------
+	 * int console_uartdm_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console.
+	 * In : w0 - character to be printed
+	 *      x1 - base address
+	 * Out: w0 - printed character on success, < 0 on error.
+	 * Clobber list : x2
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_core_putc
+1:	/* Loop until TX FIFO has space */
+	ldr	w2, [x1, #UART_DM_SR]
+	tbz	w2, #UART_DM_SR_TXRDY_BIT, 1b
+
+	/* Write character to FIFO */
+	str	w0, [x1, #UART_DM_TF]
+	ret
+endfunc console_uartdm_core_putc
+
+	/* -----------------------------------------------------------
+	 * void console_uartdm_flush(console_t *console)
+	 * Function to force a write of all buffered data
+	 * that has not been output.
+	 * In : x0 - pointer to console_t struct
+	 * Out: void
+	 * Clobber list : x0, x1, x2, x3, x4, x5
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_flush
+	ldr	x1, [x0, #CONSOLE_T_BASE]
+	b	console_uartdm_core_flush
+endfunc console_uartdm_flush
+
+	/* -----------------------------------------------------------
+	 * void console_uartdm_core_flush(unused, uintptr_t base_addr)
+	 * Function to force a write of all buffered data
+	 * that has not been output.
+	 * In : x0 - unused
+	 *      x1 - base address
+	 * Out: void
+	 * Clobber list : x2
+	 * -----------------------------------------------------------
+	 */
+func console_uartdm_core_flush
+1:	/* Loop until TX FIFO is empty */
+	ldr	w2, [x1, #UART_DM_SR]
+	tbz	w2, #UART_DM_SR_TXEMT_BIT, 1b
+	ret
+endfunc console_uartdm_core_flush
diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h
new file mode 100644
index 0000000..406ae6b
--- /dev/null
+++ b/plat/qti/msm8916/include/msm8916_mmap.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_MMAP_H
+#define MSM8916_MMAP_H
+
+#define PCNOC_BASE		0x00000000
+#define PCNOC_SIZE		0x8000000	/* 128 MiB */
+#define APCS_BASE		0x0b000000
+#define APCS_SIZE		0x800000	/* 8 MiB */
+
+#define MPM_BASE		(PCNOC_BASE + 0x04a0000)
+#define MPM_PS_HOLD		(MPM_BASE + 0xb000)
+
+#define TLMM_BASE		(PCNOC_BASE + 0x1000000)
+#define TLMM_GPIO_CFG(n)	(TLMM_BASE + ((n) * 0x1000))
+
+#define GCC_BASE		(PCNOC_BASE + 0x1800000)
+
+#define APPS_SMMU_BASE		(PCNOC_BASE + 0x1e00000)
+#define APPS_SMMU_QCOM		(APPS_SMMU_BASE + 0xf0000)
+
+#define BLSP_UART1_BASE		(PCNOC_BASE + 0x78af000)
+#define BLSP_UART2_BASE		(PCNOC_BASE + 0x78b0000)
+
+#define APCS_QGIC2_BASE		(APCS_BASE + 0x00000)
+#define APCS_QGIC2_GICD		(APCS_QGIC2_BASE + 0x0000)
+#define APCS_QGIC2_GICC		(APCS_QGIC2_BASE + 0x2000)
+#define APCS_BANKED_ACS		(APCS_BASE + 0x08000)
+#define APCS_BANKED_SAW2	(APCS_BASE + 0x09000)
+#define APCS_CFG		(APCS_BASE + 0x10000)
+#define APCS_GLB		(APCS_BASE + 0x11000)
+#define APCS_L2_SAW2		(APCS_BASE + 0x12000)
+#define APCS_QTMR		(APCS_BASE + 0x20000)
+#define APCS_ALIAS_ACS(cpu)	(APCS_BASE + 0x88000 + ((cpu) * 0x10000))
+#define APCS_ALIAS_SAW2(cpu)	(APCS_BASE + 0x89000 + ((cpu) * 0x10000))
+
+#endif /* MSM8916_MMAP_H */
diff --git a/plat/qti/msm8916/include/plat_macros.S b/plat/qti/msm8916/include/plat_macros.S
new file mode 100644
index 0000000..552add2
--- /dev/null
+++ b/plat/qti/msm8916/include/plat_macros.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+
+#include <msm8916_mmap.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC registers whenever
+	 * an unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm	x16, APCS_QGIC2_GICD
+	mov_imm	x17, APCS_QGIC2_GICC
+	arm_print_gic_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/qti/msm8916/include/platform_def.h b/plat/qti/msm8916/include/platform_def.h
new file mode 100644
index 0000000..bfade70
--- /dev/null
+++ b/plat/qti/msm8916/include/platform_def.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat/common/common_def.h>
+
+/*
+ * There is at least 1 MiB available for BL31. However, at the moment the
+ * "msm8916_entry_point" variable in the data section is read through the
+ * 64 KiB region of the "boot remapper" after reset. For simplicity, limit
+ * the end of the data section (BL31_PROGBITS_LIMIT) to 64 KiB for now and
+ * the overall limit to 128 KiB. This could be increased if needed by placing
+ * the "msm8916_entry_point" variable explicitly in the first 64 KiB of BL31.
+ */
+#define BL31_LIMIT			(BL31_BASE + 0x20000)	/* 128 KiB */
+#define BL31_PROGBITS_LIMIT		(BL31_BASE + 0x10000)	/* 64 KiB */
+
+#define CACHE_WRITEBACK_GRANULE		U(64)
+#define PLATFORM_STACK_SIZE		U(0x1000)
+
+/* CPU topology: single cluster with 4 cores */
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_MAX_CPUS_PER_CLUSTER)
+
+/* Power management */
+#define PLATFORM_SYSTEM_COUNT		U(1)
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_SYSTEM_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLAT_MAX_RET_STATE		U(2)
+#define PLAT_MAX_OFF_STATE		U(3)
+
+/* Translation tables */
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			4
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+/* Timer frequency */
+#define PLAT_SYSCNT_FREQ		19200000
+
+/*
+ * The Qualcomm QGIC2 implementation seems to have PIDR0-4 and PIDR4-7
+ * erroneously swapped for some reason. PIDR2 is actually at 0xFD8.
+ * Override the address in <drivers/arm/gicv2.h> to avoid a failing assert().
+ */
+#define GICD_PIDR2_GICV2		U(0xFD8)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/msm8916/include/uartdm_console.h b/plat/qti/msm8916/include/uartdm_console.h
new file mode 100644
index 0000000..0f09ba8
--- /dev/null
+++ b/plat/qti/msm8916/include/uartdm_console.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UARTDM_CONSOLE_H
+#define UARTDM_CONSOLE_H
+
+int console_uartdm_register(console_t *console, uintptr_t base_addr);
+
+#endif /* UARTDM_CONSOLE_H */
diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c
new file mode 100644
index 0000000..638cd09
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_bl31_setup.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "msm8916_gicv2.h"
+#include <msm8916_mmap.h>
+#include <platform_def.h>
+#include <uartdm_console.h>
+
+static const mmap_region_t msm8916_mmap[] = {
+	MAP_REGION_FLAT(PCNOC_BASE, PCNOC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+	MAP_REGION_FLAT(APCS_BASE, APCS_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+	{},
+};
+
+static struct {
+	entry_point_info_t bl32;
+	entry_point_info_t bl33;
+} image_ep_info = {
+	/* BL32 entry point */
+	SET_STATIC_PARAM_HEAD(bl32, PARAM_EP, VERSION_1,
+			      entry_point_info_t, SECURE),
+	.bl32.pc = BL32_BASE,
+
+	/* BL33 entry point */
+	SET_STATIC_PARAM_HEAD(bl33, PARAM_EP, VERSION_1,
+			      entry_point_info_t, NON_SECURE),
+	.bl33.pc = PRELOADED_BL33_BASE,
+	.bl33.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS),
+};
+
+static console_t console;
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return PLAT_SYSCNT_FREQ;
+}
+
+#define CLK_ENABLE			BIT_32(0)
+#define CLK_OFF				BIT_32(31)
+
+#define GPIO_BLSP_UART2_TX		4
+#define GPIO_BLSP_UART2_RX		5
+#define GPIO_CFG_FUNC_BLSP_UART2	(U(0x2) << 2)
+#define GPIO_CFG_DRV_STRENGTH_16MA	(U(0x7) << 6)
+
+#define GCC_BLSP1_AHB_CBCR		(GCC_BASE + 0x01008)
+#define GCC_BLSP1_UART2_APPS_CBCR	(GCC_BASE + 0x0302c)
+#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE	(GCC_BASE + 0x45004)
+#define BLSP1_AHB_CLK_ENA		BIT_32(10)
+
+/*
+ * The previous boot stage seems to disable most of the UART setup before exit
+ * so it must be enabled here again before the UART console can be used.
+ */
+static void msm8916_enable_blsp_uart2(void)
+{
+	/* Route GPIOs to BLSP UART2 */
+	mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_TX),
+		      GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA);
+	mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_RX),
+		      GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA);
+
+	/* Enable AHB clock */
+	mmio_setbits_32(GCC_APCS_CLOCK_BRANCH_ENA_VOTE, BLSP1_AHB_CLK_ENA);
+	while (mmio_read_32(GCC_BLSP1_AHB_CBCR) & CLK_OFF)
+		;
+
+	/* Enable BLSP UART2 clock */
+	mmio_setbits_32(GCC_BLSP1_UART2_APPS_CBCR, CLK_ENABLE);
+	while (mmio_read_32(GCC_BLSP1_UART2_APPS_CBCR) & CLK_OFF)
+		;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* Initialize the debug console as early as possible */
+	msm8916_enable_blsp_uart2();
+	console_uartdm_register(&console, BLSP_UART2_BASE);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	mmap_add_region(BL31_BASE, BL31_BASE, BL31_END - BL31_BASE,
+			MT_RW_DATA | MT_SECURE);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+	mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE);
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER);
+
+	mmap_add(msm8916_mmap);
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+
+static void msm8916_configure_timer(void)
+{
+	/* Set timer frequency */
+	mmio_write_32(APCS_QTMR + CNTCTLBASE_CNTFRQ, plat_get_syscnt_freq2());
+
+	/* Make frame 0 available to non-secure world */
+	mmio_write_32(APCS_QTMR + CNTNSAR, BIT_32(CNTNSAR_NS_SHIFT(0)));
+	mmio_write_32(APCS_QTMR + CNTACR_BASE(0),
+		      BIT_32(CNTACR_RPCT_SHIFT) | BIT_32(CNTACR_RVCT_SHIFT) |
+		      BIT_32(CNTACR_RFRQ_SHIFT) | BIT_32(CNTACR_RVOFF_SHIFT) |
+		      BIT_32(CNTACR_RWVT_SHIFT) | BIT_32(CNTACR_RWPT_SHIFT));
+}
+
+/*
+ * The APCS register regions always start with a SECURE register that should
+ * be cleared to 0 to only allow secure access. Since BL31 handles most of
+ * the CPU power management, most of them can be cleared to secure access only.
+ */
+#define APCS_GLB_SECURE_STS_NS		BIT_32(0)
+#define APCS_GLB_SECURE_PWR_NS		BIT_32(1)
+#define APCS_BOOT_START_ADDR_SEC	(APCS_CFG + 0x04)
+#define REMAP_EN			BIT_32(0)
+#define APCS_AA64NAA32_REG		(APCS_CFG + 0x0c)
+
+static void msm8916_configure_cpu_pm(void)
+{
+	unsigned int cpu;
+
+	/* Disallow non-secure access to boot remapper / TCM registers */
+	mmio_write_32(APCS_CFG, 0);
+
+	/*
+	 * Disallow non-secure access to power management registers.
+	 * However, allow STS and PWR since those also seem to control access
+	 * to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these
+	 * bits are not set, CPU frequency control fails in the non-secure world.
+	 */
+	mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS);
+
+	/* Disallow non-secure access to L2 SAW2 */
+	mmio_write_32(APCS_L2_SAW2, 0);
+
+	/* Disallow non-secure access to CPU ACS and SAW2 */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		mmio_write_32(APCS_ALIAS_ACS(cpu), 0);
+		mmio_write_32(APCS_ALIAS_SAW2(cpu), 0);
+	}
+
+	/* Make sure all further warm boots end up in BL31 and aarch64 state */
+	CASSERT((BL31_BASE & 0xffff) == 0, assert_bl31_base_64k_aligned);
+	mmio_write_32(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN);
+	mmio_write_32(APCS_AA64NAA32_REG, 1);
+}
+
+/*
+ * MSM8916 has a special "interrupt aggregation logic" in the APPS SMMU,
+ * which allows routing context bank interrupts to one of 3 interrupt numbers
+ * ("TZ/HYP/NS"). Route all interrupts to the non-secure interrupt number
+ * by default to avoid special setup on the non-secure side.
+ */
+#define GCC_SMMU_CFG_CBCR			(GCC_BASE + 0x12038)
+#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE	(GCC_BASE + 0x4500c)
+#define SMMU_CFG_CLK_ENA			BIT_32(12)
+#define APPS_SMMU_INTR_SEL_NS			(APPS_SMMU_QCOM + 0x2000)
+#define APPS_SMMU_INTR_SEL_NS_EN_ALL		U(0xffffffff)
+
+static void msm8916_configure_smmu(void)
+{
+	/* Enable SMMU configuration clock to enable register access */
+	mmio_setbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
+	while (mmio_read_32(GCC_SMMU_CFG_CBCR) & CLK_OFF)
+		;
+
+	/* Route all context bank interrupts to non-secure interrupt */
+	mmio_write_32(APPS_SMMU_INTR_SEL_NS, APPS_SMMU_INTR_SEL_NS_EN_ALL);
+
+	/* Disable configuration clock again */
+	mmio_clrbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
+}
+
+void bl31_platform_setup(void)
+{
+	INFO("BL31: Platform setup start\n");
+	generic_delay_timer_init();
+	msm8916_configure_timer();
+	msm8916_gicv2_init();
+	msm8916_configure_cpu_pm();
+	msm8916_configure_smmu();
+	INFO("BL31: Platform setup done\n");
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	switch (type) {
+	case SECURE:
+		return &image_ep_info.bl32;
+	case NON_SECURE:
+		return &image_ep_info.bl33;
+	default:
+		assert(sec_state_is_valid(type));
+		return NULL;
+	}
+}
diff --git a/plat/qti/msm8916/msm8916_cpu_boot.c b/plat/qti/msm8916/msm8916_cpu_boot.c
new file mode 100644
index 0000000..b3f51f6
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_cpu_boot.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <msm8916_mmap.h>
+#include "msm8916_pm.h"
+
+#define CPU_PWR_CTL			0x4
+#define APC_PWR_GATE_CTL		0x14
+
+#define CPU_PWR_CTL_CLAMP		BIT_32(0)
+#define CPU_PWR_CTL_CORE_MEM_CLAMP	BIT_32(1)
+#define CPU_PWR_CTL_L1_RST_DIS		BIT_32(2)
+#define CPU_PWR_CTL_CORE_MEM_HS		BIT_32(3)
+#define CPU_PWR_CTL_CORE_RST		BIT_32(4)
+#define CPU_PWR_CTL_COREPOR_RST		BIT_32(5)
+#define CPU_PWR_CTL_GATE_CLK		BIT_32(6)
+#define CPU_PWR_CTL_CORE_PWRD_UP	BIT_32(7)
+
+#define APC_PWR_GATE_CTL_GHDS_EN	BIT_32(0)
+#define APC_PWR_GATE_CTL_GHDS_CNT(cnt)	((cnt) << 24)
+
+/* Boot a secondary CPU core for the first time. */
+void msm8916_cpu_boot(unsigned int core)
+{
+	uintptr_t acs = APCS_ALIAS_ACS(core);
+	uint32_t pwr_ctl;
+
+	pwr_ctl = CPU_PWR_CTL_CLAMP | CPU_PWR_CTL_CORE_MEM_CLAMP |
+		  CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST;
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+
+	mmio_write_32(acs + APC_PWR_GATE_CTL, APC_PWR_GATE_CTL_GHDS_EN |
+		      APC_PWR_GATE_CTL_GHDS_CNT(16));
+	dsb();
+	udelay(2);
+
+	pwr_ctl &= ~CPU_PWR_CTL_CORE_MEM_CLAMP;
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+
+	pwr_ctl |= CPU_PWR_CTL_CORE_MEM_HS;
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+	udelay(2);
+
+	pwr_ctl &= ~CPU_PWR_CTL_CLAMP;
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+	udelay(2);
+
+	pwr_ctl &= ~(CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST);
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+
+	pwr_ctl |= CPU_PWR_CTL_CORE_PWRD_UP;
+	mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+	dsb();
+}
diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c
new file mode 100644
index 0000000..25a6628
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#include "msm8916_gicv2.h"
+#include <msm8916_mmap.h>
+
+#define IRQ_SEC_SGI_0		8
+#define IRQ_SEC_SGI_1		9
+#define IRQ_SEC_SGI_2		10
+#define IRQ_SEC_SGI_3		11
+#define IRQ_SEC_SGI_4		12
+#define IRQ_SEC_SGI_5		13
+#define IRQ_SEC_SGI_6		14
+#define IRQ_SEC_SGI_7		15
+
+#define IRQ_SEC_PHY_TIMER	(16 + 2)	/* PPI #2 */
+
+static const interrupt_prop_t msm8916_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+static const gicv2_driver_data_t msm8916_gic_data = {
+	.gicd_base		= APCS_QGIC2_GICD,
+	.gicc_base		= APCS_QGIC2_GICC,
+	.interrupt_props	= msm8916_interrupt_props,
+	.interrupt_props_num	= ARRAY_SIZE(msm8916_interrupt_props),
+};
+
+void msm8916_gicv2_init(void)
+{
+	gicv2_driver_init(&msm8916_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
diff --git a/plat/qti/msm8916/msm8916_gicv2.h b/plat/qti/msm8916/msm8916_gicv2.h
new file mode 100644
index 0000000..99db0d3
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_GICV2_H
+#define MSM8916_GICV2_H
+
+void msm8916_gicv2_init(void);
+
+#endif /* MSM8916_GICV2_H */
diff --git a/plat/qti/msm8916/msm8916_pm.c b/plat/qti/msm8916/msm8916_pm.c
new file mode 100644
index 0000000..6891e38
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_pm.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <msm8916_mmap.h>
+#include "msm8916_pm.h"
+
+static int msm8916_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+	VERBOSE("PSCI: Booting CPU %d\n", core);
+	msm8916_cpu_boot(core);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static void __dead2 msm8916_system_reset(void)
+{
+	mmio_write_32(MPM_PS_HOLD, 0);
+	mdelay(1000);
+
+	ERROR("PSCI: System reset failed\n");
+	panic();
+}
+
+static const plat_psci_ops_t msm8916_psci_ops = {
+	.pwr_domain_on			= msm8916_pwr_domain_on,
+	.pwr_domain_on_finish		= msm8916_pwr_domain_on_finish,
+	.system_off			= msm8916_system_reset,
+	.system_reset			= msm8916_system_reset,
+};
+
+/* Defined and used in msm8916_helpers.S */
+extern uintptr_t msm8916_entry_point;
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	msm8916_entry_point = sec_entrypoint;
+	*psci_ops = &msm8916_psci_ops;
+	return 0;
+}
diff --git a/plat/qti/msm8916/msm8916_pm.h b/plat/qti/msm8916/msm8916_pm.h
new file mode 100644
index 0000000..5473bfa
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_pm.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_PM_H
+#define MSM8916_PM_H
+
+void msm8916_cpu_boot(unsigned int core);
+
+#endif /* MSM8916_PM_H */
diff --git a/plat/qti/msm8916/msm8916_topology.c b/plat/qti/msm8916/msm8916_topology.c
new file mode 100644
index 0000000..4d0ed8f
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_topology.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = {
+	PLATFORM_SYSTEM_COUNT,
+	PLATFORM_CLUSTER_COUNT,
+	PLATFORM_MAX_CPUS_PER_CLUSTER,
+};
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
+	    MPIDR_AFFLVL2_VAL(mpidr) > 0 ||
+	    MPIDR_AFFLVL1_VAL(mpidr) > 0 ||
+	    core >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		return -1;
+	}
+
+	return core;
+}
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk
new file mode 100644
index 0000000..e516cea
--- /dev/null
+++ b/plat/qti/msm8916/platform.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES	:= ${XLAT_TABLES_LIB_SRCS}
+
+PLAT_INCLUDES	:=	-Iinclude/plat/arm/common/${ARCH}		\
+			-Iplat/qti/msm8916/include
+
+BL31_SOURCES	+=	${GICV2_SOURCES}				\
+			drivers/delay_timer/delay_timer.c		\
+			drivers/delay_timer/generic_delay_timer.c	\
+			lib/cpus/${ARCH}/cortex_a53.S			\
+			plat/common/plat_gicv2.c			\
+			plat/common/plat_psci_common.c			\
+			plat/qti/msm8916/msm8916_bl31_setup.c		\
+			plat/qti/msm8916/msm8916_cpu_boot.c		\
+			plat/qti/msm8916/msm8916_gicv2.c		\
+			plat/qti/msm8916/msm8916_pm.c			\
+			plat/qti/msm8916/msm8916_topology.c		\
+			plat/qti/msm8916/${ARCH}/msm8916_helpers.S	\
+			plat/qti/msm8916/${ARCH}/uartdm_console.S
+
+# Only BL31 is supported at the moment and is entered on a single CPU
+RESET_TO_BL31			:= 1
+COLD_BOOT_SINGLE_CPU		:= 1
+
+# Build config flags
+# ------------------
+BL31_BASE			?= 0x86500000
+BL32_BASE			?= 0x86000000
+PRELOADED_BL33_BASE		?= 0x8f600000
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Single cluster
+WARMBOOT_ENABLE_DCACHE_EARLY	:= 1
+
+# Disable features unsupported in ARMv8.0
+ENABLE_AMU			:= 0
+ENABLE_SPE_FOR_LOWER_ELS	:= 0
+ENABLE_SVE_FOR_NS		:= 0
+
+# MSM8916 uses ARM Cortex-A53 r0p0 so likely all the errata apply
+ERRATA_A53_819472		:= 1
+ERRATA_A53_824069		:= 1
+ERRATA_A53_826319		:= 1
+ERRATA_A53_827319		:= 1
+ERRATA_A53_835769		:= 1
+ERRATA_A53_836870		:= 1
+ERRATA_A53_843419		:= 1
+ERRATA_A53_855873		:= 0	# Workaround works only for >= r0p3
+ERRATA_A53_1530924		:= 1
+
+$(eval $(call add_define,BL31_BASE))
+$(eval $(call add_define,BL32_BASE))
diff --git a/plat/renesas/common/include/platform_def.h b/plat/renesas/common/include/platform_def.h
index 1213a3c..ab071ec 100644
--- a/plat/renesas/common/include/platform_def.h
+++ b/plat/renesas/common/include/platform_def.h
@@ -40,7 +40,7 @@
 #define PLATFORM_STACK_SIZE	U(0x400)
 #endif
 #elif IMAGE_BL31
-#define PLATFORM_STACK_SIZE	U(0x400)
+#define PLATFORM_STACK_SIZE	U(0x800)
 #elif IMAGE_BL32
 #define PLATFORM_STACK_SIZE	U(0x440)
 #endif
diff --git a/plat/renesas/common/plat_pm.c b/plat/renesas/common/plat_pm.c
index cc677f3..9810596 100644
--- a/plat/renesas/common/plat_pm.c
+++ b/plat/renesas/common/plat_pm.c
@@ -178,19 +178,22 @@
 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
 #endif
 #else
-	u_register_t cpu = read_mpidr_el1() & 0x0000ffffU;
+	u_register_t mpidr = read_mpidr_el1();
+	u_register_t cpu = mpidr & 0x0000ffffU;
 	int32_t rtn_on;
 
-	rtn_on = rcar_pwrc_cpu_on_check(cpu);
+	rtn_on = rcar_pwrc_cpu_on_check(mpidr);
 
-	if (cpu == rcar_boot_mpidr)
+	if (cpu != rcar_boot_mpidr) {
 		panic();
+	}
 
-	if (rtn_on)
+	if (rtn_on != 0) {
 		panic();
+	}
 
-	rcar_pwrc_cpuoff(cpu);
-	rcar_pwrc_clusteroff(cpu);
+	rcar_pwrc_cpuoff(mpidr);
+	rcar_pwrc_clusteroff(mpidr);
 
 #endif /* PMIC_ROHM_BD9571 */
 	wfi();
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index 7508004..d8d1c13 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,7 @@
 
 bool stm32mp_is_single_core(void);
 bool stm32mp_is_closed_device(void);
+bool stm32mp_is_auth_supported(void);
 
 /* Return the base address of the DDR controller */
 uintptr_t stm32mp_ddrctrl_base(void);
@@ -37,6 +38,11 @@
 /* Check MMU status to allow spinlock use */
 bool stm32mp_lock_available(void);
 
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+			uint32_t *otp_len);
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val);
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val);
+
 /* Get IWDG platform instance ID from peripheral IO memory base address */
 uint32_t stm32_iwdg_get_instance(uintptr_t base);
 
@@ -56,6 +62,14 @@
 /* Setup the UART console */
 int stm32mp_uart_console_setup(void);
 
+#if STM32MP_EARLY_CONSOLE
+void stm32mp_setup_early_console(void);
+#else
+static inline void stm32mp_setup_early_console(void)
+{
+}
+#endif
+
 /*
  * Platform util functions for the GPIO driver
  * @bank: Target GPIO bank ID as per DT bindings
diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h
index a87f941..b7bf1d0 100644
--- a/plat/st/common/include/stm32mp_dt.h
+++ b/plat/st/common/include/stm32mp_dt.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,6 +40,7 @@
 struct rdev *dt_get_vdd_regulator(void);
 struct rdev *dt_get_cpu_regulator(void);
 const char *dt_get_board_model(void);
+int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len);
 int fdt_get_gpio_bank_pin_count(unsigned int bank);
 
 #endif /* STM32MP_DT_H */
diff --git a/plat/st/common/stm32mp_auth.c b/plat/st/common/stm32mp_auth.c
index 744201c..97fbffa 100644
--- a/plat/st/common/stm32mp_auth.c
+++ b/plat/st/common/stm32mp_auth.c
@@ -46,6 +46,11 @@
 		INFO("Check signature on Open device\n");
 	}
 
+	if (auth_ops == NULL) {
+		ERROR("Device doesn't support image authentication\n");
+		return -EOPNOTSUPP;
+	}
+
 	ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE,
 				      STM32MP_ROM_SIZE_2MB_ALIGNED, MT_CODE | MT_SECURE);
 	if (ret != 0) {
diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c
index fb8e08e..f99cad5 100644
--- a/plat/st/common/stm32mp_common.c
+++ b/plat/st/common/stm32mp_common.c
@@ -135,6 +135,55 @@
 					   STM32MP_DDR_MAX_SIZE);
 }
 
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+			uint32_t *otp_len)
+{
+	assert(otp_name != NULL);
+	assert(otp_idx != NULL);
+
+	return dt_find_otp_name(otp_name, otp_idx, otp_len);
+}
+
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val)
+{
+	uint32_t otp_idx;
+
+	assert(otp_name != NULL);
+	assert(otp_val != NULL);
+
+	if (stm32_get_otp_index(otp_name, &otp_idx, NULL) != 0) {
+		return -1;
+	}
+
+	if (stm32_get_otp_value_from_idx(otp_idx, otp_val) != 0) {
+		ERROR("BSEC: %s Read Error\n", otp_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val)
+{
+	uint32_t ret = BSEC_NOT_SUPPORTED;
+
+	assert(otp_val != NULL);
+
+#if defined(IMAGE_BL2)
+	ret = bsec_shadow_read_otp(otp_val, otp_idx);
+#elif defined(IMAGE_BL32)
+	ret = bsec_read_otp(otp_val, otp_idx);
+#else
+#error "Not supported"
+#endif
+	if (ret != BSEC_OK) {
+		ERROR("BSEC: idx=%u Read Error\n", otp_idx);
+		return -1;
+	}
+
+	return 0;
+}
+
 #if  defined(IMAGE_BL2)
 static void reset_uart(uint32_t reset)
 {
@@ -156,10 +205,27 @@
 }
 #endif
 
+static void set_console(uintptr_t base, uint32_t clk_rate)
+{
+	unsigned int console_flags;
+
+	if (console_stm32_register(base, clk_rate,
+				   STM32MP_UART_BAUDRATE, &console) == 0) {
+		panic();
+	}
+
+	console_flags = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH |
+			CONSOLE_FLAG_TRANSLATE_CRLF;
+#if !defined(IMAGE_BL2) && defined(DEBUG)
+	console_flags |= CONSOLE_FLAG_RUNTIME;
+#endif
+
+	console_set_scope(&console, console_flags);
+}
+
 int stm32mp_uart_console_setup(void)
 {
 	struct dt_node_info dt_uart_info;
-	unsigned int console_flags;
 	uint32_t clk_rate = 0U;
 	int result;
 	uint32_t boot_itf __unused;
@@ -200,21 +266,19 @@
 	clk_rate = clk_get_rate((unsigned long)dt_uart_info.clock);
 #endif
 
-	if (console_stm32_register(dt_uart_info.base, clk_rate,
-				   STM32MP_UART_BAUDRATE, &console) == 0) {
-		panic();
-	}
-
-	console_flags = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH |
-			CONSOLE_FLAG_TRANSLATE_CRLF;
-#if !defined(IMAGE_BL2) && defined(DEBUG)
-	console_flags |= CONSOLE_FLAG_RUNTIME;
-#endif
-	console_set_scope(&console, console_flags);
+	set_console(dt_uart_info.base, clk_rate);
 
 	return 0;
 }
 
+#if STM32MP_EARLY_CONSOLE
+void stm32mp_setup_early_console(void)
+{
+	plat_crash_console_init();
+	set_console(STM32MP_DEBUG_USART_BASE, STM32MP_DEBUG_USART_CLK_FRQ);
+}
+#endif /* STM32MP_EARLY_CONSOLE */
+
 /*****************************************************************************
  * plat_is_smccc_feature_available() - This function checks whether SMCCC
  *                                     feature is availabile for platform.
diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c
index 863a90f..ea71571 100644
--- a/plat/st/common/stm32mp_dt.c
+++ b/plat/st/common/stm32mp_dt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -319,6 +319,73 @@
 }
 
 /*******************************************************************************
+ * dt_find_otp_name: get OTP ID and length in DT.
+ * name: sub-node name to look up.
+ * otp: pointer to read OTP number or NULL.
+ * otp_len: pointer to read OTP length in bits or NULL.
+ * return value: 0 if no error, an FDT error value otherwise.
+ ******************************************************************************/
+int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
+{
+	int node;
+	int index, len;
+	const fdt32_t *cuint;
+
+	if ((name == NULL) || (otp == NULL)) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	node = fdt_node_offset_by_compatible(fdt, -1, DT_NVMEM_LAYOUT_COMPAT);
+	if (node < 0) {
+		return node;
+	}
+
+	index = fdt_stringlist_search(fdt, node, "nvmem-cell-names", name);
+	if (index < 0) {
+		return index;
+	}
+
+	cuint = fdt_getprop(fdt, node, "nvmem-cells", &len);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if ((index * (int)sizeof(uint32_t)) > len) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	cuint += index;
+
+	node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+	if (node < 0) {
+		ERROR("Malformed nvmem_layout node: ignored\n");
+		return node;
+	}
+
+	cuint = fdt_getprop(fdt, node, "reg", &len);
+	if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
+		ERROR("Malformed nvmem_layout node: ignored\n");
+		return -FDT_ERR_BADVALUE;
+	}
+
+	if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
+		ERROR("Misaligned nvmem_layout element: ignored\n");
+		return -FDT_ERR_BADVALUE;
+	}
+
+	if (otp != NULL) {
+		*otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+	}
+
+	if (otp_len != NULL) {
+		cuint++;
+		*otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
  * This function gets the pin count for a GPIO bank based from the FDT.
  * It also checks node consistency.
  ******************************************************************************/
@@ -337,6 +404,9 @@
 
 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
 		const fdt32_t *cuint;
+		int pin_count;
+		int len;
+		int i;
 
 		if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
 			continue;
@@ -355,12 +425,22 @@
 			return 0;
 		}
 
-		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
-		if (cuint == NULL) {
-			return -FDT_ERR_NOTFOUND;
+		/* Parse gpio-ranges with its 4 parameters */
+		cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
+		len /= sizeof(*cuint);
+		if ((len % 4) != 0) {
+			return -FDT_ERR_BADVALUE;
 		}
 
-		return (int)fdt32_to_cpu(*cuint);
+		/* Get the last defined gpio line (offset + nb of pins) */
+		pin_count = fdt32_to_cpu(*(cuint + 1)) + fdt32_to_cpu(*(cuint + 3));
+		for (i = 0; i < len / 4; i++) {
+			pin_count = MAX(pin_count, (int)(fdt32_to_cpu(*(cuint + 1)) +
+							 fdt32_to_cpu(*(cuint + 3))));
+			cuint += 4;
+		}
+
+		return pin_count;
 	}
 
 	return 0;
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index b5fc3ff..33ad56f 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -33,6 +33,20 @@
 #include <stm32mp_common.h>
 #include <stm32mp1_dbgmcu.h>
 
+#if DEBUG
+static const char debug_msg[] = {
+	"***************************************************\n"
+	"** DEBUG ACCESS PORT IS OPEN!                    **\n"
+	"** This boot image is only for debugging purpose **\n"
+	"** and is unsafe for production use.             **\n"
+	"**                                               **\n"
+	"** If you see this message and you are not       **\n"
+	"** debugging report this immediately to your     **\n"
+	"** vendor!                                       **\n"
+	"***************************************************\n"
+};
+#endif
+
 static struct stm32mp_auth_ops stm32mp1_auth_ops;
 
 static void print_reset_reason(void)
@@ -125,6 +139,8 @@
 				  u_register_t arg2 __unused,
 				  u_register_t arg3 __unused)
 {
+	stm32mp_setup_early_console();
+
 	stm32mp_save_boot_ctx_address(arg0);
 }
 
@@ -155,6 +171,40 @@
 #endif /* STM32MP_USE_STM32IMAGE */
 }
 
+static void update_monotonic_counter(void)
+{
+	uint32_t version;
+	uint32_t otp;
+
+	CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE,
+		assert_stm32mp1_monotonic_counter_reach_max);
+
+	/* Check if monotonic counter needs to be incremented */
+	if (stm32_get_otp_index(MONOTONIC_OTP, &otp, NULL) != 0) {
+		panic();
+	}
+
+	if (stm32_get_otp_value_from_idx(otp, &version) != 0) {
+		panic();
+	}
+
+	if ((version + 1U) < BIT(STM32_TF_VERSION)) {
+		uint32_t result;
+
+		/* Need to increment the monotonic counter. */
+		version = BIT(STM32_TF_VERSION) - 1U;
+
+		result = bsec_program_otp(version, otp);
+		if (result != BSEC_OK) {
+			ERROR("BSEC: MONOTONIC_OTP program Error %u\n",
+			      result);
+			panic();
+		}
+		INFO("Monotonic counter has been incremented (value 0x%x)\n",
+		     version);
+	}
+}
+
 void bl2_el3_plat_arch_setup(void)
 {
 	const char *board_model;
@@ -163,6 +213,10 @@
 	uintptr_t pwr_base;
 	uintptr_t rcc_base;
 
+	if (bsec_probe() != 0U) {
+		panic();
+	}
+
 	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
 			BL_CODE_END - BL_CODE_BASE,
 			MT_CODE | MT_SECURE);
@@ -205,10 +259,6 @@
 		;
 	}
 
-	if (bsec_probe() != 0) {
-		panic();
-	}
-
 	/* Reset backup domain on cold boot cases */
 	if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) {
 		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
@@ -299,16 +349,31 @@
 
 	stm32_iwdg_refresh();
 
-	stm32mp1_auth_ops.check_key = boot_context->bootrom_ecdsa_check_key;
-	stm32mp1_auth_ops.verify_signature =
-		boot_context->bootrom_ecdsa_verify_signature;
+	if (bsec_read_debug_conf() != 0U) {
+		if (stm32mp_is_closed_device()) {
+#if DEBUG
+			WARN("\n%s", debug_msg);
+#else
+			ERROR("***Debug opened on closed chip***\n");
+#endif
+		}
+	}
 
-	stm32mp_init_auth(&stm32mp1_auth_ops);
+	if (stm32mp_is_auth_supported()) {
+		stm32mp1_auth_ops.check_key =
+			boot_context->bootrom_ecdsa_check_key;
+		stm32mp1_auth_ops.verify_signature =
+			boot_context->bootrom_ecdsa_verify_signature;
+
+		stm32mp_init_auth(&stm32mp1_auth_ops);
+	}
 
 	stm32mp1_arch_security_setup();
 
 	print_reset_reason();
 
+	update_monotonic_counter();
+
 	stm32mp1_syscfg_enable_io_compensation_finish();
 
 #if !STM32MP_USE_STM32IMAGE
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 6f7c79b..8d4320a 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -9,6 +9,8 @@
 BL2_AT_EL3		:=	1
 USE_COHERENT_MEM	:=	0
 
+STM32MP_EARLY_CONSOLE	?=	0
+
 # Allow TF-A to concatenate BL2 & BL32 binaries in a single file,
 # share DTB file between BL2 and BL32
 # If it is set to 0, then FIP is used
@@ -19,6 +21,8 @@
 BL2_IN_XIP_MEM		:=	1
 endif
 
+# Please don't increment this value without good understanding of
+# the monotonic counter
 STM32_TF_VERSION	?=	0
 
 # Enable dynamic memory mapping
@@ -96,8 +100,14 @@
 FDT_SOURCES		+=	$(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME)))
 endif
 endif
+
+$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}'))
+$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g")))
 DTC_CPPFLAGS		+=	${INCLUDES}
 DTC_FLAGS		+=	-Wno-unit_address_vs_reg
+ifeq ($(shell test $(DTC_VERSION) -ge 10601; echo $$?),0)
+DTC_FLAGS		+=	-Wno-interrupt_provider
+endif
 
 # Macros and rules to build TF binary
 STM32_TF_ELF_LDFLAGS	:=	--hash-style=gnu --as-needed
@@ -149,6 +159,7 @@
 		PLAT_XLAT_TABLES_DYNAMIC \
 		STM32MP_DDR_32BIT_INTERFACE \
 		STM32MP_DDR_DUAL_AXI_PORT \
+		STM32MP_EARLY_CONSOLE \
 		STM32MP_EMMC \
 		STM32MP_EMMC_BOOT \
 		STM32MP_RAW_NAND \
@@ -175,6 +186,7 @@
 		STM32_TF_VERSION \
 		STM32MP_DDR_32BIT_INTERFACE \
 		STM32MP_DDR_DUAL_AXI_PORT \
+		STM32MP_EARLY_CONSOLE \
 		STM32MP_EMMC \
 		STM32MP_EMMC_BOOT \
 		STM32MP_RAW_NAND \
@@ -216,7 +228,7 @@
 				drivers/clk/clk.c					\
 				drivers/delay_timer/delay_timer.c			\
 				drivers/delay_timer/generic_delay_timer.c		\
-				drivers/st/bsec/bsec.c					\
+				drivers/st/bsec/bsec2.c					\
 				drivers/st/clk/stm32mp_clkfunc.c			\
 				drivers/st/clk/stm32mp1_clk.c				\
 				drivers/st/ddr/stm32mp_ddr.c				\
@@ -361,8 +373,6 @@
 	${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean
 
 check_dtc_version:
-	$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}'))
-	$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g")))
 	@if [ ${DTC_VERSION} -lt 10404 ]; then \
 		echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \
 		false; \
diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
index a1d7fc6..1fb44b4 100644
--- a/plat/st/stm32mp1/services/bsec_svc.c
+++ b/plat/st/stm32mp1/services/bsec_svc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,7 @@
 
 #include <common/debug.h>
 #include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
 
 #include <stm32mp1_smc.h>
 
diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c
index 6a05707..714ab80 100644
--- a/plat/st/stm32mp1/stm32mp1_boot_device.c
+++ b/plat/st/stm32mp1/stm32mp1_boot_device.c
@@ -20,13 +20,11 @@
 #if STM32MP_RAW_NAND || STM32MP_SPI_NAND
 static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
 {
-	int result;
 	uint32_t nand_param;
 
 	/* Check if NAND parameters are stored in OTP */
-	result = bsec_shadow_read_otp(&nand_param, NAND_OTP);
-	if (result != BSEC_OK) {
-		ERROR("BSEC: NAND_OTP Error %i\n", result);
+	if (stm32_get_otp_value(NAND_OTP, &nand_param) != 0) {
+		ERROR("BSEC: NAND_OTP Error\n");
 		return -EACCES;
 	}
 
diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
index 1826783..08e332a 100644
--- a/plat/st/stm32mp1/stm32mp1_dbgmcu.c
+++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,14 +7,14 @@
 #include <assert.h>
 #include <errno.h>
 
-#include <platform_def.h>
-
 #include <common/debug.h>
 #include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
 #include <drivers/st/stm32mp1_rcc.h>
 #include <lib/mmio.h>
 #include <lib/utils_def.h>
 
+#include <platform_def.h>
 #include <stm32mp1_dbgmcu.h>
 
 #define DBGMCU_IDC		U(0x00)
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index c63efd5..fd12159 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -347,19 +347,19 @@
 
 #define OTP_MAX_SIZE			(STM32MP1_OTP_MAX_ID + 1U)
 
-/* OTP offsets */
-#define DATA0_OTP			U(0)
-#define PART_NUMBER_OTP			U(1)
-#define NAND_OTP			U(9)
-#define UID0_OTP			U(13)
-#define UID1_OTP			U(14)
-#define UID2_OTP			U(15)
-#define PACKAGE_OTP			U(16)
-#define HW2_OTP				U(18)
+/* OTP labels */
+#define CFG0_OTP			"cfg0_otp"
+#define PART_NUMBER_OTP			"part_number_otp"
+#define PACKAGE_OTP			"package_otp"
+#define HW2_OTP				"hw2_otp"
+#define NAND_OTP			"nand_otp"
+#define MONOTONIC_OTP			"monotonic_otp"
+#define UID_OTP				"uid_otp"
+#define BOARD_ID_OTP			"board_id"
 
 /* OTP mask */
-/* DATA0 */
-#define DATA0_OTP_SECURED		BIT(6)
+/* CFG0 */
+#define CFG0_CLOSED_DEVICE		BIT(6)
 
 /* PART NUMBER */
 #define PART_NUMBER_OTP_PART_MASK	GENMASK_32(7, 0)
@@ -416,6 +416,9 @@
 /* NAND number of planes */
 #define NAND_PLANE_BIT_NB_MASK		BIT(14)
 
+/* MONOTONIC OTP */
+#define MAX_MONOTONIC_VALUE		32
+
 /* UID OTP */
 #define UID_WORD_NB			U(3)
 
@@ -486,7 +489,9 @@
 #define DT_BSEC_COMPAT			"st,stm32mp15-bsec"
 #define DT_DDR_COMPAT			"st,stm32mp1-ddr"
 #define DT_IWDG_COMPAT			"st,stm32mp1-iwdg"
+#define DT_NVMEM_LAYOUT_COMPAT		"st,stm32-nvmem-layout"
 #define DT_PWR_COMPAT			"st,stm32mp1,pwr-reg"
 #define DT_RCC_CLK_COMPAT		"st,stm32mp1-rcc"
+#define DT_RCC_SEC_CLK_COMPAT		"st,stm32mp1-rcc-secure"
 
 #endif /* STM32MP1_DEF_H */
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index 9016b0d..9b39b9d 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -278,7 +278,7 @@
 		return part_number;
 	}
 
-	if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) {
+	if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) {
 		panic();
 	}
 
@@ -294,7 +294,7 @@
 {
 	uint32_t package;
 
-	if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) {
+	if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) {
 		panic();
 	}
 
@@ -397,35 +397,9 @@
 
 void stm32mp_print_boardinfo(void)
 {
-	uint32_t board_id;
-	uint32_t board_otp;
-	int bsec_node, bsec_board_id_node;
-	void *fdt;
-	const fdt32_t *cuint;
+	uint32_t board_id = 0;
 
-	if (fdt_get_address(&fdt) == 0) {
-		panic();
-	}
-
-	bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
-	if (bsec_node < 0) {
-		return;
-	}
-
-	bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id");
-	if (bsec_board_id_node <= 0) {
-		return;
-	}
-
-	cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL);
-	if (cuint == NULL) {
-		panic();
-	}
-
-	board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
-
-	if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) {
-		ERROR("BSEC: PART_NUMBER_OTP Error\n");
+	if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) {
 		return;
 	}
 
@@ -446,15 +420,20 @@
 /* Return true when SoC provides a single Cortex-A7 core, and false otherwise */
 bool stm32mp_is_single_core(void)
 {
+	bool single_core = false;
+
 	switch (get_part_number()) {
 	case STM32MP151A_PART_NB:
 	case STM32MP151C_PART_NB:
 	case STM32MP151D_PART_NB:
 	case STM32MP151F_PART_NB:
-		return true;
+		single_core = true;
+		break;
 	default:
-		return false;
+		break;
 	}
+
+	return single_core;
 }
 
 /* Return true when device is in closed state */
@@ -462,12 +441,32 @@
 {
 	uint32_t value;
 
-	if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
-	    (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+	if (stm32_get_otp_value(CFG0_OTP, &value) != 0) {
 		return true;
 	}
 
-	return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+	return (value & CFG0_CLOSED_DEVICE) == CFG0_CLOSED_DEVICE;
+}
+
+/* Return true when device supports secure boot */
+bool stm32mp_is_auth_supported(void)
+{
+	bool supported = false;
+
+	switch (get_part_number()) {
+	case STM32MP151C_PART_NB:
+	case STM32MP151F_PART_NB:
+	case STM32MP153C_PART_NB:
+	case STM32MP153F_PART_NB:
+	case STM32MP157C_PART_NB:
+	case STM32MP157F_PART_NB:
+		supported = true;
+		break;
+	default:
+		break;
+	}
+
+	return supported;
 }
 
 uint32_t stm32_iwdg_get_instance(uintptr_t base)
@@ -487,13 +486,7 @@
 	uint32_t iwdg_cfg = 0U;
 	uint32_t otp_value;
 
-#if defined(IMAGE_BL2)
-	if (bsec_shadow_register(HW2_OTP) != BSEC_OK) {
-		panic();
-	}
-#endif
-
-	if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
+	if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
 		panic();
 	}
 
@@ -515,29 +508,34 @@
 #if defined(IMAGE_BL2)
 uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags)
 {
+	uint32_t otp_value;
 	uint32_t otp;
 	uint32_t result;
 
-	if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) {
+	if (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) {
 		panic();
 	}
 
-	if ((flags & IWDG_DISABLE_ON_STOP) != 0U) {
-		otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
+	if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
+		panic();
 	}
 
-	if ((flags & IWDG_DISABLE_ON_STANDBY) != 0U) {
-		otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
+	if ((flags & IWDG_DISABLE_ON_STOP) != 0) {
+		otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
 	}
 
-	result = bsec_write_otp(otp, HW2_OTP);
+	if ((flags & IWDG_DISABLE_ON_STANDBY) != 0) {
+		otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
+	}
+
+	result = bsec_write_otp(otp_value, otp);
 	if (result != BSEC_OK) {
 		return result;
 	}
 
 	/* Sticky lock OTP_IWDG (read and write) */
-	if (!bsec_write_sr_lock(HW2_OTP, 1U) ||
-	    !bsec_write_sw_lock(HW2_OTP, 1U)) {
+	if ((bsec_set_sr_lock(otp) != BSEC_OK) ||
+	    (bsec_set_sw_lock(otp) != BSEC_OK)) {
 		return BSEC_LOCK_FAIL;
 	}
 
diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c
index 01a6439..3f34af1 100644
--- a/plat/st/stm32mp1/stm32mp1_syscfg.c
+++ b/plat/st/stm32mp1/stm32mp1_syscfg.c
@@ -7,11 +7,11 @@
 #include <common/debug.h>
 #include <drivers/clk.h>
 #include <drivers/delay_timer.h>
-#include <drivers/st/bsec.h>
 #include <drivers/st/stpmic1.h>
 #include <lib/mmio.h>
 
 #include <platform_def.h>
+#include <stm32mp_common.h>
 #include <stm32mp_dt.h>
 #include <stm32mp1_private.h>
 
@@ -116,8 +116,9 @@
 
 static void stm32mp1_syscfg_set_hslv(void)
 {
-	uint32_t otp = 0;
+	uint32_t otp_value;
 	uint32_t vdd_voltage;
+	bool product_below_2v5;
 
 	/*
 	 * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
@@ -134,26 +135,26 @@
 	 *   => TF-A enables the low power mode only if VDD < 2.7V (in DT)
 	 *      but this value needs to be consistent with board design.
 	 */
-	if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) {
+	if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
 		panic();
 	}
 
-	otp = otp & HW2_OTP_PRODUCT_BELOW_2V5;
+	product_below_2v5 = (otp_value & HW2_OTP_PRODUCT_BELOW_2V5) != 0U;
 
 	/* Get VDD supply */
 	vdd_voltage = dt_get_pwr_vdd_voltage();
 
 	/* Check if VDD is Low Voltage */
 	if (vdd_voltage == 0U) {
-		WARN("VDD unknown");
+		WARN("VDD unknown\n");
 	} else if (vdd_voltage < 2700000U) {
 		enable_high_speed_mode_low_voltage();
 
-		if (otp == 0U) {
+		if (!product_below_2v5) {
 			INFO("Product_below_2v5=0: HSLVEN protected by HW\n");
 		}
 	} else {
-		if (otp != 0U) {
+		if (product_below_2v5) {
 			ERROR("Product_below_2v5=1:\n");
 			ERROR("\tHSLVEN update is destructive,\n");
 			ERROR("\tno update as VDD > 2.7V\n");
diff --git a/plat/st/stm32mp1/stm32mp1_usb_dfu.c b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
index 70fbba6..33b12d0 100644
--- a/plat/st/stm32mp1/stm32mp1_usb_dfu.c
+++ b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -157,27 +157,28 @@
 static void update_serial_num_string(void)
 {
 	uint8_t i;
-	uint32_t result;
 	char serial_string[SIZ_STRING_SERIAL + 2U];
-	uint32_t deviceserial[UID_WORD_NB];
+	/* serial number is set to 0 */
+	uint32_t deviceserial[UID_WORD_NB] = {0U, 0U, 0U};
+	uint32_t otp;
+	uint32_t len;
 	uint16_t length;
 
-	for (i = 0U; i < UID_WORD_NB; i++) {
-		result = bsec_shadow_register(i + UID0_OTP);
-		if (result != BSEC_OK) {
-			ERROR("BSEC: UID%d Shadowing Error\n", i);
-			break;
-		}
-		result = bsec_read_otp(&deviceserial[i], i + UID0_OTP);
-		if (result != BSEC_OK) {
-			ERROR("BSEC: UID%d Read Error\n", i);
-			break;
-		}
+	if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) {
+		ERROR("BSEC: Get UID_OTP number Error\n");
+		return;
 	}
-	/* On bsec error: serial number is set to 0 */
-	if (result != BSEC_OK) {
-		for (i = 0; i < UID_WORD_NB; i++) {
-			deviceserial[i] = 0U;
+
+	if ((len / __WORD_BIT) != UID_WORD_NB) {
+		ERROR("BSEC: Get UID_OTP length Error\n");
+		return;
+	}
+
+	for (i = 0; i < UID_WORD_NB; i++) {
+		if (bsec_shadow_read_otp(&deviceserial[i], i + otp) !=
+		    BSEC_OK) {
+			ERROR("BSEC: UID%d Error\n", i);
+			return;
 		}
 	}
 	/* build serial number with OTP value as in ROM code */
diff --git a/tools/sptool/sp_mk_generator.py b/tools/sptool/sp_mk_generator.py
index f983ff3..6b1f204 100755
--- a/tools/sptool/sp_mk_generator.py
+++ b/tools/sptool/sp_mk_generator.py
@@ -1,5 +1,5 @@
 #!/usr/bin/python3
-# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -134,7 +134,7 @@
         int.from_bytes(y[1], byteorder='little', signed=False),
         int.from_bytes(y[2], byteorder='little', signed=False),
         int.from_bytes(y[3], byteorder='little', signed=False))
-        uuid_std = uuid.UUID(f'{z[0]:04x}{z[1]:04x}{z[2]:04x}{z[3]:04x}')
+        uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
 
         """
         Append FIP_ARGS