Merge "feat(rcar3): change CAM setting to improve bus latency of R-Car Gen3" into integration
diff --git a/Makefile b/Makefile
index 800346a..7058d57 100644
--- a/Makefile
+++ b/Makefile
@@ -1221,7 +1221,6 @@
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_HCX \
-	ENABLE_FEAT_MTE \
 	ENABLE_FEAT_MTE2 \
 	ENABLE_FEAT_PAN \
 	ENABLE_FEAT_RNG \
@@ -1235,7 +1234,6 @@
 	ENABLE_FEAT_S1POE \
 	ENABLE_FEAT_GCS \
 	ENABLE_FEAT_VHE \
-	ENABLE_FEAT_MTE_PERM \
 	ENABLE_FEAT_MPAM \
 	ENABLE_RME \
 	ENABLE_SPE_FOR_NS \
@@ -1384,9 +1382,7 @@
 	ENABLE_FEAT_S2POE \
 	ENABLE_FEAT_S1POE \
 	ENABLE_FEAT_GCS \
-	ENABLE_FEAT_MTE \
 	ENABLE_FEAT_MTE2 \
-	ENABLE_FEAT_MTE_PERM \
 	FEATURE_DETECTION \
 	TWED_DELAY \
 	ENABLE_FEAT_TWED \
diff --git a/bl31/bl31_traps.c b/bl31/bl31_traps.c
index f1b1fa6..474b4d5 100644
--- a/bl31/bl31_traps.c
+++ b/bl31/bl31_traps.c
@@ -165,7 +165,7 @@
 
 	/* If FEAT_MTE2 is implemented mask tag faults by setting TCO bit */
 	new_spsr |= old_spsr & SPSR_TCO_BIT_AARCH64;
-	if (read_feat_mte_id_field() >= MTE_IMPLEMENTED_ELX) {
+	if (is_feat_mte2_present()) {
 		new_spsr |= SPSR_TCO_BIT_AARCH64;
 	}
 
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
index d8031f9..805575a 100644
--- a/bl32/tsp/tsp_main.c
+++ b/bl32/tsp/tsp_main.c
@@ -239,10 +239,10 @@
 	service_arg1 = (uint64_t)(service_args >> 64U);
 
 	/*
-	 * Write a dummy value to an MTE register, to simulate usage in the
+	 * Write a dummy value to an MTE2 register, to simulate usage in the
 	 * secure world
 	 */
-	if (is_feat_mte_supported()) {
+	if (is_feat_mte2_supported()) {
 		write_gcr_el1(0x99);
 	}
 
diff --git a/changelog.yaml b/changelog.yaml
index 7f0c1ec..b7f281c 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -116,8 +116,11 @@
       - title: Memory Partitioning and Monitoring (MPAM) Extension (FEAT_MPAM)
         scope: mpam
 
-      - title: Memory Tagging Extension
-        scope: mte
+      - title: Memory Tagging Extension2
+        scope: mte2
+
+        deprecated:
+          - mte
 
       - title: Pointer Authentication Extension
         scope: pauth
@@ -544,6 +547,9 @@
           - title: Raspberry Pi 4
             scope: rpi4
 
+          - title: Raspberry Pi 5
+            scope: rpi5
+
       - title: Renesas
         scope: renesas
 
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 7a2f0d7..7f01037 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -167,9 +167,7 @@
 		      "TRF", 1, 1);
 
 	/* v8.5 features */
-	check_feature(ENABLE_FEAT_MTE, read_feat_mte_id_field(), "MTE",
-		      MTE_IMPLEMENTED_EL0, MTE_IMPLEMENTED_ASY);
-	check_feature(ENABLE_FEAT_MTE2, read_feat_mte_id_field(), "MTE2",
+	check_feature(ENABLE_FEAT_MTE2, get_armv8_5_mte_support(), "MTE2",
 		      MTE_IMPLEMENTED_ELX, MTE_IMPLEMENTED_ASY);
 	check_feature(ENABLE_FEAT_RNG, read_feat_rng_id_field(), "RNG", 1, 1);
 	read_feat_bti();
@@ -204,8 +202,6 @@
 		      "S2POE", 1, 1);
 	check_feature(ENABLE_FEAT_S1POE, read_feat_s1poe_id_field(),
 		      "S1POE", 1, 1);
-	check_feature(ENABLE_FEAT_MTE_PERM, read_feat_mte_perm_id_field(),
-		      "MTE_PERM", 1, 1);
 	check_feature(ENABLE_FEAT_CSV2_3, read_feat_csv2_id_field(),
 		      "CSV2_3", 3, 3);
 
diff --git a/docs/components/secure-partition-manager.rst b/docs/components/secure-partition-manager.rst
index 4834d3a..b6f4219 100644
--- a/docs/components/secure-partition-manager.rst
+++ b/docs/components/secure-partition-manager.rst
@@ -215,7 +215,7 @@
     ARM_ARCH_MINOR=5 \
     BRANCH_PROTECTION=1 \
     CTX_INCLUDE_PAUTH_REGS=1 \
-    ENABLE_FEAT_MTE=1 \
+    ENABLE_FEAT_MTE2=1 \
     BL32=<path-to-hafnium-binary> \
     BL33=<path-to-bl33-binary> \
     SP_LAYOUT_FILE=sp_layout.json \
@@ -233,7 +233,7 @@
     ARM_ARCH_MINOR=5 \
     BRANCH_PROTECTION=1 \
     CTX_INCLUDE_PAUTH_REGS=1 \
-    ENABLE_FEAT_MTE=1 \
+    ENABLE_FEAT_MTE2=1 \
     BL32=<path-to-hafnium-binary> \
     BL33=<path-to-bl33-binary> \
     SP_LAYOUT_FILE=sp_layout.json \
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 97e164d..5733214 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -793,7 +793,7 @@
 
 - ``ERRATA_X3_2615812``: This applies errata 2615812 workaround to Cortex-X3
   CPU. This needs to be enabled only for revisions r0p0, r1p0 and r1p1 of the
-  CPU, it is still open.
+  CPU, it is fixed in r1p2.
 
 - ``ERRATA_X3_2641945``: This applies errata 2641945 workaround to Cortex-X3
   CPU. This needs to be enabled only for revisions r0p0 and r1p0 of the CPU.
@@ -916,6 +916,15 @@
    Cortex-A715 CPU. This needs to be enabled only for revision r1p0.
    It is fixed in r1p1.
 
+For Cortex-A720, the following errata build flags are defined :
+
+-  ``ERRATA_A720_2926083``: This applies errata 2926083 workaround to
+   Cortex-A720 CPU. This needs to be enabled for revisions r0p0 and r0p1.
+   It is fixed in r0p2.
+
+-  ``ERRATA_A720_2940794``: This applies errata 2940794 workaround to
+   Cortex-A720 CPU. This needs to be enabled for revisions r0p0 and r0p1.
+   It is fixed in r0p2.
 
 DSU Errata Workarounds
 ----------------------
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index fa06c8e..2ba54ea 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -2800,9 +2800,11 @@
 -  Branch Target Identification feature is selected by ``BRANCH_PROTECTION``
    option set to 1. This option defaults to 0.
 
--  Memory Tagging Extension feature is unconditionally enabled for both worlds.
-   To enable MTE at EL0 use ``ENABLE_FEAT_MTE`` is required and to enable MTE at
-   ELX ``ENABLE_FEAT_MTE2`` is required.
+-  Memory Tagging Extension feature has few variants but not all of them require
+   enablement from EL3 to be used at lower EL. e.g. Memory tagging only at
+   EL0(MTE) does not require EL3 configuration however memory tagging at
+   EL2/EL1 (MTE2) does require EL3 enablement and we need to set this option
+   ``ENABLE_FEAT_MTE2`` to 1. This option defaults to 0.
 
 Armv7-A
 ~~~~~~~
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index f817da0..c18c155 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -340,23 +340,11 @@
    flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
    mechanism. Default value is ``0``.
 
--  ``ENABLE_FEAT_MTE``: Numeric value to enable Memory Tagging Extension
-   if the platform wants to use this feature at EL0 ``ENABLE_FEAT_MTE`` is
-   required. This flag can take values 0 to 2, to align with the ``ENABLE_FEAT``
-   feature detection mechanism. Default value is ``0``.
-
 -  ``ENABLE_FEAT_MTE2``: Numeric value to enable Memory Tagging Extension2
    if the platform wants to use this feature and MTE2 is enabled at ELX.
    This flag can take values 0 to 2, to align with the ``ENABLE_FEAT``
    mechanism. Default value is ``0``.
 
--  ``ENABLE_FEAT_MTE_PERM``: Numeric value to enable support for
-   ``FEAT_MTE_PERM``, which introduces Allocation tag access permission to
-   memory region attributes. ``FEAT_MTE_PERM`` is a optional architectural
-   feature available from v8.9 and upwards.  This flag can take the values 0 to
-   2, to align  with the ``ENABLE_FEAT`` mechanism. Default value is
-   ``0``.
-
 -  ``ENABLE_FEAT_PAN``: Numeric value to enable the ``FEAT_PAN`` (Privileged
    Access Never) extension. ``FEAT_PAN`` adds a bit to PSTATE, generating a
    permission fault for any privileged data access from EL1/EL2 to virtual
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 43f4898..35cc27d 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -38,6 +38,7 @@
    qti-msm8916
    rpi3
    rpi4
+   rpi5
    rcar-gen3
    rz-g2
    rockchip
diff --git a/docs/plat/rpi5.rst b/docs/plat/rpi5.rst
new file mode 100644
index 0000000..f2e1b9f
--- /dev/null
+++ b/docs/plat/rpi5.rst
@@ -0,0 +1,78 @@
+Raspberry Pi 5
+==============
+
+The `Raspberry Pi 5`_ is a single-board computer that contains four
+Arm Cortex-A76 cores.
+
+This port is a minimal BL31 implementation capable of booting 64-bit EL2
+payloads such as Linux and EDK2.
+
+**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM,
+which is available from both the Non-secure and Secure worlds. The SoC does
+not seem to feature a secure memory controller of any kind, so portions of
+DRAM can't be protected properly from the Non-secure world.
+
+Build
+------------------
+
+To build this platform, run:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi5 DEBUG=1
+
+The firmware will be generated at ``build/rpi5/debug/bl31.bin``.
+
+The following build options are supported:
+
+- ``RPI3_DIRECT_LINUX_BOOT``: Enabled by default. Allows direct boot of the Linux
+  kernel from the firmware.
+
+- ``PRELOADED_BL33_BASE``: Used to specify the fixed address of a BL33 binary
+  that has been preloaded by earlier boot stages (VPU). Useful for bundling
+  BL31 and BL33 in the same ``armstub`` image (e.g. TF-A + EDK2).
+
+- ``RPI3_PRELOADED_DTB_BASE``: This option allows to specify the fixed address of
+  a DTB in memory. Can only be used if ``device_tree_address=`` is present in
+  config.txt.
+
+- ``RPI3_RUNTIME_UART``: Indicates whether TF-A should use the debug UART for
+  runtime messages or not. ``-1`` (default) disables the option, any other value
+  enables it.
+
+Usage
+------------------
+
+Copy the firmware binary to the first FAT32 partition of a supported boot media
+(SD, USB) and append ``armstub=bl31.bin`` to config.txt, or just rename the
+file to ``armstub8-2712.bin``.
+
+No other config options or files are required by the firmware alone, this will
+depend on the payload you intend to run.
+
+For Linux, you must also place an appropriate DTB and kernel in the boot
+partition. This has been validated with a copy of Raspberry Pi OS.
+
+The VPU will preload a BL33 AArch64 image named either ``kernel_2712.img`` or
+``kernel8.img``, which can be overridden by adding a ``kernel=filename`` option
+to config.txt.
+
+Kernel and DTB load addresses are also chosen by the VPU and can be changed with
+``kernel_address=`` and ``device_tree_address=`` in config.txt. If TF-A was built
+with ``PRELOADED_BL33_BASE`` or ``RPI3_PRELOADED_DTB_BASE``, setting those config
+options may be necessary.
+
+By default, all boot stages print messages to the dedicated UART debug port.
+Configuration is ``115200 8n1``.
+
+Design
+------------------
+
+This port is largely based on the RPi 4 one.
+
+The boot process is essentially the same, the only notable difference being that
+all VPU blobs have been moved into EEPROM (former start4.elf & fixup4.dat). There's
+also a custom BL31 TF-A armstub included for PSCI, which can be replaced with this
+port.
+
+.. _Raspberry Pi 5: https://www.raspberrypi.com/products/raspberry-pi-5/
diff --git a/docs/plat/st/stm32mp1.rst b/docs/plat/st/stm32mp1.rst
index b6e4b0d..39a43ee 100644
--- a/docs/plat/st/stm32mp1.rst
+++ b/docs/plat/st/stm32mp1.rst
@@ -115,8 +115,9 @@
     make stm32mp15_trusted_defconfig
     make DEVICE_TREE=stm32mp157c-ev1 all
 
-OP-TEE (optional)
-_________________
+OP-TEE (recommended)
+____________________
+OP-TEE is the default BL32 supported for STMicroelectronics platforms.
 
 .. code:: bash
 
@@ -125,9 +126,10 @@
         CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-ev1.dts
 
 
-TF-A BL32 (SP_min)
-__________________
+TF-A BL32 (SP_min) (not recommended)
+____________________________________
 If you choose not to use OP-TEE, you can use TF-A SP_min.
+This is not the recommended BL32 to use, and will have very limited support.
 To build TF-A BL32, and its device tree file:
 
 .. code:: bash
@@ -217,4 +219,4 @@
 .. _STM32MP1 Series: https://www.st.com/en/microcontrollers-microprocessors/stm32mp1-series.html
 .. _STM32MP1 part number codification: https://wiki.st.com/stm32mpu/wiki/STM32MP15_microprocessor#Part_number_codification
 
-*Copyright (c) 2023, STMicroelectronics - All Rights Reserved*
+*Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved*
diff --git a/docs/plat/st/stm32mpus.rst b/docs/plat/st/stm32mpus.rst
index 931dd57..ab6d8fe 100644
--- a/docs/plat/st/stm32mpus.rst
+++ b/docs/plat/st/stm32mpus.rst
@@ -45,6 +45,8 @@
 - ``STM32MP_UART_PROGRAMMER``
 - ``STM32MP_USB_PROGRAMMER``
 
+Only one storage or serial device should be selected in the build command line,
+to save space and not overflow SYSRAM size, or else the platform won't build or boot.
 
 Other configuration flags:
 
@@ -75,4 +77,4 @@
 
 --------------
 
-*Copyright (c) 2023, STMicroelectronics - All Rights Reserved*
+*Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved*
diff --git a/docs/security_advisories/security-advisory-tfv-9.rst b/docs/security_advisories/security-advisory-tfv-9.rst
index 762801d..014221e 100644
--- a/docs/security_advisories/security-advisory-tfv-9.rst
+++ b/docs/security_advisories/security-advisory-tfv-9.rst
@@ -87,7 +87,7 @@
 +----------------------+
 | Neoverse-V2          |
 +----------------------+
-| Neoverse-Poseidon    |
+| Neoverse-V3          |
 +----------------------+
 
 For all other cores impacted by Spectre-BHB, some of which that do not implement
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index a4786bb..5e44aa9 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  * Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -75,7 +75,7 @@
 		panic();
 	}
 
-	/* Poll till PUP is zero before intiating write */
+	/* Poll till PUP is zero before initiating write */
 	gicd_dchipr_wait_for_power_update_progress(base);
 
 	write_gicd_dchipr(base, read_gicd_dchipr(base) |
diff --git a/drivers/arm/mhu/mhu_v3_x.c b/drivers/arm/mhu/mhu_v3_x.c
new file mode 100644
index 0000000..118c608
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "mhu_v3_x.h"
+
+#include "mhu_v3_x_private.h"
+
+/*
+ * Get the device base from the device struct. Return an error if the dev is
+ * invalid.
+ */
+static enum mhu_v3_x_error_t get_dev_base(const struct mhu_v3_x_dev_t *dev,
+	 union _mhu_v3_x_frame_t **base)
+{
+	if (dev == NULL) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	/* Ensure driver has been initialized */
+	if (dev->is_initialized == false) {
+		return MHU_V_3_X_ERR_NOT_INIT;
+	}
+
+	*base = (union _mhu_v3_x_frame_t *)dev->base;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev)
+{
+	uint32_t aidr = 0;
+	uint8_t mhu_major_rev;
+	union _mhu_v3_x_frame_t *p_mhu;
+
+	if (dev == NULL) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	/* Return if already initialized */
+	if (dev->is_initialized == true) {
+		return MHU_V_3_X_ERR_NONE;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	/* Read revision from MHU hardware */
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		aidr = p_mhu->pbx_frame.pbx_ctrl_page.pbx_aidr;
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		aidr = p_mhu->mbx_frame.mbx_ctrl_page.mbx_aidr;
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	/* Read the MHU Architecture Major Revision */
+	mhu_major_rev =
+		((aidr & MHU_ARCH_MAJOR_REV_MASK) >> MHU_ARCH_MAJOR_REV_OFF);
+
+	/* Return error if the MHU major revision is not 3 */
+	if (mhu_major_rev != MHU_MAJOR_REV_V3) {
+		/* Unsupported MHU version */
+		return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
+	}
+
+	/* Read the MHU Architecture Minor Revision */
+	dev->subversion =
+		((aidr & MHU_ARCH_MINOR_REV_MASK) >> MHU_ARCH_MINOR_REV_MASK);
+
+	/* Return error if the MHU minor revision is not 0 */
+	if (dev->subversion != MHU_MINOR_REV_3_0) {
+		/* Unsupported subversion */
+		return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
+	}
+
+	/* Initialize the Postbox/Mailbox to remain in operational state */
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		p_mhu->pbx_frame.pbx_ctrl_page.pbx_ctrl |= MHU_V3_OP_REQ;
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		p_mhu->mbx_frame.mbx_ctrl_page.mbx_ctrl |= MHU_V3_OP_REQ;
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	dev->is_initialized = true;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
+	 const struct mhu_v3_x_dev_t *dev,
+	 enum mhu_v3_x_channel_type_t ch_type, uint8_t *num_ch)
+{
+	enum mhu_v3_x_error_t status;
+	union _mhu_v3_x_frame_t *p_mhu;
+
+	if (num_ch == NULL) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only doorbell channel is supported */
+	if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	/* Read the number of channels implemented in the MHU */
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		*num_ch = (p_mhu->pbx_frame.pbx_ctrl_page.pbx_dbch_cfg0 + 1);
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		*num_ch = (p_mhu->mbx_frame.mbx_ctrl_page.mbx_dbch_cfg0 + 1);
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+	enum mhu_v3_x_error_t status;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only MBX can clear the Doorbell channel */
+	if (dev->frame != MHU_V3_X_MBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+	mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+		&(p_mhu->mbx_frame.mdbcw_page);
+
+	/* Clear the bits in the doorbell channel */
+	mdbcw_reg[channel].mdbcw_clr |= flags;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+	enum mhu_v3_x_error_t status;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only PBX can set the Doorbell channel value */
+	if (dev->frame != MHU_V3_X_PBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+		&(p_mhu->pbx_frame.pdbcw_page);
+
+	/* Write the value to the doorbell channel */
+	pdbcw_reg[channel].pdbcw_set |= flags;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t *flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	enum mhu_v3_x_error_t status;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+	struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+
+	if (flags == NULL) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+			&(p_mhu->pbx_frame.pdbcw_page);
+
+		/* Read the value from Postbox Doorbell status register */
+		*flags = pdbcw_reg[channel].pdbcw_st;
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+			&(p_mhu->mbx_frame.mdbcw_page);
+
+		/* Read the value from Mailbox Doorbell status register */
+		*flags = mdbcw_reg[channel].mdbcw_st;
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 uint32_t flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+	enum mhu_v3_x_error_t status;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Doorbell channel mask is not applicable for PBX */
+	if (dev->frame != MHU_V3_X_MBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+		&(p_mhu->mbx_frame.mdbcw_page);
+
+	/* Set the Doorbell channel mask */
+	mdbcw_reg[channel].mdbcw_msk_set |= flags;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 uint32_t flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+	enum mhu_v3_x_error_t status;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Doorbell channel mask is not applicable for PBX */
+	if (dev->frame != MHU_V3_X_MBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+		&(p_mhu->mbx_frame.mdbcw_page);
+
+	/* Clear the Doorbell channel mask */
+	mdbcw_reg[channel].mdbcw_msk_clr = flags;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 uint32_t *flags)
+{
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+	enum mhu_v3_x_error_t status;
+
+	if (flags == NULL) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Doorbell channel mask is not applicable for PBX */
+	if (dev->frame != MHU_V3_X_MBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+		&(p_mhu->mbx_frame.mdbcw_page);
+
+	/* Save the Doorbell channel mask status */
+	*flags = mdbcw_reg[channel].mdbcw_msk_st;
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type)
+{
+	enum mhu_v3_x_error_t status;
+
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only doorbell channel is supported */
+	if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+			&(p_mhu->pbx_frame.pdbcw_page);
+
+		/*
+		 * Enable this doorbell channel to generate interrupts for
+		 * transfer acknowledge events.
+		 */
+		pdbcw_reg[channel].pdbcw_int_en = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
+
+		/*
+		 * Enable this doorbell channel to contribute to the PBX
+		 * combined interrupt.
+		 */
+		pdbcw_reg[channel].pdbcw_ctrl = MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN;
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+			&(p_mhu->mbx_frame.mdbcw_page);
+
+		/*
+		 * Enable this doorbell channel to contribute to the MBX
+		 * combined interrupt.
+		 */
+		mdbcw_reg[channel].mdbcw_ctrl = MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN;
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type)
+{
+	enum mhu_v3_x_error_t status;
+
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+	struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only doorbell channel is supported */
+	if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+	if (dev->frame == MHU_V3_X_PBX_FRAME) {
+		pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+			&(p_mhu->pbx_frame.pdbcw_page);
+
+		/* Clear channel transfer acknowledge event interrupt */
+		pdbcw_reg[channel].pdbcw_int_clr = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
+
+		/* Disable channel transfer acknowledge event interrupt */
+		pdbcw_reg[channel].pdbcw_int_en &=
+			~(MHU_V3_X_PDBCW_INT_X_TFR_ACK);
+
+		/*
+		 * Disable this doorbell channel from contributing to the PBX
+		 * combined interrupt.
+		 */
+		pdbcw_reg[channel].pdbcw_ctrl &=
+			~(MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN);
+	} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+		mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+			&(p_mhu->mbx_frame.mdbcw_page);
+
+		/*
+		 * Disable this doorbell channel from contributing to the MBX
+		 * combined interrupt.
+		 */
+		mdbcw_reg[channel].mdbcw_ctrl &=
+			~(MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN);
+	} else {
+		/* Only PBX and MBX frames are supported. */
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type)
+{
+	enum mhu_v3_x_error_t status;
+	union _mhu_v3_x_frame_t *p_mhu;
+	struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+
+	/* Get dev->base if it is valid or return an error if dev is not */
+	status = get_dev_base(dev, &p_mhu);
+	if (status != MHU_V_3_X_ERR_NONE) {
+		return status;
+	}
+
+	/* Only doorbell channel is supported */
+	if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+		return MHU_V_3_X_ERR_UNSUPPORTED;
+	}
+
+	/*
+	 * Only postbox doorbell channel transfer acknowledge interrupt can be
+	 * cleared manually.
+	 *
+	 * To clear MBX interrupt the unmasked status must be cleared using
+	 * mhu_v3_x_doorbell_clear.
+	 */
+	if (dev->frame != MHU_V3_X_PBX_FRAME) {
+		return MHU_V_3_X_ERR_INVALID_PARAM;
+	}
+
+	p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+	pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)&(
+			p_mhu->pbx_frame.pdbcw_page);
+
+	/* Clear channel transfer acknowledge event interrupt */
+	pdbcw_reg[channel].pdbcw_int_clr |= 0x1;
+
+	return MHU_V_3_X_ERR_NONE;
+}
diff --git a/drivers/arm/mhu/mhu_v3_x.h b/drivers/arm/mhu/mhu_v3_x.h
new file mode 100644
index 0000000..a3a1950
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V3_X_H
+#define MHU_V3_X_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* MHU Architecture Major Revision 3 */
+#define MHU_MAJOR_REV_V3 U(0x2)
+/* MHU Architecture Minor Revision 0 */
+#define MHU_MINOR_REV_3_0 U(0x0)
+
+/* MHU Architecture Major Revision offset */
+#define MHU_ARCH_MAJOR_REV_OFF U(0x4)
+/* MHU Architecture Major Revision mask */
+#define MHU_ARCH_MAJOR_REV_MASK (U(0xf) << MHU_ARCH_MAJOR_REV_OFF)
+
+/* MHU Architecture Minor Revision offset */
+#define MHU_ARCH_MINOR_REV_OFF U(0x0)
+/* MHU Architecture Minor Revision mask */
+#define MHU_ARCH_MINOR_REV_MASK (U(0xf) << MHU_ARCH_MINOR_REV_OFF)
+
+/* MHUv3 PBX/MBX Operational Request offset */
+#define MHU_V3_OP_REQ_OFF U(0)
+/* MHUv3 PBX/MBX Operational Request */
+#define MHU_V3_OP_REQ (U(1) << MHU_V3_OP_REQ_OFF)
+
+/**
+ * MHUv3 error enumeration types
+ */
+enum mhu_v3_x_error_t {
+	/* No error */
+	MHU_V_3_X_ERR_NONE,
+	/* MHU driver not initialized */
+	MHU_V_3_X_ERR_NOT_INIT,
+	/* MHU driver alreary initialized */
+	MHU_V_3_X_ERR_ALREADY_INIT,
+	/* MHU Revision not supported error */
+	MHU_V_3_X_ERR_UNSUPPORTED_VERSION,
+	/* Operation not supported */
+	MHU_V_3_X_ERR_UNSUPPORTED,
+	/* Invalid parameter */
+	MHU_V_3_X_ERR_INVALID_PARAM,
+	/* General MHU driver error */
+	MHU_V_3_X_ERR_GENERAL,
+};
+
+/**
+ * MHUv3 channel types
+ */
+enum mhu_v3_x_channel_type_t {
+	/* Doorbell channel */
+	MHU_V3_X_CHANNEL_TYPE_DBCH,
+	/* Channel type count */
+	MHU_V3_X_CHANNEL_TYPE_COUNT,
+};
+
+/**
+ * MHUv3 frame types
+ */
+enum mhu_v3_x_frame_t {
+	/* MHUv3 postbox frame */
+	MHU_V3_X_PBX_FRAME,
+	/* MHUv3 mailbox frame */
+	MHU_V3_X_MBX_FRAME,
+};
+
+/**
+ * MHUv3 device structure
+ */
+struct mhu_v3_x_dev_t {
+	/* Base address of the MHUv3 frame */
+	uintptr_t base;
+	/* Type of the MHUv3 frame */
+	enum mhu_v3_x_frame_t frame;
+	/* Minor revision of the MHUv3 */
+	uint32_t subversion;
+	/* Flag to indicate if the MHUv3 is initialized */
+	bool is_initialized;
+};
+
+/**
+ * Initializes the MHUv3
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev);
+
+/**
+ * Returns the number of channels implemented
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * ch_type	MHU channel type mhu_v3_x_channel_type_t
+ * num_ch	Pointer to the variable that will store the value
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
+	 const struct mhu_v3_x_dev_t *dev, enum mhu_v3_x_channel_type_t ch_type,
+	 uint8_t *num_ch);
+
+/**
+ * Clear flags from a doorbell channel
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Flags to be cleared from the channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t flags);
+
+/**
+ * Write flags to a doorbell channel
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Flags to be written to the channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t flags);
+
+/**
+ * Read value from a doorbell channel
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Pointer to the variable that will store the flags read from the
+ *		channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
+	 const uint32_t channel, uint32_t *flags);
+
+/**
+ * Set bits in a doorbell channel mask which is used to disable interrupts for
+ * received flags corresponding to the mask
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Flags to set mask bits in this doorbell channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 uint32_t flags);
+
+/**
+ * Clear bits in a doorbell channel mask which is used to disable interrupts
+ * for received flags corresponding to the mask
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Flags to clear mask bits in this doorbell channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t flags);
+
+/**
+ * Get the mask of a doorbell channel which is used to disable interrupts for
+ * received flags corresponding to the mask
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * flags	Pointer to the variable that will store the flags read from the
+ *		mask value
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t *flags);
+
+/**
+ * Enable the channel interrupt
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * ch_type	MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type);
+
+/**
+ * Disable the channel interrupt
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * ch_type	MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type);
+
+/**
+ * Clear the channel interrupt
+ *
+ * dev		MHU device struct mhu_v3_x_dev_t
+ * channel	Doorbell channel number
+ * ch_type	MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
+	 const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+	 enum mhu_v3_x_channel_type_t ch_type);
+
+#endif /* MHU_V3_X_H */
diff --git a/drivers/arm/mhu/mhu_v3_x_private.h b/drivers/arm/mhu/mhu_v3_x_private.h
new file mode 100644
index 0000000..9594a2a
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x_private.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V3_X_PRIVATE_H
+#define MHU_V3_X_PRIVATE_H
+
+#include <stdint.h>
+
+/* Flag for PDBCW Interrupt Transfer Acknowledgment  */
+#define MHU_V3_X_PDBCW_INT_X_TFR_ACK 0x1
+
+/* Flag for PDBCW CTRL Postbox combined interrupts enable */
+#define MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN 0x1
+
+/* Flag for MDBCW CTRL Mailbox combined interrupts enable */
+#define MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN 0x1
+
+/**
+ * Postbox control page structure
+ */
+struct _mhu_v3_x_pbx_ctrl_reg_t {
+	/* Offset: 0x000 (R/ ) Postbox Block Identifier */
+	const volatile uint32_t pbx_blk_id;
+	/* Offset: 0x004 (R/ ) Reserved */
+	const volatile uint8_t reserved_0[0x10 - 0x04];
+	/* Offset: 0x010 (R/ ) Postbox Feature Support 0 */
+	const volatile uint32_t pbx_feat_spt0;
+	/* Offset: 0x014 (R/ ) Postbox Feature Support 1 */
+	const volatile uint32_t pbx_feat_spt1;
+	/* Offset: 0x018 (R/ ) Reserved */
+	const volatile uint8_t reserved_1[0x20 - 0x18];
+	/* Offset: 0x020 (R/ ) Postbox Doorbell Channel Configuration 0 */
+	const volatile uint32_t pbx_dbch_cfg0;
+	/* Offset: 0x024 (R/ ) Reserved */
+	const volatile uint8_t reserved_2[0x30 - 0x24];
+	/* Offset: 0x030 (R/ ) Postbox FIFO Channel Configuration 0 */
+	const volatile uint32_t pbx_ffch_cfg0;
+	/* Offset: 0x034 (R/ ) Reserved */
+	const volatile uint8_t reserved_3[0x40 - 0x34];
+	/* Offset: 0x040 (R/ ) Postbox Fast Channel Configuration 0 */
+	const volatile uint32_t pbx_fch_cfg0;
+	/* Offset: 0x044 (R/ ) Reserved */
+	const volatile uint8_t reserved_4[0x100 - 0x44];
+	/* Offset: 0x100 (R/W) Postbox control */
+	volatile uint32_t pbx_ctrl;
+	/* Offset: 0x164 (R/ ) Reserved */
+	const volatile uint8_t reserved_5[0x400 - 0x104];
+	/*
+	 * Offset: 0x400 (R/ ) Postbox Doorbell Channel Interrupt Status n,
+	 * where n is 0 - 3.
+	 */
+	const volatile uint32_t pbx_dbch_int_st[4];
+	/*
+	 * Offset: 0x410 (R/ ) Postbox FIFO Channel <n> Interrupt Status n,
+	 * where n is 0 - 1.
+	 */
+	const volatile uint32_t pbx_ffch_int_st[2];
+	/* Offset: 0x418 (R/ ) Reserved */
+	const uint8_t reserved_6[0xFC8 - 0x418];
+	/* Offset: 0xFC8 (R/ ) Postbox Implementer Identification Register */
+	const volatile uint32_t pbx_iidr;
+	/* Offset: 0xFCC (R/ ) Postbox Architecture Identification Register */
+	const volatile uint32_t pbx_aidr;
+	/*
+	 * Offset: 0xFD0 (R/ ) Postbox Implementation Defined Identification
+	 * Register n, where n is 0 - 11.
+	 */
+	const volatile uint32_t impl_def_id[12];
+};
+
+/**
+ * Postbox doorbell channel window page structure
+ */
+struct _mhu_v3_x_pdbcw_reg_t {
+	/* Offset: 0x000 (R/ ) Postbox Doorbell Channel Window Status */
+	const volatile uint32_t pdbcw_st;
+	/* Offset: 0x004 (R/ ) Reserved */
+	const uint8_t reserved_0[0xC - 0x4];
+	/* Offset: 0x00C ( /W) Postbox Doorbell Channel Window Set */
+	volatile uint32_t pdbcw_set;
+	/*
+	 * Offset: 0x010 (R/ ) Postbox Doorbell Channel Window Interrupt Status
+	 */
+	const volatile uint32_t pdbcw_int_st;
+	/*
+	 * Offset: 0x014 ( /W) Postbox Doorbell Channel Window Interrupt Clear
+	 */
+	volatile uint32_t pdbcw_int_clr;
+	/*
+	 * Offset: 0x018 (R/W) Postbox Doorbell Channel Window Interrupt Enable
+	 */
+	volatile uint32_t pdbcw_int_en;
+	/* Offset: 0x01C (R/W) Postbox Doorbell Channel Window Control */
+	volatile uint32_t pdbcw_ctrl;
+};
+
+/**
+ * Postbox structure
+ */
+struct _mhu_v3_x_pbx {
+	/* Postbox Control */
+	struct _mhu_v3_x_pbx_ctrl_reg_t pbx_ctrl_page;
+	/* Postbox Doorbell Channel Window */
+	struct _mhu_v3_x_pdbcw_reg_t pdbcw_page;
+};
+
+/**
+ * Mailbox control page structure
+ */
+struct _mhu_v3_x_mbx_ctrl_reg_t {
+	/* Offset: 0x000 (R/ ) Mailbox Block Identifier */
+	const volatile uint32_t mbx_blk_id;
+	/* Offset: 0x004 (R/ ) Reserved */
+	const volatile uint8_t reserved_0[0x10 - 0x04];
+	/* Offset: 0x010 (R/ ) Mailbox Feature Support 0 */
+	const volatile uint32_t mbx_feat_spt0;
+	/* Offset: 0x014 (R/ ) Mailbox Feature Support 1 */
+	const volatile uint32_t mbx_feat_spt1;
+	/* Offset: 0x018 (R/ ) Reserved */
+	const volatile uint8_t reserved_1[0x20 - 0x18];
+	/* Offset: 0x020 (R/ ) Mailbox Doorbell Channel Configuration 0 */
+	const volatile uint32_t mbx_dbch_cfg0;
+	/* Offset: 0x024 (R/ ) Reserved */
+	const volatile uint8_t reserved_2[0x30 - 0x24];
+	/* Offset: 0x030 (R/ ) Mailbox FIFO Channel Configuration 0 */
+	const volatile uint32_t mbx_ffch_cfg0;
+	/* Offset: 0x034 (R/ ) Reserved */
+	const volatile uint8_t reserved_4[0x40 - 0x34];
+	/* Offset: 0x040 (R/ ) Mailbox Fast Channel Configuration 0 */
+	const volatile uint32_t mbx_fch_cfg0;
+	/* Offset: 0x044 (R/ ) Reserved */
+	const volatile uint8_t reserved_5[0x100 - 0x44];
+	/* Offset: 0x100 (R/W) Mailbox control */
+	volatile uint32_t mbx_ctrl;
+	/* Offset: 0x104 (R/ ) Reserved */
+	const volatile uint8_t reserved_6[0x140 - 0x104];
+	/* Offset: 0x140 (R/W) Mailbox Fast Channel control */
+	volatile uint32_t mbx_fch_ctrl;
+	/* Offset: 0x144 (R/W) Mailbox Fast Channel Group Interrupt Enable */
+	volatile uint32_t mbx_fcg_int_en;
+	/* Offset: 0x148 (R/ ) Reserved */
+	const volatile uint8_t reserved_7[0x400 - 0x148];
+	/*
+	 * Offset: 0x400 (R/ ) Mailbox Doorbell Channel Interrupt Status n,
+	 * where n = 0 - 3.
+	 */
+	const volatile uint32_t mbx_dbch_int_st[4];
+	/*
+	 * Offset: 0x410 (R/ ) Mailbox FIFO Channel Interrupt Status n, where
+	 * n = 0 - 1.
+	 */
+	const volatile uint32_t mbx_ffch_int_st[2];
+	/* Offset: 0x418 (R/ ) Reserved */
+	const volatile uint8_t reserved_8[0x470 - 0x418];
+	/* Offset: 0x470 (R/ ) Mailbox Fast Channel Group Interrupt Status */
+	const volatile uint32_t mbx_fcg_int_st;
+	/* Offset: 0x474 (R/ ) Reserved */
+	const volatile uint8_t reserved_9[0x480 - 0x474];
+	/*
+	 * Offset: 0x480 (R/ ) Mailbox Fast Channel Group <n> Interrupt Status,
+	 * where n = 0 - 31.
+	 */
+	const volatile uint32_t mbx_fch_grp_int_st[32];
+	/* Offset: 0x500 (R/ ) Reserved */
+	const volatile uint8_t reserved_10[0xFC8 - 0x500];
+	/* Offset: 0xFC8 (R/ ) Mailbox Implementer Identification Register */
+	const volatile uint32_t mbx_iidr;
+	/* Offset: 0xFCC (R/ ) Mailbox Architecture Identification Register */
+	const volatile uint32_t mbx_aidr;
+	/*
+	 * Offset: 0xFD0 (R/ ) Mailbox Implementation Defined Identification
+	 * Register n, where n is 0 - 11.
+	 */
+	const volatile uint32_t impl_def_id[12];
+};
+
+/**
+ * Mailbox doorbell channel window page structure
+ */
+struct _mhu_v3_x_mdbcw_reg_t {
+	/* Offset: 0x000 (R/ ) Mailbox Doorbell Channel Window Status */
+	const volatile uint32_t mdbcw_st;
+	/* Offset: 0x004 (R/ ) Mailbox Doorbell Channel Window Status Masked */
+	const volatile uint32_t mdbcw_st_msk;
+	/* Offset: 0x008 ( /W) Mailbox Doorbell Channel Window Clear */
+	volatile uint32_t mdbcw_clr;
+	/* Offset: 0x00C (R/ ) Reserved */
+	const volatile uint8_t reserved_0[0x10 - 0x0C];
+	/* Offset: 0x010 (R/ ) Mailbox Doorbell Channel Window Mask Status */
+	const volatile uint32_t mdbcw_msk_st;
+	/* Offset: 0x014 ( /W) Mailbox Doorbell Channel Window Mask Set */
+	volatile uint32_t mdbcw_msk_set;
+	/* Offset: 0x018 ( /W) Mailbox Doorbell Channel Window Mask Clear */
+	volatile uint32_t mdbcw_msk_clr;
+	/* Offset: 0x01C (R/W) Mailbox Doorbell Channel Window Control */
+	volatile uint32_t mdbcw_ctrl;
+};
+
+/**
+ * Mailbox structure
+ */
+struct _mhu_v3_x_mbx {
+	/* Mailbox control */
+	struct _mhu_v3_x_mbx_ctrl_reg_t mbx_ctrl_page;
+	/* Mailbox Doorbell Channel Window */
+	struct _mhu_v3_x_mdbcw_reg_t mdbcw_page;
+};
+
+/**
+ * MHUv3 frame type
+ */
+union _mhu_v3_x_frame_t {
+	/* Postbox Frame */
+	struct _mhu_v3_x_pbx pbx_frame;
+	/* Mailbox Frame */
+	struct _mhu_v3_x_mbx mbx_frame;
+};
+
+#endif /* MHU_V3_X_PRIVATE_H */
diff --git a/drivers/arm/mhu/mhu_wrapper_v3_x.c b/drivers/arm/mhu/mhu_wrapper_v3_x.c
new file mode 100644
index 0000000..b3d51e3
--- /dev/null
+++ b/drivers/arm/mhu/mhu_wrapper_v3_x.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/arm/mhu.h>
+
+#include "mhu_v3_x.h"
+
+#define MHU_NOTIFY_VALUE	U(1234)
+
+#ifndef ALIGN_UP
+#define ALIGN_UP(num, align)	(((num) + ((align) - 1)) & ~((align) - 1))
+#endif
+
+/*
+ * MHUv3 Wrapper utility macros
+ */
+#define IS_ALIGNED(val, align)	(val == ALIGN_UP(val, align))
+
+/*
+ * MHU devices for host:
+ * HSE: Host to Secure Enclave (sender device)
+ * SEH: Secure Enclave to Host (receiver device)
+ */
+struct mhu_v3_x_dev_t mhu_hse_dev = {0, MHU_V3_X_PBX_FRAME};
+struct mhu_v3_x_dev_t mhu_seh_dev = {0, MHU_V3_X_MBX_FRAME};
+
+/* MHUv3 driver error to MHUv3 wrapper error mapping */
+static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v3_x_error_t err)
+{
+	switch (err) {
+	case MHU_V_3_X_ERR_NONE:
+		return MHU_ERR_NONE;
+
+	case MHU_V_3_X_ERR_NOT_INIT:
+		return MHU_ERR_NOT_INIT;
+
+	case MHU_V_3_X_ERR_UNSUPPORTED_VERSION:
+		return MHU_ERR_UNSUPPORTED_VERSION;
+
+	case MHU_V_3_X_ERR_UNSUPPORTED:
+		return MHU_ERR_UNSUPPORTED;
+
+	case MHU_V_3_X_ERR_INVALID_PARAM:
+		return MHU_ERR_INVALID_ARG;
+
+	default:
+		return MHU_ERR_GENERAL;
+	}
+}
+
+static enum mhu_error_t signal_and_wait_for_clear(
+	void *mhu_sender_dev, uint32_t value)
+{
+	enum mhu_v3_x_error_t err;
+	struct mhu_v3_x_dev_t *dev;
+	uint8_t num_channels;
+	uint32_t read_val;
+
+	dev = (struct mhu_v3_x_dev_t *)mhu_sender_dev;
+
+	if ((dev == NULL) || (dev->base == 0)) {
+		return MHU_ERR_INVALID_ARG;
+	}
+
+	err = mhu_v3_x_get_num_channel_implemented(dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/* Wait for any pending acknowledgment from transmitter side */
+	do {
+		err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	} while ((read_val & value) == value);
+
+	/* Use the last channel to notify that a transfer is ready */
+	err = mhu_v3_x_doorbell_write(dev, num_channels - 1, value);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/* Wait until receiver side acknowledges the transfer */
+	do {
+		err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	} while ((read_val & value) == value);
+
+	return error_mapping_to_mhu_error_t(MHU_V_3_X_ERR_NONE);
+}
+
+static enum mhu_error_t wait_for_signal(
+	void *mhu_receiver_dev, uint32_t value)
+{
+	enum mhu_v3_x_error_t err;
+	struct mhu_v3_x_dev_t *dev;
+	uint32_t read_val;
+	uint8_t num_channels;
+
+	dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev;
+
+	if ((dev == NULL) || (dev->base == 0)) {
+		return MHU_ERR_INVALID_ARG;
+	}
+
+	err = mhu_v3_x_get_num_channel_implemented(dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	do {
+		err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	} while (read_val != value);
+
+	return error_mapping_to_mhu_error_t(err);
+}
+
+static enum mhu_error_t clear_and_wait_for_signal(
+	void *mhu_receiver_dev, uint32_t value)
+{
+	enum mhu_v3_x_error_t err;
+	struct mhu_v3_x_dev_t *dev;
+	uint8_t num_channels;
+
+	dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev;
+
+	if ((dev == NULL) || (dev->base == 0)) {
+		return MHU_ERR_INVALID_ARG;
+	}
+
+	err = mhu_v3_x_get_num_channel_implemented(dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/* Clear all channels */
+	for (int i = 0; i < num_channels; i++) {
+		err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	}
+
+	return wait_for_signal(mhu_receiver_dev, value);
+}
+
+static enum mhu_error_t validate_buffer_params(uintptr_t buf_addr)
+{
+	if ((buf_addr == 0) || (!IS_ALIGNED(buf_addr, sizeof(uint32_t)))) {
+		return MHU_ERR_INVALID_ARG;
+	}
+
+	return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base)
+{
+	enum mhu_v3_x_error_t err;
+	struct mhu_v3_x_dev_t *dev;
+	uint8_t num_ch;
+	uint32_t ch;
+
+	assert(mhu_sender_base != (uintptr_t)NULL);
+
+	mhu_hse_dev.base = mhu_sender_base;
+	dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev;
+
+	/* Initialize MHUv3 */
+	err = mhu_v3_x_driver_init(dev);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/* Read the number of doorbell channels implemented in the MHU */
+	err = mhu_v3_x_get_num_channel_implemented(
+		dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	} else if (num_ch < 2) {
+		/* This wrapper requires at least two channels implemented */
+		return MHU_ERR_UNSUPPORTED;
+	}
+
+	/*
+	 * The sender polls the postbox doorbell channel window status register
+	 * to get notified about successful transfer. So, disable the doorbell
+	 * channel's contribution to postbox combined interrupt.
+	 *
+	 * Also, clear and disable the postbox doorbell channel transfer
+	 * acknowledge interrupt.
+	 */
+	for (ch = 0; ch < num_ch; ch++) {
+		err = mhu_v3_x_channel_interrupt_disable(
+			dev, ch, MHU_V3_X_CHANNEL_TYPE_DBCH);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	}
+
+	return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base)
+{
+	enum mhu_v3_x_error_t err;
+	struct mhu_v3_x_dev_t *dev;
+	uint32_t ch;
+	uint8_t num_ch;
+
+	assert(mhu_receiver_base != (uintptr_t)NULL);
+
+	mhu_seh_dev.base = mhu_receiver_base;
+	dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev;
+
+	/* Initialize MHUv3 */
+	err = mhu_v3_x_driver_init(dev);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/* Read the number of doorbell channels implemented in the MHU */
+	err = mhu_v3_x_get_num_channel_implemented(
+		dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	} else if (num_ch < 2) {
+		/* This wrapper requires at least two channels implemented */
+		return MHU_ERR_UNSUPPORTED;
+	}
+
+	/* Mask all channels except the notifying channel */
+	for (ch = 0; ch < (num_ch - 1); ch++) {
+		/* Mask interrupts on channels used for data */
+		err = mhu_v3_x_doorbell_mask_set(dev, ch, UINT32_MAX);
+		if (err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(err);
+		}
+	}
+
+	/* Unmask doorbell notification channel interrupt */
+	err = mhu_v3_x_doorbell_mask_clear(dev, (num_ch - 1), UINT32_MAX);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	/*
+	 * Enable the doorbell channel's contribution to mailbox combined
+	 * interrupt.
+	 */
+	err = mhu_v3_x_channel_interrupt_enable(dev, (num_ch - 1),
+			MHU_V3_X_CHANNEL_TYPE_DBCH);
+	if (err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(err);
+	}
+
+	return MHU_ERR_NONE;
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of transferring a message:
+ * 1. Send the size of the payload on Channel 0. It is the very first Bytes of
+ *    the transfer. Continue with Channel 1.
+ * 2. Send the payload, writing the channels one after the other (4 Bytes
+ *    each). The last available channel is reserved for controlling the
+ *    transfer. When the last channel is reached or no more data is left, STOP.
+ * 3. Notify the receiver using the last channel and wait for acknowledge. If
+ *    there is still data to transfer, jump to step 2. Otherwise, proceed.
+ *
+ */
+enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size)
+{
+	enum mhu_error_t mhu_err;
+	enum mhu_v3_x_error_t mhu_v3_err;
+	uint8_t num_channels;
+	uint8_t chan;
+	uint32_t *buffer;
+	struct mhu_v3_x_dev_t *dev;
+
+	if (size == 0) {
+		return MHU_ERR_NONE;
+	}
+
+	dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev;
+	chan = 0;
+
+	if ((dev == NULL) || (dev->base == 0)) {
+		return MHU_ERR_INVALID_ARG;
+	}
+
+	mhu_err = validate_buffer_params((uintptr_t)send_buffer);
+	if (mhu_err != MHU_ERR_NONE) {
+		return mhu_err;
+	}
+
+	mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+	if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(mhu_v3_err);
+	}
+
+	/* First send the size of the actual message. */
+	mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, (uint32_t)size);
+	if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(mhu_v3_err);
+	}
+	chan++;
+
+	buffer = (uint32_t *)send_buffer;
+	for (size_t i = 0; i < size; i += 4) {
+		mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, *buffer++);
+		if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(mhu_v3_err);
+		}
+
+		if (++chan == (num_channels - 1)) {
+			/* Use the last channel to notify transfer complete */
+			mhu_err = signal_and_wait_for_clear(
+				dev, MHU_NOTIFY_VALUE);
+			if (mhu_err != MHU_ERR_NONE) {
+				return mhu_err;
+			}
+			chan = 0;
+		}
+	}
+
+	if (chan != 0) {
+		/* Use the last channel to notify transfer complete */
+		mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+		if (mhu_err != MHU_ERR_NONE) {
+			return mhu_err;
+		}
+	}
+
+	return MHU_ERR_NONE;
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of receiving a message:
+ * 1. Read the size of the payload from Channel 0. It is the very first
+ *    4 Bytes of the transfer. Continue with Channel 1.
+ * 2. Receive the payload, read the channels one after the other
+ *    (4 Bytes each). The last available channel is reserved for controlling
+ *    the transfer.
+ *    When the last channel is reached clear all the channels
+ *    (also sending an acknowledge on the last channel).
+ * 3. If there is still data to receive wait for a notification on the last
+ *    channel and jump to step 2 as soon as it arrived. Otherwise, proceed.
+ *
+ */
+enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size)
+{
+	enum mhu_error_t mhu_err;
+	enum mhu_v3_x_error_t mhu_v3_err;
+	uint32_t msg_len;
+	uint8_t num_channels;
+	uint8_t chan;
+	uint32_t *buffer;
+	struct mhu_v3_x_dev_t *dev;
+
+	dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev;
+	chan = 0;
+
+	mhu_err = validate_buffer_params((uintptr_t)receive_buffer);
+	if (mhu_err != MHU_ERR_NONE) {
+		return mhu_err;
+	}
+
+	mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+	if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(mhu_v3_err);
+	}
+
+	/* Busy wait for incoming reply */
+	mhu_err = wait_for_signal(dev, MHU_NOTIFY_VALUE);
+	if (mhu_err != MHU_ERR_NONE) {
+		return mhu_err;
+	}
+
+	/* The first word is the length of the actual message. */
+	mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, &msg_len);
+	if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+		return error_mapping_to_mhu_error_t(mhu_v3_err);
+	}
+	chan++;
+
+	if (*size < msg_len) {
+		/* Message buffer too small */
+		*size = msg_len;
+		return MHU_ERR_BUFFER_TOO_SMALL;
+	}
+
+	buffer = (uint32_t *)receive_buffer;
+	for (size_t i = 0; i < msg_len; i += 4) {
+		mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, buffer++);
+		if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(mhu_v3_err);
+		}
+
+		/* Only wait for next transfer if still missing data. */
+		if (++chan == (num_channels - 1) && (msg_len - i) > 4) {
+			/* Busy wait for next transfer */
+			mhu_err = clear_and_wait_for_signal(
+				dev, MHU_NOTIFY_VALUE);
+			if (mhu_err != MHU_ERR_NONE) {
+				return mhu_err;
+			}
+			chan = 0;
+		}
+	}
+
+	/* Clear all channels */
+	for (uint8_t i = U(0); i < num_channels; i++) {
+		mhu_v3_err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX);
+		if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+			return error_mapping_to_mhu_error_t(mhu_v3_err);
+		}
+	}
+
+	*size = msg_len;
+
+	return MHU_ERR_NONE;
+}
+
+size_t mhu_get_max_message_size(void)
+{
+	enum mhu_v3_x_error_t err;
+	uint8_t num_channels;
+
+	err = mhu_v3_x_get_num_channel_implemented(&mhu_seh_dev,
+			MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+
+	assert(err == MHU_V_3_X_ERR_NONE);
+	assert(num_channels != U(0));
+	/*
+	 * Returns only usable size of memory. As one channel is specifically
+	 * used to inform about the size of payload, discard it from available
+	 * memory size.
+	 */
+	return (num_channels - 1) * sizeof(uint32_t);
+}
diff --git a/drivers/arm/rss/rss_comms.mk b/drivers/arm/rss/rss_comms.mk
index c1c994b..0d1e308 100644
--- a/drivers/arm/rss/rss_comms.mk
+++ b/drivers/arm/rss/rss_comms.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2022, Arm Limited. All rights reserved.
+# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -13,10 +13,22 @@
 					rss_comms_protocol_pointer_access.c	\
 				)
 
+# Default to MHUv2 if PLAT_MHU_VERSION undefined
+PLAT_MHU_VERSION ?= 2
+
+ifeq (${PLAT_MHU_VERSION}, 3)
+RSS_COMMS_SOURCES	+=	$(addprefix drivers/arm/mhu/,			\
+					mhu_v3_x.c				\
+					mhu_wrapper_v3_x.c			\
+				)
+else ifeq (${PLAT_MHU_VERSION}, 2)
 RSS_COMMS_SOURCES	+=	$(addprefix drivers/arm/mhu/,			\
 					mhu_v2_x.c				\
 					mhu_wrapper_v2_x.c			\
 				)
+else
+$(error Unsupported MHU version)
+endif
 
 PLAT_INCLUDES		+=	-Idrivers/arm/rss		\
 				-Idrivers/arm/mhu
diff --git a/drivers/rpi3/rng/rpi3_rng.c b/drivers/rpi3/rng/rpi3_rng.c
index b6bf005..16733e1 100644
--- a/drivers/rpi3/rng/rpi3_rng.c
+++ b/drivers/rpi3/rng/rpi3_rng.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,19 @@
 
 #include <rpi_hw.h>
 
+#define RPI3_RNG_CTRL_OFFSET		ULL(0x00000000)
+#define RPI3_RNG_STATUS_OFFSET		ULL(0x00000004)
+#define RPI3_RNG_DATA_OFFSET		ULL(0x00000008)
+#define RPI3_RNG_INT_MASK_OFFSET	ULL(0x00000010)
+/* Enable/disable RNG */
+#define RPI3_RNG_CTRL_ENABLE		U(0x1)
+#define RPI3_RNG_CTRL_DISABLE		U(0x0)
+/* Number of currently available words */
+#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT	U(24)
+#define RPI3_RNG_STATUS_NUM_WORDS_MASK	U(0xFF)
+/* Value to mask interrupts caused by the RNG */
+#define RPI3_RNG_INT_MASK_DISABLE	U(0x1)
+
 /* Initial amount of values to discard */
 #define RNG_WARMUP_COUNT	U(0x40000)
 
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index c9c3c5f..818fd85 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2024, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  */
@@ -2326,6 +2326,17 @@
 }
 #endif /* STM32MP_SHARED_RESOURCES */
 
+void stm32mp1_clk_mcuss_protect(bool enable)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	if (enable) {
+		mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+	} else {
+		mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+	}
+}
+
 static void sync_earlyboot_clocks_state(void)
 {
 	unsigned int idx;
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
index 734a6b5..b52e4d0 100644
--- a/include/arch/aarch32/arch_features.h
+++ b/include/arch/aarch32/arch_features.h
@@ -159,7 +159,6 @@
 static inline bool is_feat_spe_supported(void) { return false; }
 static inline bool is_feat_rng_supported(void) { return false; }
 static inline bool is_feat_gcs_supported(void) { return false; }
-static inline bool is_feat_mte_supported(void) { return false; }
 static inline bool is_feat_mte2_supported(void) { return false; }
 static inline bool is_feat_mpam_supported(void) { return false; }
 static inline bool is_feat_hcx_supported(void) { return false; }
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index de59d45..7582fc6 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -105,6 +105,10 @@
 	return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_MTE_SHIFT) &
 		ID_AA64PFR1_EL1_MTE_MASK);
 }
+static inline unsigned int is_feat_mte2_present(void)
+{
+	return get_armv8_5_mte_support() >= MTE_IMPLEMENTED_ELX;
+}
 
 static inline bool is_feat_ssbs_present(void)
 {
@@ -136,18 +140,14 @@
 		ID_AA64DFR0_SEBEP_MASK) == SEBEP_IMPLEMENTED;
 }
 
-CREATE_FEATURE_FUNCS(feat_mte, id_aa64pfr1_el1, ID_AA64PFR1_EL1_MTE_SHIFT,
-		     ENABLE_FEAT_MTE)
-CREATE_FEATURE_FUNCS_VER(feat_mte2, read_feat_mte_id_field, MTE_IMPLEMENTED_ELX,
-		     ENABLE_FEAT_MTE2)
+CREATE_FEATURE_FUNCS_VER(feat_mte2, get_armv8_5_mte_support, MTE_IMPLEMENTED_ELX,
+			 ENABLE_FEAT_MTE2)
 CREATE_FEATURE_FUNCS(feat_sel2, id_aa64pfr0_el1, ID_AA64PFR0_SEL2_SHIFT,
 		     ENABLE_FEAT_SEL2)
 CREATE_FEATURE_FUNCS(feat_twed, id_aa64mmfr1_el1, ID_AA64MMFR1_EL1_TWED_SHIFT,
 		     ENABLE_FEAT_TWED)
 CREATE_FEATURE_FUNCS(feat_fgt, id_aa64mmfr0_el1, ID_AA64MMFR0_EL1_FGT_SHIFT,
 		     ENABLE_FEAT_FGT)
-CREATE_FEATURE_FUNCS(feat_mte_perm, id_aa64pfr2_el1,
-		     ID_AA64PFR2_EL1_MTEPERM_SHIFT, ENABLE_FEAT_MTE_PERM)
 CREATE_FEATURE_FUNCS(feat_ecv, id_aa64mmfr0_el1, ID_AA64MMFR0_EL1_ECV_SHIFT,
 		     ENABLE_FEAT_ECV)
 CREATE_FEATURE_FUNCS_VER(feat_ecv_v2, read_feat_ecv_id_field,
diff --git a/include/drivers/rpi3/mailbox/rpi3_mbox.h b/include/drivers/rpi3/mailbox/rpi3_mbox.h
index c107440..33458e3 100644
--- a/include/drivers/rpi3/mailbox/rpi3_mbox.h
+++ b/include/drivers/rpi3/mailbox/rpi3_mbox.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -16,6 +16,22 @@
 	uint32_t	tags[0];
 } rpi3_mbox_request_t;
 
+/* VideoCore -> ARM */
+#define RPI3_MBOX0_READ_OFFSET		ULL(0x00000000)
+#define RPI3_MBOX0_PEEK_OFFSET		ULL(0x00000010)
+#define RPI3_MBOX0_SENDER_OFFSET	ULL(0x00000014)
+#define RPI3_MBOX0_STATUS_OFFSET	ULL(0x00000018)
+#define RPI3_MBOX0_CONFIG_OFFSET	ULL(0x0000001C)
+/* ARM -> VideoCore */
+#define RPI3_MBOX1_WRITE_OFFSET		ULL(0x00000020)
+#define RPI3_MBOX1_PEEK_OFFSET		ULL(0x00000030)
+#define RPI3_MBOX1_SENDER_OFFSET	ULL(0x00000034)
+#define RPI3_MBOX1_STATUS_OFFSET	ULL(0x00000038)
+#define RPI3_MBOX1_CONFIG_OFFSET	ULL(0x0000003C)
+/* Mailbox status constants */
+#define RPI3_MBOX_STATUS_FULL_MASK	U(0x80000000) /* Set if full */
+#define RPI3_MBOX_STATUS_EMPTY_MASK	U(0x40000000) /* Set if empty */
+
 #define RPI3_MBOX_BUFFER_SIZE		U(256)
 
 /* Constants to perform a request/check the status of a request. */
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
index e2395bc..93ec1c5 100644
--- a/include/drivers/st/stm32mp1_clk.h
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2018-2024, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -32,6 +32,8 @@
 void stm32mp1_clk_rcc_regs_lock(void);
 void stm32mp1_clk_rcc_regs_unlock(void);
 
+void stm32mp1_clk_mcuss_protect(bool enable);
+
 #ifdef STM32MP_SHARED_RESOURCES
 void stm32mp1_register_clock_parents_secure(unsigned long id);
 #endif
diff --git a/include/lib/cpus/aarch64/cortex_a720.h b/include/lib/cpus/aarch64/cortex_a720.h
index 47bbbc0..fb27f79 100644
--- a/include/lib/cpus/aarch64/cortex_a720.h
+++ b/include/lib/cpus/aarch64/cortex_a720.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,16 @@
 #define CORTEX_A720_BHB_LOOP_COUNT				U(132)
 
 /*******************************************************************************
+ * CPU Auxiliary Control register 1 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A720_CPUACTLR_EL1				S3_0_C15_C1_0
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A720_CPUACTLR2_EL1				S3_0_C15_C1_1
+
+/*******************************************************************************
  * CPU Extended Control register specific definitions
  ******************************************************************************/
 #define CORTEX_A720_CPUECTLR_EL1				S3_0_C15_C1_4
diff --git a/include/lib/cpus/aarch64/neoverse_poseidon.h b/include/lib/cpus/aarch64/neoverse_poseidon.h
deleted file mode 100644
index 117826d..0000000
--- a/include/lib/cpus/aarch64/neoverse_poseidon.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef NEOVERSE_POSEIDON_H
-#define NEOVERSE_POSEIDON_H
-
-
-#define NEOVERSE_POSEIDON_VNAE_MIDR				U(0x410FD830)
-#define NEOVERSE_POSEIDON_V_MIDR				U(0x410FD840)
-
-/* Neoverse Poseidon loop count for CVE-2022-23960 mitigation */
-#define NEOVERSE_POSEIDON_BHB_LOOP_COUNT			U(132)
-
-/*******************************************************************************
- * CPU Extended Control register specific definitions.
- ******************************************************************************/
-#define NEOVERSE_POSEIDON_CPUECTLR_EL1				S3_0_C15_C1_4
-
-/*******************************************************************************
- * CPU Power Control register specific definitions
- ******************************************************************************/
-#define NEOVERSE_POSEIDON_CPUPWRCTLR_EL1			S3_0_C15_C2_7
-#define NEOVERSE_POSEIDON_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
-
-#endif /* NEOVERSE_POSEIDON_H */
diff --git a/include/lib/cpus/aarch64/neoverse_v3.h b/include/lib/cpus/aarch64/neoverse_v3.h
new file mode 100644
index 0000000..e5f75ba
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_v3.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_V3_H
+#define NEOVERSE_V3_H
+
+
+#define NEOVERSE_V3_VNAE_MIDR				U(0x410FD830)
+#define NEOVERSE_V3_MIDR				U(0x410FD840)
+
+/* Neoverse V3 loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_V3_BHB_LOOP_COUNT			U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_V3_CPUECTLR_EL1				S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_V3_CPUPWRCTLR_EL1			S3_0_C15_C2_7
+#define NEOVERSE_V3_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
+
+#endif /* NEOVERSE_V3_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 44efee5..fbaa008 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -141,7 +141,7 @@
 #define CTX_TIMER_SYSREGS_END	CTX_AARCH32_END
 #endif /* NS_TIMER_SWITCH */
 
-#if ENABLE_FEAT_MTE
+#if ENABLE_FEAT_MTE2
 #define CTX_TFSRE0_EL1		(CTX_TIMER_SYSREGS_END + U(0x0))
 #define CTX_TFSR_EL1		(CTX_TIMER_SYSREGS_END + U(0x8))
 #define CTX_RGSR_EL1		(CTX_TIMER_SYSREGS_END + U(0x10))
@@ -151,7 +151,7 @@
 #define CTX_MTE_REGS_END	(CTX_TIMER_SYSREGS_END + U(0x20))
 #else
 #define CTX_MTE_REGS_END	CTX_TIMER_SYSREGS_END
-#endif /* ENABLE_FEAT_MTE */
+#endif /* ENABLE_FEAT_MTE2 */
 
 /*
  * End of system registers.
diff --git a/include/plat/nuvoton/common/npcm845x_arm_def.h b/include/plat/nuvoton/common/npcm845x_arm_def.h
index 5a44907..df3ad24 100644
--- a/include/plat/nuvoton/common/npcm845x_arm_def.h
+++ b/include/plat/nuvoton/common/npcm845x_arm_def.h
@@ -149,7 +149,16 @@
 			ARM_AP_TZC_DRAM1_SIZE - 1U)
 
 /* Define the Access permissions for Secure peripherals to NS_DRAM */
+#if ARM_CRYPTOCELL_INTEG
+/*
+ * Allow Secure peripheral to read NS DRAM when integrated with CryptoCell.
+ * This is required by CryptoCell to authenticate BL33 which is loaded
+ * into the Non Secure DDR.
+ */
+#define ARM_TZC_NS_DRAM_S_ACCESS	TZC_REGION_S_RD
+#else
 #define ARM_TZC_NS_DRAM_S_ACCESS	TZC_REGION_S_NONE
+#endif /* ARM_CRYPTOCELL_INTEG */
 
 #ifdef SPD_opteed
 /*
@@ -310,7 +319,7 @@
 			BL_RO_DATA_END - BL_RO_DATA_BASE,	\
 			MT_RO_DATA | EL3_PAS)
 #else
-#define ARM_MAP_BL_RO		MAP_REGION_FLAT(	\
+#define ARM_MAP_BL_RO_NOT_USED		MAP_REGION_FLAT(	\
 			BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,	\
 			MT_CODE | EL3_PAS)
 #endif /* SEPARATE_CODE_AND_RODATA */
@@ -474,9 +483,9 @@
 #define NEW_SRAM_ALLOCATION
 
 #ifdef NEW_SRAM_ALLOCATION
-	#define BL31_BASE				0x20001000
+	#define BL31_BASE				0x02000000
 #else
-	#define BL31_BASE				0x20001000
+	#define BL31_BASE				0x02001000
 #endif /* NEW_SRAM_ALLOCATION */
 
 #define BL31_LIMIT			BL2_BASE	/* PLAT_ARM_MAX_BL31_SIZE */
@@ -502,6 +511,7 @@
  * no SPD and no SPM-MM, as they are the only ones that can be used as BL32.
  */
 #if defined(SPD_none) && !SPM_MM
+#error BL32_BASE is not defined
 #undef BL32_BASE
 #endif /* SPD_none && !SPM_MM */
 
diff --git a/include/plat/nuvoton/common/plat_macros.S b/include/plat/nuvoton/common/plat_macros.S
index 08f9feb..549db39 100644
--- a/include/plat/nuvoton/common/plat_macros.S
+++ b/include/plat/nuvoton/common/plat_macros.S
@@ -41,7 +41,8 @@
  * BL31.
  */
 .macro plat_crash_print_regs
-	/* TODO */
+plat_print_gic_regs
+/*print_cci_regs*/
 .endm
 
 #endif /* PLAT_MACROS_S */
diff --git a/lib/cpus/aarch64/cortex_a715.S b/lib/cpus/aarch64/cortex_a715.S
index abd649c..a5be22d 100644
--- a/lib/cpus/aarch64/cortex_a715.S
+++ b/lib/cpus/aarch64/cortex_a715.S
@@ -60,15 +60,18 @@
 
 check_erratum_ls cortex_a715, ERRATUM(2344187), CPU_REV(1, 0)
 
-/* Errata applies only when Static profiling extension is enabled. */
 workaround_reset_start cortex_a715, ERRATUM(2413290), ERRATA_A715_2413290
-	/* Apply the workaround by setting CPUACTLR_EL1[58:57] = 0b11. */
+/* Erratum 2413290 workaround is required only if SPE is enabled */
+#if ENABLE_SPE_FOR_NS != 0
+	/* Check if Static profiling extension is implemented or present. */
 	mrs x1, id_aa64dfr0_el1
 	ubfx x0, x1, ID_AA64DFR0_PMS_SHIFT, #4
 	cbz x0, 1f
+	/* Apply the workaround by setting CPUACTLR_EL1[58:57] = 0b11. */
 	sysreg_bit_set CORTEX_A715_CPUACTLR_EL1, BIT(57)
 	sysreg_bit_set CORTEX_A715_CPUACTLR_EL1, BIT(58)
 1:
+#endif
 workaround_reset_end cortex_a715, ERRATUM(2413290)
 
 check_erratum_range cortex_a715, ERRATUM(2413290), CPU_REV(1,0), CPU_REV(1, 0)
diff --git a/lib/cpus/aarch64/cortex_a720.S b/lib/cpus/aarch64/cortex_a720.S
index 4b28fdb..53a1b78 100644
--- a/lib/cpus/aarch64/cortex_a720.S
+++ b/lib/cpus/aarch64/cortex_a720.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,6 +26,28 @@
         wa_cve_2022_23960_bhb_vector_table CORTEX_A720_BHB_LOOP_COUNT, cortex_a720
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+workaround_reset_start cortex_a720, ERRATUM(2926083), ERRATA_A720_2926083
+/* Erratum 2926083 workaround is required only if SPE is enabled */
+#if ENABLE_SPE_FOR_NS != 0
+	/* Check if Static profiling extension is implemented or present. */
+	mrs x1, id_aa64dfr0_el1
+	ubfx x0, x1, ID_AA64DFR0_PMS_SHIFT, #4
+	cbz x0, 1f
+	/* Apply the workaround by setting CPUACTLR_EL1[58:57] = 0b11. */
+	sysreg_bit_set CORTEX_A720_CPUACTLR_EL1, BIT(57)
+	sysreg_bit_set CORTEX_A720_CPUACTLR_EL1, BIT(58)
+1:
+#endif
+workaround_reset_end cortex_a720, ERRATUM(2926083)
+
+check_erratum_ls cortex_a720, ERRATUM(2926083), CPU_REV(0, 1)
+
+workaround_reset_start cortex_a720, ERRATUM(2940794), ERRATA_A720_2940794
+        sysreg_bit_set CORTEX_A720_CPUACTLR2_EL1, BIT(37)
+workaround_reset_end cortex_a720, ERRATUM(2940794)
+
+check_erratum_ls cortex_a720, ERRATUM(2940794), CPU_REV(0, 1)
+
 workaround_reset_start cortex_a720, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
diff --git a/lib/cpus/aarch64/neoverse_poseidon.S b/lib/cpus/aarch64/neoverse_poseidon.S
deleted file mode 100644
index 54c2ff9..0000000
--- a/lib/cpus/aarch64/neoverse_poseidon.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <asm_macros.S>
-#include <common/bl_common.h>
-#include <neoverse_poseidon.h>
-#include <cpu_macros.S>
-#include <plat_macros.S>
-#include "wa_cve_2022_23960_bhb_vector.S"
-
-/* Hardware handled coherency */
-#if HW_ASSISTED_COHERENCY == 0
-#error "Neoverse Poseidon must be compiled with HW_ASSISTED_COHERENCY enabled"
-#endif
-
-/* 64-bit only core */
-#if CTX_INCLUDE_AARCH32_REGS == 1
-#error "Neoverse Poseidon supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
-#endif
-
-#if WORKAROUND_CVE_2022_23960
-	wa_cve_2022_23960_bhb_vector_table NEOVERSE_POSEIDON_BHB_LOOP_COUNT, neoverse_poseidon
-#endif /* WORKAROUND_CVE_2022_23960 */
-
-workaround_reset_start neoverse_poseidon, CVE(2022,23960), WORKAROUND_CVE_2022_23960
-#if IMAGE_BL31
-	/*
-	 * The Neoverse-poseidon generic vectors are overridden to apply errata
-         * mitigation on exception entry from lower ELs.
-	 */
-	override_vector_table wa_cve_vbar_neoverse_poseidon
-
-#endif /* IMAGE_BL31 */
-workaround_reset_end neoverse_poseidon, CVE(2022,23960)
-
-check_erratum_chosen neoverse_poseidon, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
-
-	/* ---------------------------------------------
-	 * HW will do the cache maintenance while powering down
-	 * ---------------------------------------------
-	 */
-func neoverse_poseidon_core_pwr_dwn
-	/* ---------------------------------------------
-	 * Enable CPU power down bit in power control register
-	 * ---------------------------------------------
-	 */
-	sysreg_bit_set NEOVERSE_POSEIDON_CPUPWRCTLR_EL1, \
-		NEOVERSE_POSEIDON_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
-
-	isb
-	ret
-endfunc neoverse_poseidon_core_pwr_dwn
-
-cpu_reset_func_start neoverse_poseidon
-	/* Disable speculative loads */
-	msr	SSBS, xzr
-cpu_reset_func_end neoverse_poseidon
-
-errata_report_shim neoverse_poseidon
-
-	/* ---------------------------------------------
-	 * This function provides Neoverse-Poseidon specific
-	 * register information for crash reporting.
-	 * It needs to return with x6 pointing to
-	 * a list of register names in ascii and
-	 * x8 - x15 having values of registers to be
-	 * reported.
-	 * ---------------------------------------------
-	 */
-.section .rodata.neoverse_poseidon_regs, "aS"
-neoverse_poseidon_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
-
-func neoverse_poseidon_cpu_reg_dump
-	adr	x6, neoverse_poseidon_regs
-	mrs	x8, NEOVERSE_POSEIDON_CPUECTLR_EL1
-	ret
-endfunc neoverse_poseidon_cpu_reg_dump
-
-declare_cpu_ops neoverse_poseidon, NEOVERSE_POSEIDON_VNAE_MIDR, \
-	neoverse_poseidon_reset_func, \
-	neoverse_poseidon_core_pwr_dwn
-
-declare_cpu_ops neoverse_poseidon, NEOVERSE_POSEIDON_V_MIDR, \
-	neoverse_poseidon_reset_func, \
-	neoverse_poseidon_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_v3.S b/lib/cpus/aarch64/neoverse_v3.S
new file mode 100644
index 0000000..67258c8
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_v3.S
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_v3.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse V3 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse V3 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V3_BHB_LOOP_COUNT, neoverse_v3
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+workaround_reset_start neoverse_v3, CVE(2022,23960), WORKAROUND_CVE_2022_23960
+#if IMAGE_BL31
+	/*
+	 * The Neoverse V3 generic vectors are overridden to apply errata
+         * mitigation on exception entry from lower ELs.
+	 */
+	override_vector_table wa_cve_vbar_neoverse_v3
+
+#endif /* IMAGE_BL31 */
+workaround_reset_end neoverse_v3, CVE(2022,23960)
+
+check_erratum_chosen neoverse_v3, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func neoverse_v3_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	sysreg_bit_set NEOVERSE_V3_CPUPWRCTLR_EL1, \
+		NEOVERSE_V3_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+
+	isb
+	ret
+endfunc neoverse_v3_core_pwr_dwn
+
+cpu_reset_func_start neoverse_v3
+	/* Disable speculative loads */
+	msr	SSBS, xzr
+cpu_reset_func_end neoverse_v3
+
+errata_report_shim neoverse_v3
+
+	/* ---------------------------------------------
+	 * This function provides Neoverse V3 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.neoverse_v3_regs, "aS"
+neoverse_v3_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func neoverse_v3_cpu_reg_dump
+	adr	x6, neoverse_v3_regs
+	mrs	x8, NEOVERSE_V3_CPUECTLR_EL1
+	ret
+endfunc neoverse_v3_cpu_reg_dump
+
+declare_cpu_ops neoverse_v3, NEOVERSE_V3_VNAE_MIDR, \
+	neoverse_v3_reset_func, \
+	neoverse_v3_core_pwr_dwn
+
+declare_cpu_ops neoverse_v3, NEOVERSE_V3_MIDR, \
+	neoverse_v3_reset_func, \
+	neoverse_v3_core_pwr_dwn
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index f5997ae..872f6c7 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -795,7 +795,7 @@
 CPU_FLAG_LIST += ERRATA_X3_2372204
 
 # Flag to apply erratum 2615812 workaround on powerdown. This erratum applies
-# to revisions r0p0, r1p0, r1p1 of the Cortex-X3 cpu, it is still open.
+# to revisions r0p0, r1p0, r1p1 of the Cortex-X3 cpu, it is fixed in r1p2.
 CPU_FLAG_LIST += ERRATA_X3_2615812
 
 # Flag to apply erratum 2641945 workaround on reset. This erratum applies
@@ -940,6 +940,14 @@
 # only to revision r1p0. It is fixed in r1p1.
 CPU_FLAG_LIST += ERRATA_A715_2561034
 
+# Flag to apply erratum 2926083 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_A720_2926083
+
+# Flag to apply erratum 2940794 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_A720_2940794
+
 # Flag to apply DSU erratum 798953. This erratum applies to DSUs revision r0p0.
 # Applying the workaround results in higher DSU power consumption on idle.
 CPU_FLAG_LIST += ERRATA_DSU_798953
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 5c8f03c..7a00e47 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -123,8 +123,8 @@
 	scr_el3 |= get_scr_el3_from_routing_model(SECURE);
 #endif
 
-	/* Allow access to Allocation Tags when mte is set*/
-	if (is_feat_mte_supported()) {
+	/* Allow access to Allocation Tags when FEAT_MTE2 is implemented and enabled. */
+	if (is_feat_mte2_supported()) {
 		scr_el3 |= SCR_ATA_BIT;
 	}
 
@@ -193,8 +193,10 @@
 	/* SCR_NS: Set the NS bit */
 	scr_el3 |= SCR_NS_BIT;
 
-	/* Allow access to Allocation Tags when MTE is implemented. */
-	scr_el3 |= SCR_ATA_BIT;
+	/* Allow access to Allocation Tags when FEAT_MTE2 is implemented and enabled. */
+	if (is_feat_mte2_supported()) {
+		scr_el3 |= SCR_ATA_BIT;
+	}
 
 #if !CTX_INCLUDE_PAUTH_REGS
 	/*
@@ -959,8 +961,8 @@
 		scr_el3 = read_ctx_reg(get_el3state_ctx(ctx),
 						 CTX_SCR_EL3);
 
-		if (((scr_el3 & SCR_HCE_BIT) != 0U)
-			|| (el2_implemented != EL_IMPL_NONE)) {
+		if (el2_implemented != EL_IMPL_NONE) {
+
 			/*
 			 * If context is not being used for EL2, initialize
 			 * HCRX_EL2 with its init value here.
@@ -986,28 +988,32 @@
 				write_hfgrtr_el2(HFGRTR_EL2_INIT_VAL);
 				write_hfgwtr_el2(HFGWTR_EL2_INIT_VAL);
 			}
-		}
 
-		if ((scr_el3 & SCR_HCE_BIT) != 0U) {
-			/* Use SCTLR_EL1.EE value to initialise sctlr_el2 */
-			sctlr_elx = read_ctx_reg(get_el1_sysregs_ctx(ctx),
-							   CTX_SCTLR_EL1);
-			sctlr_elx &= SCTLR_EE_BIT;
-			sctlr_elx |= SCTLR_EL2_RES1;
+			/* Condition to ensure EL2 is being used. */
+			if ((scr_el3 & SCR_HCE_BIT) != 0U) {
+				/* Use SCTLR_EL1.EE value to initialise sctlr_el2 */
+				sctlr_elx = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+								CTX_SCTLR_EL1);
+				sctlr_elx &= SCTLR_EE_BIT;
+				sctlr_elx |= SCTLR_EL2_RES1;
 #if ERRATA_A75_764081
-			/*
-			 * If workaround of errata 764081 for Cortex-A75 is used
-			 * then set SCTLR_EL2.IESB to enable Implicit Error
-			 * Synchronization Barrier.
-			 */
-			sctlr_elx |= SCTLR_IESB_BIT;
-#endif
-			write_sctlr_el2(sctlr_elx);
-		} else if (el2_implemented != EL_IMPL_NONE) {
-			init_nonsecure_el2_unused(ctx);
+				/*
+				 * If workaround of errata 764081 for Cortex-A75
+				 * is used then set SCTLR_EL2.IESB to enable
+				 * Implicit Error Synchronization Barrier.
+				 */
+				sctlr_elx |= SCTLR_IESB_BIT;
+#endif /* ERRATA_A75_764081 */
+				write_sctlr_el2(sctlr_elx);
+			} else {
+				/*
+				 * (scr_el3 & SCR_HCE_BIT==0)
+				 * EL2 implemented but unused.
+				 */
+				init_nonsecure_el2_unused(ctx);
+			}
 		}
 	}
-
 	cm_el1_sysregs_context_restore(security_state);
 	cm_set_next_eret_context(security_state);
 }
@@ -1271,7 +1277,7 @@
 	el2_sysregs_context_save_common(el2_sysregs_ctx);
 	el2_sysregs_context_save_gic(el2_sysregs_ctx);
 
-	if (is_feat_mte_supported()) {
+	if (is_feat_mte2_supported()) {
 		write_el2_ctx_mte(el2_sysregs_ctx, tfsr_el2, read_tfsr_el2());
 	}
 
@@ -1357,7 +1363,7 @@
 	el2_sysregs_context_restore_common(el2_sysregs_ctx);
 	el2_sysregs_context_restore_gic(el2_sysregs_ctx);
 
-	if (is_feat_mte_supported()) {
+	if (is_feat_mte2_supported()) {
 		write_tfsr_el2(read_el2_ctx_mte(el2_sysregs_ctx, tfsr_el2));
 	}
 
@@ -1502,12 +1508,12 @@
 	write_ctx_reg(ctx, CTX_CNTKCTL_EL1, read_cntkctl_el1());
 #endif /* NS_TIMER_SWITCH */
 
-#if ENABLE_FEAT_MTE
+#if ENABLE_FEAT_MTE2
 	write_ctx_reg(ctx, CTX_TFSRE0_EL1, read_tfsre0_el1());
 	write_ctx_reg(ctx, CTX_TFSR_EL1, read_tfsr_el1());
 	write_ctx_reg(ctx, CTX_RGSR_EL1, read_rgsr_el1());
 	write_ctx_reg(ctx, CTX_GCR_EL1, read_gcr_el1());
-#endif /* ENABLE_FEAT_MTE */
+#endif /* ENABLE_FEAT_MTE2 */
 
 }
 
@@ -1557,12 +1563,12 @@
 	write_cntkctl_el1(read_ctx_reg(ctx, CTX_CNTKCTL_EL1));
 #endif /* NS_TIMER_SWITCH */
 
-#if ENABLE_FEAT_MTE
+#if ENABLE_FEAT_MTE2
 	write_tfsre0_el1(read_ctx_reg(ctx, CTX_TFSRE0_EL1));
 	write_tfsr_el1(read_ctx_reg(ctx, CTX_TFSR_EL1));
 	write_rgsr_el1(read_ctx_reg(ctx, CTX_RGSR_EL1));
 	write_gcr_el1(read_ctx_reg(ctx, CTX_GCR_EL1));
-#endif /* ENABLE_FEAT_MTE */
+#endif /* ENABLE_FEAT_MTE2 */
 
 }
 
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index 643d550..ac47960 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -307,27 +307,16 @@
 # registers, by setting SCR_EL3.TRNDR.
 ENABLE_FEAT_RNG_TRAP			?=	0
 
-# Enable Memory Tagging Extension. This must be set to 1 if the platform wants
-# to use this feature in the Secure world and MTE is enabled at ELX.
 ifeq ($(CTX_INCLUDE_MTE_REGS),1)
-        $(warning CTX_INCLUDE_MTE_REGS option is deprecated use ENABLE_FEAT_MTE, Enabling ENABLE_FEAT_MTE)
-        ENABLE_FEAT_MTE                 ?=      1
+        $(warning CTX_INCLUDE_MTE_REGS option is deprecated, Check ENABLE_FEAT_MTE2 usage)
 endif
-ifeq (${ARCH},aarch32)
-        ifneq ($(or $(ENABLE_FEAT_MTE),0),0)
-                $(error ENABLE_FEAT_MTE is not supported for AArch32)
-        endif
+ifeq ($(ENABLE_FEAT_MTE),1)
+        $(warning ENABLE_FEAT_MTE option is deprecated, Check ENABLE_FEAT_MTE2 usage)
 endif
-ENABLE_FEAT_MTE		                ?=	0
-ENABLE_FEAT_MTE2		        ?=	0
-
 
-# Add a error message to indicate incorrect MTE2 selection without MTE enabled.
-ifneq ($(ENABLE_FEAT_MTE2),0)
-        ifeq ($(ENABLE_FEAT_MTE),0)
-               $(error ENABLE_FEAT_MTE2 is not supported without enabling ENABLE_FEAT_MTE)
-        endif
-endif
+# Enable FEAT_MTE2. This must be set to 1 if the platform wants
+# to use this feature and is enabled at ELX.
+ENABLE_FEAT_MTE2		        ?=	0
 
 #----
 # 8.6
@@ -352,9 +341,6 @@
 # 8.9
 #----
 
-# Flag to enable NoTagAccess memory region attribute for stage 2 of translation.
-ENABLE_FEAT_MTE_PERM			?=	0
-
 # Flag to enable access to Stage 2 Permission Indirection (FEAT_S2PIE).
 ENABLE_FEAT_S2PIE			?=	0
 
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 569ac3f..6b995af 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -76,7 +76,6 @@
 ENABLE_FEAT_CSV2_3		:= 2
 ENABLE_FEAT_DIT			:= 2
 ENABLE_FEAT_PAN			:= 2
-ENABLE_FEAT_MTE_PERM		:= 2
 ENABLE_FEAT_VHE			:= 2
 CTX_INCLUDE_NEVE_REGS		:= 2
 ENABLE_FEAT_SEL2		:= 2
@@ -205,6 +204,7 @@
 					lib/cpus/aarch64/cortex_a78c.S		\
 					lib/cpus/aarch64/cortex_a710.S		\
 					lib/cpus/aarch64/cortex_a715.S		\
+					lib/cpus/aarch64/cortex_a720.S		\
 					lib/cpus/aarch64/neoverse_n_common.S	\
 					lib/cpus/aarch64/neoverse_n1.S		\
 					lib/cpus/aarch64/neoverse_n2.S		\
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 2f23d80..b30e40c 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -40,7 +40,6 @@
 
 ifeq (${SPD},spmd)
 	SPMD_SPM_AT_SEL2	:=	1
-	ENABLE_FEAT_MTE		:=	1
 	CTX_INCLUDE_PAUTH_REGS	:=	1
 endif
 
diff --git a/plat/common/aarch64/crash_console_helpers.S b/plat/common/aarch64/crash_console_helpers.S
index 75b4208..1a50091 100644
--- a/plat/common/aarch64/crash_console_helpers.S
+++ b/plat/common/aarch64/crash_console_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -100,7 +100,7 @@
 	 * int plat_crash_console_putc(char c)
 	 * Prints the character on all consoles registered with the console
 	 * framework that have CONSOLE_FLAG_CRASH set. Note that this is only
-	 * helpful for crashes that occur after the platform intialization code
+	 * helpful for crashes that occur after the platform initialization code
 	 * has registered a console. Platforms using this implementation need to
 	 * ensure that all console drivers they use that have the CRASH flag set
 	 * support this (i.e. are written in assembly and comply to the register
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
index dc9dd59..bff8fb4 100644
--- a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
@@ -77,11 +77,31 @@
 
 static const struct imx_csu_cfg csu_cfg[] = {
 	/* peripherals csl setting */
-	CSU_CSLx(0x1, CSU_SEC_LEVEL_0, UNLOCKED),
+	CSU_CSLx(CSU_CSL_RDC, CSU_SEC_LEVEL_3, LOCKED),
+	CSU_CSLx(CSU_CSL_TZASC, CSU_SEC_LEVEL_5, LOCKED),
+	CSU_CSLx(CSU_CSL_CSU, CSU_SEC_LEVEL_5, LOCKED),
 
 	/* master HP0~1 */
 
 	/* SA setting */
+	CSU_SA(CSU_SA_M4, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_PCIE_CTRL1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USB1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USB2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_VPU, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_GPU, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_APBHDMA, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ENET, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC3, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_HUGO, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_DAP, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA3, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_LCDIF, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_CSI, NON_SEC_ACCESS, LOCKED),
 
 	/* HP control setting */
 
diff --git a/plat/imx/imx8m/imx8mm/include/imx_sec_def.h b/plat/imx/imx8m/imx8mm/include/imx_sec_def.h
index 6215983..d53c922 100644
--- a/plat/imx/imx8m/imx8mm/include/imx_sec_def.h
+++ b/plat/imx/imx8m/imx8mm/include/imx_sec_def.h
@@ -213,4 +213,26 @@
 	CSU_CSL_CAAM = 114,
 };
 
+enum csu_sa_idx {
+	CSU_SA_M4 = 1,
+	CSU_SA_SDMA1 = 2,
+	CSU_SA_PCIE_CTRL1 = 3,
+	CSU_SA_USB1 = 4,
+	CSU_SA_USB2 = 5,
+	CSU_SA_VPU = 6,
+	CSU_SA_GPU = 7,
+	CSU_SA_APBHDMA = 8,
+	CSU_SA_ENET = 9,
+	CSU_SA_USDHC1 = 10,
+	CSU_SA_USDHC2 = 11,
+	CSU_SA_USDHC3 = 12,
+	CSU_SA_HUGO = 13,
+	CSU_SA_DAP = 14,
+	CSU_SA_SDMA2 = 15,
+	CSU_SA_CAAM = 16,
+	CSU_SA_SDMA3 = 17,
+	CSU_SA_LCDIF = 18,
+	CSU_SA_CSI = 19,
+};
+
 #endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mn/include/imx_sec_def.h b/plat/imx/imx8m/imx8mn/include/imx_sec_def.h
index 0ef14a9..83c5fa9 100644
--- a/plat/imx/imx8m/imx8mn/include/imx_sec_def.h
+++ b/plat/imx/imx8m/imx8mn/include/imx_sec_def.h
@@ -207,4 +207,23 @@
 	CSU_CSL_OCRAM_S = 119,
 };
 
+enum csu_sa_idx {
+	CSU_SA_M7 = 1,
+	CSU_SA_SDMA1 = 2,
+	CSU_SA_USB1 = 4,
+	CSU_SA_GPU = 7,
+	CSU_SA_APBHDMA = 8,
+	CSU_SA_ENET1 = 9,
+	CSU_SA_USDHC1 = 10,
+	CSU_SA_USDHC2 = 11,
+	CSU_SA_USDHC3 = 12,
+	CSU_SA_HUGO = 13,
+	CSU_SA_DAP = 14,
+	CSU_SA_SDMA2 = 15,
+	CSU_SA_CAAM = 16,
+	CSU_SA_SDMA3 = 17,
+	CSU_SA_LCDIF = 18,
+	CSU_SA_ISI = 19,
+};
+
 #endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
index 43fa064..8e35219 100644
--- a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
@@ -63,12 +63,45 @@
 
 static const struct imx_csu_cfg csu_cfg[] = {
 	/* peripherals csl setting */
-	CSU_CSLx(CSU_CSL_OCRAM, CSU_SEC_LEVEL_2, UNLOCKED),
-	CSU_CSLx(CSU_CSL_OCRAM_S, CSU_SEC_LEVEL_2, UNLOCKED),
+	CSU_CSLx(CSU_CSL_OCRAM, CSU_SEC_LEVEL_2, LOCKED),
+	CSU_CSLx(CSU_CSL_OCRAM_S, CSU_SEC_LEVEL_2, LOCKED),
+	CSU_CSLx(CSU_CSL_RDC, CSU_SEC_LEVEL_3, LOCKED),
+	CSU_CSLx(CSU_CSL_TZASC, CSU_SEC_LEVEL_5, LOCKED),
+	CSU_CSLx(CSU_CSL_CSU, CSU_SEC_LEVEL_5, LOCKED),
 
 	/* master HP0~1 */
 
 	/* SA setting */
+	CSU_SA(CSU_SA_M7, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_PCIE_CTRL1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USB1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USB2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_APB_HDMA, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ENET1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_USDHC3, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_HUGO, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_DAP, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_SDMA3, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_LCDIF1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ISI, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_NPU, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_LCDIF2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_HDMI_TX, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ENET2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_GPU3D, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_GPU2D, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_VPU_G1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_VPU_G2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_VPU_VC8000E, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_AUDIO_EDMA, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ISP1, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_ISP2, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_DEWARP, NON_SEC_ACCESS, LOCKED),
+	CSU_SA(CSU_SA_GIC500, NON_SEC_ACCESS, LOCKED),
 
 	/* HP control setting */
 
diff --git a/plat/imx/imx8m/imx8mp/include/imx_sec_def.h b/plat/imx/imx8m/imx8mp/include/imx_sec_def.h
index ba248b5..1ba3033 100644
--- a/plat/imx/imx8m/imx8mp/include/imx_sec_def.h
+++ b/plat/imx/imx8m/imx8mp/include/imx_sec_def.h
@@ -269,6 +269,41 @@
 	CSU_CSL_OCRAM_A = 113,
 	CSU_CSL_OCRAM = 118,
 	CSU_CSL_OCRAM_S = 119,
+	CSU_CSL_VPU = 120,
+};
+
+enum csu_sa_idx {
+	CSU_SA_M7 = 1,
+	CSU_SA_SDMA1 = 2,
+	CSU_SA_PCIE_CTRL1 = 3,
+	CSU_SA_USB1 = 4,
+	CSU_SA_USB2 = 6,
+	CSU_SA_APB_HDMA = 8,
+	CSU_SA_ENET1 = 9,
+	CSU_SA_USDHC1 = 10,
+	CSU_SA_USDHC2 = 11,
+	CSU_SA_USDHC3 = 12,
+	CSU_SA_HUGO = 13,
+	CSU_SA_DAP = 14,
+	CSU_SA_SDMA2 = 15,
+	CSU_SA_CAAM = 16,
+	CSU_SA_SDMA3 = 17,
+	CSU_SA_LCDIF1 = 18,
+	CSU_SA_ISI = 19,
+	CSU_SA_NPU = 20,
+	CSU_SA_LCDIF2 = 21,
+	CSU_SA_HDMI_TX = 22,
+	CSU_SA_ENET2 = 23,
+	CSU_SA_GPU3D = 24,
+	CSU_SA_GPU2D = 25,
+	CSU_SA_VPU_G1 = 26,
+	CSU_SA_VPU_G2 = 27,
+	CSU_SA_VPU_VC8000E = 28,
+	CSU_SA_AUDIO_EDMA = 29,
+	CSU_SA_ISP1 = 30,
+	CSU_SA_ISP2 = 31,
+	CSU_SA_DEWARP = 32,
+	CSU_SA_GIC500 = 33,
 };
 
 #endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/include/imx8m_csu.h b/plat/imx/imx8m/include/imx8m_csu.h
index dc634ed..3851e91 100644
--- a/plat/imx/imx8m/include/imx8m_csu.h
+++ b/plat/imx/imx8m/include/imx8m_csu.h
@@ -20,6 +20,9 @@
 #define CSU_SEC_LEVEL_6		0x03
 #define CSU_SEC_LEVEL_7		0x0
 
+#define SEC_ACCESS		0x0
+#define NON_SEC_ACCESS		0x1
+
 #define LOCKED			0x1
 #define UNLOCKED		0x0
 
@@ -27,11 +30,11 @@
 #define CSLx_LOCK(x)		((0x1 << (((x) % 2) * 16 + 8)))
 #define CSLx_CFG(x, n)		((x) << (((n) % 2) * 16))
 
-#define CSU_HP_REG(x)		(IMX_CSU_BASE + ((x) / 16) * 4 + 0x200)
+#define CSU_HP_REG(x)		(IMX_CSU_BASE + (((x) / 16) * 4) + 0x200)
 #define CSU_HP_LOCK(x)		((0x1 << (((x) % 16) * 2 + 1)))
 #define CSU_HP_CFG(x, n)	((x) << (((n) % 16) * 2))
 
-#define CSU_SA_REG(x)		(IMX_CSU_BASE + 0x218)
+#define CSU_SA_REG(x)		(IMX_CSU_BASE + (((x) / 16) * 4) + 0x218)
 #define CSU_SA_LOCK(x)		((0x1 << (((x) % 16) * 2 + 1)))
 #define CSU_SA_CFG(x, n)	((x) << (((n) % 16) * 2))
 
diff --git a/plat/imx/imx8ulp/xrdc/xrdc_config.h b/plat/imx/imx8ulp/xrdc/xrdc_config.h
index 25edd37..d2af55c 100644
--- a/plat/imx/imx8ulp/xrdc/xrdc_config.h
+++ b/plat/imx/imx8ulp/xrdc/xrdc_config.h
@@ -116,13 +116,15 @@
 
 struct xrdc_pac_msc_config imx8ulp_pdac[] = {
 	{ 0, PAC_SLOT_ALL, {0, 7, 0, 0, 0, 0, 0, 7} }, /* PAC0 */
+	{ 0, 44, {0, 7, 7, 0, 0, 0, 0, 7} }, /* PAC0 slot 44 for CGC1 */
 	{ 0, 36, {0, 0, 0, 0, 0, 0, 7, 7} }, /* PAC0 slot 36 for CMC1 */
 	{ 0, 41, {0, 0, 0, 0, 0, 0, 7, 7} }, /* PAC0 slot 41 for SIM_AD */
 	{ 1, PAC_SLOT_ALL, {0, 7, 0, 0, 0, 0, 0, 7} }, /* PAC1 */
-	{ 1, 0, {0, 7, 0, 0, 0, 0, 7, 7} }, /* PAC1 slot 0 for PCC4 */
+	{ 1, 0, {0, 7, 7, 0, 0, 0, 7, 7} }, /* PAC1 slot 0 for PCC4 */
 	{ 1, 6, {0, 7, 7, 0, 0, 0, 0, 7} }, /* PAC1 slot 6 for LPUART6 */
+	{ 1, 7, {0, 7, 7, 0, 0, 0, 0, 7} }, /* PAC1 slot 7 for LPUART7 */
 	{ 1, 9,  {0, 7, 7, 7, 0, 0, 0, 7} }, /* SAI5 for HIFI4 and eDMA2 */
-	{ 1, 12, {0, 7, 0, 0, 0, 0, 7, 7} }, /* PAC1 slot 12 for IOMUXC1 */
+	{ 1, 12, {0, 7, 7, 0, 0, 0, 7, 7} }, /* PAC1 slot 12 for IOMUXC1 */
 	{ 2, PAC_SLOT_ALL, {7, 7, 7, 7, 0, 0, 7, 7} }, /* PAC2 */
 };
 
diff --git a/plat/intel/soc/agilex5/bl31_plat_setup.c b/plat/intel/soc/agilex5/bl31_plat_setup.c
index 0d4f2cc..8d3928f 100644
--- a/plat/intel/soc/agilex5/bl31_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl31_plat_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -182,7 +182,7 @@
 
 /*******************************************************************************
  * Perform the very early platform specific architectural setup here. At the
- * moment this is only intializes the mmu in a quick and dirty way.
+ * moment this is only initializes the mmu in a quick and dirty way.
  ******************************************************************************/
 void bl31_plat_arch_setup(void)
 {
diff --git a/plat/nuvoton/common/nuvoton_helpers.S b/plat/nuvoton/common/nuvoton_helpers.S
index 09035a1..9c78815 100644
--- a/plat/nuvoton/common/nuvoton_helpers.S
+++ b/plat/nuvoton/common/nuvoton_helpers.S
@@ -151,9 +151,9 @@
 	 */
 	bl	plat_my_core_pos
 	lsl	x0, x0, #3
-	mov x8, x0
 	mov_imm	x2, PLAT_NPCM_TM_HOLD_BASE
 	add	x0, x0, x2
+	mov x8, x0
 	mov_imm	x2, PLAT_NPCM_TRUSTED_NOTIFICATION_BASE
 	add	x8, x8, x2
 	/*
diff --git a/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c b/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c
index 08448db..b8371d8 100644
--- a/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c
+++ b/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c
@@ -47,6 +47,20 @@
 					BL31_END - BL31_START, \
 					MT_MEMORY | MT_RW | EL3_PAS)
 
+#if RECLAIM_INIT_CODE
+IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE);
+IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_CODE_END_UNALIGNED);
+
+#define	BL_INIT_CODE_END	((BL_CODE_END_UNALIGNED + PAGE_SIZE - 1) & \
+					~(PAGE_SIZE - 1))
+
+#define MAP_BL_INIT_CODE	MAP_REGION_FLAT( \
+					BL_INIT_CODE_BASE, \
+					BL_INIT_CODE_END - \
+					BL_INIT_CODE_BASE, \
+					MT_CODE | MT_SECURE)
+#endif /* RECLAIM_INIT_CODE */
+
 #if SEPARATE_NOBITS_REGION
 #define MAP_BL31_NOBITS		MAP_REGION_FLAT( \
 					BL31_NOBITS_BASE, \
@@ -117,6 +131,7 @@
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 		u_register_t arg2, u_register_t arg3)
 {
+	arg0 = arg1 = arg2 = arg3 = 0;
 #if RESET_TO_BL31
 	void *from_bl2 = (void *)arg0;
 	void *plat_params_from_bl2 = (void *)arg3;
@@ -309,26 +324,23 @@
 {
 	const mmap_region_t bl_regions[] = {
 		MAP_BL31_TOTAL,
-#if SEPARATE_NOBITS_REGION
-		MAP_BL31_NOBITS,
-#endif /* SEPARATE_NOBITS_REGION */
+#if RECLAIM_INIT_CODE
+		MAP_BL_INIT_CODE_NOT_USED,
+#endif /* RECLAIM_INIT_CODE */
 		ARM_MAP_BL_RO,
-#if USE_ROMLIB
-		ARM_MAP_ROMLIB_CODE,
-		ARM_MAP_ROMLIB_DATA,
-#endif /* USE_ROMLIB */
 #if USE_COHERENT_MEM
 		ARM_MAP_BL_COHERENT_RAM,
 #endif /* USE_COHERENT_MEM */
 		ARM_MAP_SHARED_RAM,
 #ifdef SECONDARY_BRINGUP
-		ARM_MAP_NS_DRAM1,
+		ARM_MAP_NS_DRAM1_NO_USED,
 	#ifdef BL32_BASE
-		ARM_MAP_BL32_CORE_MEM
+		ARM_MAP_BL32_CORE_MEM_NO_USED
 	#endif /* BL32_BASE */
 #endif /* SECONDARY_BRINGUP */
 		{0}
 	};
 	setup_page_tables(bl_regions, plat_arm_get_mmap());
 	enable_mmu_el3(0U);
+	NOTICE("Done enabling MMU\n");
 }
diff --git a/plat/nuvoton/npcm845x/platform.mk b/plat/nuvoton/npcm845x/platform.mk
index 92c7e2f..1959aac 100644
--- a/plat/nuvoton/npcm845x/platform.mk
+++ b/plat/nuvoton/npcm845x/platform.mk
@@ -12,6 +12,7 @@
 SPMD_SPM_AT_SEL2	:= 0
 #temporary until the RAM size is reduced
 USE_COHERENT_MEM	:=	1
+INIT_UNUSED_NS_EL2  := 1
 
 
 $(eval $(call add_define,RESET_TO_BL31))
@@ -21,12 +22,29 @@
 # Trusted DRAM (if available) or the TZC secured area of DRAM.
 # TZC secured DRAM is the default.
 
+ARM_TSP_RAM_LOCATION	?=	dram
+
+ifeq (${ARM_TSP_RAM_LOCATION}, tsram)
+ARM_TSP_RAM_LOCATION_ID	=	ARM_TRUSTED_SRAM_ID
+else ifeq (${ARM_TSP_RAM_LOCATION}, tdram)
+ARM_TSP_RAM_LOCATION_ID	=	ARM_TRUSTED_DRAM_ID
+else ifeq (${ARM_TSP_RAM_LOCATION}, dram)
+ARM_TSP_RAM_LOCATION_ID	=	ARM_DRAM_ID
+else
+$(error "Unsupported ARM_TSP_RAM_LOCATION value")
+endif
+
+# Process flags
 # Process ARM_BL31_IN_DRAM flag
 ARM_BL31_IN_DRAM	:=	0
 $(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
 $(eval $(call add_define,ARM_BL31_IN_DRAM))
+else
+ARM_TSP_RAM_LOCATION_ID	=	ARM_TRUSTED_SRAM_ID
 endif
 
+$(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
+
 # For the original power-state parameter format, the State-ID can be encoded
 # according to the recommended encoding or zero. This flag determines which
 # State-ID encoding to be parsed.
@@ -140,11 +158,25 @@
 endif
 endif
 
+# Disable ARM Cryptocell by default
+ARM_CRYPTOCELL_INTEG	:=	0
+$(eval $(call assert_boolean,ARM_CRYPTOCELL_INTEG))
+$(eval $(call add_define,ARM_CRYPTOCELL_INTEG))
+
 # Enable PIE support for RESET_TO_BL31 case
 ifeq (${RESET_TO_BL31},1)
 ENABLE_PIE	:=	1
 endif
 
+# CryptoCell integration relies on coherent buffers for passing data from
+# the AP CPU to the CryptoCell
+
+ifeq (${ARM_CRYPTOCELL_INTEG},1)
+ifeq (${USE_COHERENT_MEM},0)
+$(error "ARM_CRYPTOCELL_INTEG needs USE_COHERENT_MEM to be set.")
+endif
+endif
+
 PLAT_INCLUDES	:=	-Iinclude/plat/nuvoton/npcm845x \
 		-Iinclude/plat/nuvoton/common \
 		-Iinclude/drivers/nuvoton/npcm845x \
@@ -287,7 +319,8 @@
 
 # Pointer Authentication sources
 ifeq (${ENABLE_PAUTH}, 1)
-PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c \
+		lib/extensions/pauth/pauth_helpers.S
 endif
 
 ifeq (${SPD},spmd)
@@ -325,7 +358,11 @@
 $(eval $(call TOOL_ADD_IMG,ns_bl2u,--fwu,FWU_))
 
 # We expect to locate the *.mk files under the directories specified below
+ifeq (${ARM_CRYPTOCELL_INTEG},0)
 CRYPTO_LIB_MK	:=	drivers/auth/mbedtls/mbedtls_crypto.mk
+else
+CRYPTO_LIB_MK	:=	drivers/auth/cryptocell/cryptocell_crypto.mk
+endif
 
 IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk
 
@@ -336,6 +373,12 @@
 include ${IMG_PARSER_LIB_MK}
 endif
 
+ifeq (${RECLAIM_INIT_CODE}, 1)
+ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+$(error "To reclaim init code xlat tables v2 must be used")
+endif
+endif
+
 ifeq (${MEASURED_BOOT},1)
 MEASURED_BOOT_MK := drivers/measured_boot/measured_boot.mk
 $(info Including ${MEASURED_BOOT_MK})
@@ -352,3 +395,6 @@
 
 DEBUG_CONSOLE	?=	0
 $(eval $(call add_define,DEBUG_CONSOLE))
+
+$(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
+
diff --git a/plat/rpi/rpi4/aarch64/armstub8_header.S b/plat/rpi/common/aarch64/armstub8_header.S
similarity index 89%
rename from plat/rpi/rpi4/aarch64/armstub8_header.S
rename to plat/rpi/common/aarch64/armstub8_header.S
index 246358d..dc1e54e 100644
--- a/plat/rpi/rpi4/aarch64/armstub8_header.S
+++ b/plat/rpi/common/aarch64/armstub8_header.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/rpi/common/aarch64/plat_helpers.S b/plat/rpi/common/aarch64/plat_helpers.S
index f045e21..18873af 100644
--- a/plat/rpi/common/aarch64/plat_helpers.S
+++ b/plat/rpi/common/aarch64/plat_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,10 +27,19 @@
 	 *
 	 *  This function uses the plat_rpi3_calc_core_pos()
 	 *  definition to get the index of the calling CPU.
+	 *
+	 *  When MT is set, lowest affinity represents the thread ID.
+	 *  Since we only support one thread per core, discard this field
+	 *  so cluster and core IDs go back into Aff1 and Aff0 respectively.
+	 *  The upper bits are also affected, but plat_rpi3_calc_core_pos()
+	 *  does not use them.
 	 * -----------------------------------------------------
 	 */
 func plat_my_core_pos
 	mrs	x0, mpidr_el1
+	tst	x0, #MPIDR_MT_MASK
+	lsr	x1, x0, #MPIDR_AFFINITY_BITS
+	csel	x0, x1, x0, ne
 	b	plat_rpi3_calc_core_pos
 endfunc plat_my_core_pos
 
@@ -164,10 +173,16 @@
 	 * ---------------------------------------------
 	 */
 func plat_crash_console_init
-	mov_imm	x0, PLAT_RPI_MINI_UART_BASE
+	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
+#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
+	mov_imm	x1, RPI4_PL011_UART_CLOCK
+	mov_imm	x2, PLAT_RPI_UART_BAUDRATE
+	b	console_pl011_core_init
+#else
 	mov	x1, xzr
 	mov	x2, xzr
 	b	console_16550_core_init
+#endif
 endfunc plat_crash_console_init
 
 	/* ---------------------------------------------
@@ -178,8 +193,12 @@
 	 * ---------------------------------------------
 	 */
 func plat_crash_console_putc
-	mov_imm	x1, PLAT_RPI_MINI_UART_BASE
+	mov_imm	x1, PLAT_RPI_CRASH_UART_BASE
+#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
+	b	console_pl011_core_putc
+#else
 	b	console_16550_core_putc
+#endif
 endfunc plat_crash_console_putc
 
 	/* ---------------------------------------------
@@ -191,8 +210,12 @@
 	 * ---------------------------------------------
 	 */
 func plat_crash_console_flush
-	mov_imm	x0, PLAT_RPI_MINI_UART_BASE
+	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
+#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
+	b	console_pl011_core_flush
+#else
 	b	console_16550_core_flush
+#endif
 endfunc plat_crash_console_flush
 
 	/* ---------------------------------------------
diff --git a/plat/rpi/rpi4/include/plat_macros.S b/plat/rpi/common/include/plat_macros.S
similarity index 87%
rename from plat/rpi/rpi4/include/plat_macros.S
rename to plat/rpi/common/include/plat_macros.S
index 6007d03..576d0ff 100644
--- a/plat/rpi/rpi4/include/plat_macros.S
+++ b/plat/rpi/common/include/plat_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/rpi/common/include/rpi_shared.h b/plat/rpi/common/include/rpi_shared.h
index ddf239e..8562c3d 100644
--- a/plat/rpi/common/include/rpi_shared.h
+++ b/plat/rpi/common/include/rpi_shared.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,14 +7,20 @@
 #ifndef RPI_SHARED_H
 #define RPI_SHARED_H
 
+#include <stddef.h>
 #include <stdint.h>
 
+#include <drivers/console.h>
+
 /*******************************************************************************
  * Function and variable prototypes
  ******************************************************************************/
 
-/* Utility functions */
+/* Serial console functions */
 void rpi3_console_init(void);
+int rpi3_register_used_uart(console_t *console);
+
+/* Utility functions */
 void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
 			    uintptr_t code_start, uintptr_t code_limit,
 			    uintptr_t rodata_start, uintptr_t rodata_limit
@@ -23,6 +29,8 @@
 #endif
 			    );
 
+uintptr_t rpi4_get_dtb_address(void);
+
 /* Optional functions required in the Raspberry Pi 3 port */
 unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
 
@@ -38,4 +46,10 @@
 
 int plat_rpi_get_model(void);
 
+/*******************************************************************************
+ * Platform implemented functions
+ ******************************************************************************/
+
+void plat_rpi_bl31_custom_setup(void);
+
 #endif /* RPI3_PRIVATE_H */
diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c
index ef88bf1..8976496 100644
--- a/plat/rpi/common/rpi3_common.c
+++ b/plat/rpi/common/rpi3_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,9 +13,6 @@
 #include <common/debug.h>
 #include <bl31/interrupt_mgmt.h>
 #include <drivers/console.h>
-#include <drivers/rpi3/gpio/rpi3_gpio.h>
-#include <drivers/ti/uart/uart_16550.h>
-#include <drivers/arm/pl011.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
 #include <rpi_hw.h>
@@ -106,12 +103,6 @@
  ******************************************************************************/
 static console_t rpi3_console;
 
-
-static bool rpi3_use_mini_uart(void)
-{
-	return rpi3_gpio_get_select(14) == RPI3_GPIO_FUNC_ALT5;
-}
-
 void rpi3_console_init(void)
 {
 	int console_scope = CONSOLE_FLAG_BOOT;
@@ -120,18 +111,7 @@
 	if (RPI3_RUNTIME_UART != -1)
 		console_scope |= CONSOLE_FLAG_RUNTIME;
 
-	rpi3_gpio_init();
-
-	if (rpi3_use_mini_uart())
-		rc = console_16550_register(PLAT_RPI_MINI_UART_BASE,
-					    0,
-					    PLAT_RPI_UART_BAUDRATE,
-					    &rpi3_console);
-	else
-		rc = console_pl011_register(PLAT_RPI_PL011_UART_BASE,
-					    PLAT_RPI_PL011_UART_CLOCK,
-					    PLAT_RPI_UART_BAUDRATE,
-					    &rpi3_console);
+	rc = rpi3_register_used_uart(&rpi3_console);
 
 	if (rc == 0) {
 		/*
diff --git a/plat/rpi/common/rpi3_console_dual.c b/plat/rpi/common/rpi3_console_dual.c
new file mode 100644
index 0000000..15ee3e7
--- /dev/null
+++ b/plat/rpi/common/rpi3_console_dual.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <platform_def.h>
+
+#include <rpi_shared.h>
+
+static bool rpi3_use_mini_uart(void)
+{
+	return rpi3_gpio_get_select(14) == RPI3_GPIO_FUNC_ALT5;
+}
+
+int rpi3_register_used_uart(console_t *console)
+{
+	rpi3_gpio_init();
+
+	if (rpi3_use_mini_uart())
+		return console_16550_register(PLAT_RPI_MINI_UART_BASE,
+					      0,
+					      PLAT_RPI_UART_BAUDRATE,
+					      console);
+	else
+		return console_pl011_register(PLAT_RPI_PL011_UART_BASE,
+					      PLAT_RPI_PL011_UART_CLOCK,
+					      PLAT_RPI_UART_BAUDRATE,
+					      console);
+}
diff --git a/plat/rpi/common/rpi3_console_pl011.c b/plat/rpi/common/rpi3_console_pl011.c
new file mode 100644
index 0000000..6ab7209
--- /dev/null
+++ b/plat/rpi/common/rpi3_console_pl011.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <platform_def.h>
+
+#include <rpi_shared.h>
+
+int rpi3_register_used_uart(console_t *console)
+{
+	return console_pl011_register(PLAT_RPI_PL011_UART_BASE,
+				      PLAT_RPI_PL011_UART_CLOCK,
+				      PLAT_RPI_UART_BAUDRATE,
+				      console);
+}
diff --git a/plat/rpi/common/rpi3_pm.c b/plat/rpi/common/rpi3_pm.c
index d98ac66..456e160 100644
--- a/plat/rpi/common/rpi3_pm.c
+++ b/plat/rpi/common/rpi3_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,22 @@
 #include <drivers/arm/gicv2.h>
 #endif
 
+/* Registers on top of RPI3_PM_BASE. */
+#define RPI3_PM_RSTC_OFFSET		ULL(0x0000001C)
+#define RPI3_PM_RSTS_OFFSET		ULL(0x00000020)
+#define RPI3_PM_WDOG_OFFSET		ULL(0x00000024)
+/* Watchdog constants */
+#define RPI3_PM_PASSWORD		U(0x5A000000)
+#define RPI3_PM_RSTC_WRCFG_MASK		U(0x00000030)
+#define RPI3_PM_RSTC_WRCFG_FULL_RESET	U(0x00000020)
+/*
+ * The RSTS register is used by the VideoCore firmware when booting the
+ * Raspberry Pi to know which partition to boot from. The partition value is
+ * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
+ * to indicate halt.
+ */
+#define RPI3_PM_RSTS_WRCFG_HALT		U(0x00000555)
+
 /* Make composite power state parameter till power level 0 */
 #if PSCI_EXTENDED_STATE_ID
 
diff --git a/plat/rpi/common/rpi3_topology.c b/plat/rpi/common/rpi3_topology.c
index 3747287..5fef777 100644
--- a/plat/rpi/common/rpi3_topology.c
+++ b/plat/rpi/common/rpi3_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -39,12 +39,27 @@
 	unsigned int cluster_id, cpu_id;
 
 	mpidr &= MPIDR_AFFINITY_MASK;
+
+	/*
+	 * When MT is set, lowest affinity represents the thread ID.
+	 * Since we only support one thread per core, discard this field
+	 * so cluster and core IDs go back into Aff1 and Aff0 respectively.
+	 * The upper bits are also affected, but plat_rpi3_calc_core_pos()
+	 * does not use them.
+	 */
+	if ((read_mpidr() & MPIDR_MT_MASK) != 0) {
+		if (MPIDR_AFFLVL0_VAL(mpidr) != 0) {
+			return -1;
+		}
+		mpidr >>= MPIDR_AFFINITY_BITS;
+	}
+
 	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
 		return -1;
 	}
 
-	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
-	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+	cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
 	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
 		return -1;
diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/common/rpi4_bl31_setup.c
similarity index 67%
rename from plat/rpi/rpi4/rpi4_bl31_setup.c
rename to plat/rpi/common/rpi4_bl31_setup.c
index 2fb4d3d..a7228fd 100644
--- a/plat/rpi/rpi4/rpi4_bl31_setup.c
+++ b/plat/rpi/common/rpi4_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,21 +8,15 @@
 #include <inttypes.h>
 #include <stdint.h>
 
-#include <libfdt.h>
-
-#include <platform_def.h>
 #include <arch_helpers.h>
 #include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_mmu_helpers.h>
 #include <lib/xlat_tables/xlat_tables_defs.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
-#include <common/fdt_fixup.h>
-#include <common/fdt_wrappers.h>
-#include <libfdt.h>
-
-#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
 
 #include <rpi_shared.h>
 
@@ -85,7 +79,7 @@
 #endif
 }
 
-static uintptr_t rpi4_get_dtb_address(void)
+uintptr_t rpi4_get_dtb_address(void)
 {
 #ifdef RPI3_PRELOADED_DTB_BASE
 	return RPI3_PRELOADED_DTB_BASE;
@@ -151,7 +145,7 @@
 	 * r1 = machine type number, optional in DT-only platforms (~0 if so)
 	 * r2 = Physical address of the device tree blob
 	 */
-	VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n");
+	VERBOSE("rpi: Preparing to boot 32-bit Linux kernel\n");
 	bl33_image_ep_info.args.arg0 = 0U;
 	bl33_image_ep_info.args.arg1 = ~0U;
 	bl33_image_ep_info.args.arg2 = rpi4_get_dtb_address();
@@ -162,7 +156,7 @@
 	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
 	 * must be 0.
 	 */
-	VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n");
+	VERBOSE("rpi: Preparing to boot 64-bit Linux kernel\n");
 	bl33_image_ep_info.args.arg0 = rpi4_get_dtb_address();
 	bl33_image_ep_info.args.arg1 = 0ULL;
 	bl33_image_ep_info.args.arg2 = 0ULL;
@@ -203,102 +197,13 @@
 	enable_mmu_el3(0);
 }
 
-/*
- * Remove the FDT /memreserve/ entry that covers the region at the very
- * beginning of memory (if that exists). This is where the secondaries
- * originally spin, but we pull them out there.
- * Having overlapping /reserved-memory and /memreserve/ regions confuses
- * the Linux kernel, so we need to get rid of this one.
- */
-static void remove_spintable_memreserve(void *dtb)
-{
-	uint64_t addr, size;
-	int regions = fdt_num_mem_rsv(dtb);
-	int i;
-
-	for (i = 0; i < regions; i++) {
-		if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) {
-			return;
-		}
-		if (size == 0U) {
-			return;
-		}
-		/* We only look for the region at the beginning of DRAM. */
-		if (addr != 0U) {
-			continue;
-		}
-		/*
-		 * Currently the region in the existing DTs is exactly 4K
-		 * in size. Should this value ever change, there is probably
-		 * a reason for that, so inform the user about this.
-		 */
-		if (size == 4096U) {
-			fdt_del_mem_rsv(dtb, i);
-			return;
-		}
-		WARN("Keeping unknown /memreserve/ region at 0, size: %" PRId64 "\n",
-		     size);
-	}
-}
-
-static void rpi4_prepare_dtb(void)
-{
-	void *dtb = (void *)rpi4_get_dtb_address();
-	uint32_t gic_int_prop[3];
-	int ret, offs;
-
-	/* Return if no device tree is detected */
-	if (fdt_check_header(dtb) != 0)
-		return;
-
-	ret = fdt_open_into(dtb, dtb, 0x100000);
-	if (ret < 0) {
-		ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
-		return;
-	}
-
-	if (dt_add_psci_node(dtb)) {
-		ERROR("Failed to add PSCI Device Tree node\n");
-		return;
-	}
-
-	if (dt_add_psci_cpu_enable_methods(dtb)) {
-		ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
-		return;
-	}
-
-	/*
-	 * Remove the original reserved region (used for the spintable), and
-	 * replace it with a region describing the whole of Trusted Firmware.
-	 */
-	remove_spintable_memreserve(dtb);
-	if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000))
-		WARN("Failed to add reserved memory nodes to DT.\n");
-
-	offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400");
-	gic_int_prop[0] = cpu_to_fdt32(1);		// PPI
-	gic_int_prop[1] = cpu_to_fdt32(9);		// PPI #9
-	gic_int_prop[2] = cpu_to_fdt32(0x0f04);		// all cores, level high
-	fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12);
-
-	offs = fdt_path_offset(dtb, "/chosen");
-	fdt_setprop_string(dtb, offs, "stdout-path", "serial0");
-
-	ret = fdt_pack(dtb);
-	if (ret < 0)
-		ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
-
-	clean_dcache_range((uintptr_t)dtb, fdt_blob_size(dtb));
-	INFO("Changed device tree to advertise PSCI.\n");
-}
-
 void bl31_platform_setup(void)
 {
-	rpi4_prepare_dtb();
-
 	/* Configure the interrupt controller */
 	gicv2_driver_init(&rpi4_gic_data);
 	gicv2_distif_init();
 	gicv2_pcpu_distif_init();
 	gicv2_cpuif_enable();
+
+	plat_rpi_bl31_custom_setup();
 }
diff --git a/plat/rpi/rpi3/include/plat_macros.S b/plat/rpi/rpi3/include/plat_macros.S
deleted file mode 100644
index c0c3967..0000000
--- a/plat/rpi/rpi3/include/plat_macros.S
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#ifndef PLAT_MACROS_S
-#define PLAT_MACROS_S
-
-	/* ---------------------------------------------
-	 * The below required platform porting macro
-	 * prints out relevant platform registers
-	 * whenever an unhandled exception is taken in
-	 * BL31.
-	 * Clobbers: x0 - x10, x16, x17, sp
-	 * ---------------------------------------------
-	 */
-	.macro plat_crash_print_regs
-	.endm
-
-#endif /* PLAT_MACROS_S */
diff --git a/plat/rpi/rpi3/include/platform_def.h b/plat/rpi/rpi3/include/platform_def.h
index f44d1f5..757c64a 100644
--- a/plat/rpi/rpi3/include/platform_def.h
+++ b/plat/rpi/rpi3/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -254,6 +254,7 @@
 #define PLAT_RPI_PL011_UART_BASE	RPI3_PL011_UART_BASE
 #define PLAT_RPI_PL011_UART_CLOCK	RPI3_PL011_UART_CLOCK
 #define PLAT_RPI_UART_BAUDRATE		ULL(115200)
+#define PLAT_RPI_CRASH_UART_BASE	PLAT_RPI_MINI_UART_BASE
 
 /*
  * System counter
diff --git a/plat/rpi/rpi3/include/rpi_hw.h b/plat/rpi/rpi3/include/rpi_hw.h
index 2aecab3..dec5963 100644
--- a/plat/rpi/rpi3/include/rpi_hw.h
+++ b/plat/rpi/rpi3/include/rpi_hw.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,60 +21,18 @@
  */
 #define RPI3_MBOX_OFFSET		ULL(0x0000B880)
 #define RPI3_MBOX_BASE			(RPI_IO_BASE + RPI3_MBOX_OFFSET)
-/* VideoCore -> ARM */
-#define RPI3_MBOX0_READ_OFFSET		ULL(0x00000000)
-#define RPI3_MBOX0_PEEK_OFFSET		ULL(0x00000010)
-#define RPI3_MBOX0_SENDER_OFFSET	ULL(0x00000014)
-#define RPI3_MBOX0_STATUS_OFFSET	ULL(0x00000018)
-#define RPI3_MBOX0_CONFIG_OFFSET	ULL(0x0000001C)
-/* ARM -> VideoCore */
-#define RPI3_MBOX1_WRITE_OFFSET		ULL(0x00000020)
-#define RPI3_MBOX1_PEEK_OFFSET		ULL(0x00000030)
-#define RPI3_MBOX1_SENDER_OFFSET	ULL(0x00000034)
-#define RPI3_MBOX1_STATUS_OFFSET	ULL(0x00000038)
-#define RPI3_MBOX1_CONFIG_OFFSET	ULL(0x0000003C)
-/* Mailbox status constants */
-#define RPI3_MBOX_STATUS_FULL_MASK	U(0x80000000) /* Set if full */
-#define RPI3_MBOX_STATUS_EMPTY_MASK	U(0x40000000) /* Set if empty */
 
 /*
  * Power management, reset controller, watchdog.
  */
 #define RPI3_IO_PM_OFFSET		ULL(0x00100000)
 #define RPI3_PM_BASE			(RPI_IO_BASE + RPI3_IO_PM_OFFSET)
-/* Registers on top of RPI3_PM_BASE. */
-#define RPI3_PM_RSTC_OFFSET		ULL(0x0000001C)
-#define RPI3_PM_RSTS_OFFSET		ULL(0x00000020)
-#define RPI3_PM_WDOG_OFFSET		ULL(0x00000024)
-/* Watchdog constants */
-#define RPI3_PM_PASSWORD		U(0x5A000000)
-#define RPI3_PM_RSTC_WRCFG_MASK		U(0x00000030)
-#define RPI3_PM_RSTC_WRCFG_FULL_RESET	U(0x00000020)
-/*
- * The RSTS register is used by the VideoCore firmware when booting the
- * Raspberry Pi to know which partition to boot from. The partition value is
- * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
- * to indicate halt.
- */
-#define RPI3_PM_RSTS_WRCFG_HALT		U(0x00000555)
 
 /*
  * Hardware random number generator.
  */
 #define RPI3_IO_RNG_OFFSET		ULL(0x00104000)
 #define RPI3_RNG_BASE			(RPI_IO_BASE + RPI3_IO_RNG_OFFSET)
-#define RPI3_RNG_CTRL_OFFSET		ULL(0x00000000)
-#define RPI3_RNG_STATUS_OFFSET		ULL(0x00000004)
-#define RPI3_RNG_DATA_OFFSET		ULL(0x00000008)
-#define RPI3_RNG_INT_MASK_OFFSET	ULL(0x00000010)
-/* Enable/disable RNG */
-#define RPI3_RNG_CTRL_ENABLE		U(0x1)
-#define RPI3_RNG_CTRL_DISABLE		U(0x0)
-/* Number of currently available words */
-#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT	U(24)
-#define RPI3_RNG_STATUS_NUM_WORDS_MASK	U(0xFF)
-/* Value to mask interrupts caused by the RNG */
-#define RPI3_RNG_INT_MASK_DISABLE	U(0x1)
 
 /*
  * Serial ports:
diff --git a/plat/rpi/rpi3/platform.mk b/plat/rpi/rpi3/platform.mk
index 26a3268..8034fa4 100644
--- a/plat/rpi/rpi3/platform.mk
+++ b/plat/rpi/rpi3/platform.mk
@@ -17,6 +17,7 @@
 				drivers/rpi3/gpio/rpi3_gpio.c		\
 				plat/rpi/common/aarch64/plat_helpers.S	\
 				plat/rpi/common/rpi3_common.c		\
+				plat/rpi/common/rpi3_console_dual.c	\
 				${XLAT_TABLES_LIB_SRCS}
 
 BL1_SOURCES		+=	drivers/io/io_fip.c			\
diff --git a/plat/rpi/rpi4/include/platform_def.h b/plat/rpi/rpi4/include/platform_def.h
index 6787ebf..b72aedc 100644
--- a/plat/rpi/rpi4/include/platform_def.h
+++ b/plat/rpi/rpi4/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -131,6 +131,7 @@
 #define PLAT_RPI_PL011_UART_BASE	RPI4_PL011_UART_BASE
 #define PLAT_RPI_PL011_UART_CLOCK       RPI4_PL011_UART_CLOCK
 #define PLAT_RPI_UART_BAUDRATE          ULL(115200)
+#define PLAT_RPI_CRASH_UART_BASE	PLAT_RPI_MINI_UART_BASE
 
 /*
  * System counter
diff --git a/plat/rpi/rpi4/include/rpi_hw.h b/plat/rpi/rpi4/include/rpi_hw.h
index 0430d46..8162492 100644
--- a/plat/rpi/rpi4/include/rpi_hw.h
+++ b/plat/rpi/rpi4/include/rpi_hw.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,60 +23,18 @@
  */
 #define RPI3_MBOX_OFFSET		ULL(0x0000B880)
 #define RPI3_MBOX_BASE			(RPI_LEGACY_BASE + RPI3_MBOX_OFFSET)
-/* VideoCore -> ARM */
-#define RPI3_MBOX0_READ_OFFSET		ULL(0x00000000)
-#define RPI3_MBOX0_PEEK_OFFSET		ULL(0x00000010)
-#define RPI3_MBOX0_SENDER_OFFSET	ULL(0x00000014)
-#define RPI3_MBOX0_STATUS_OFFSET	ULL(0x00000018)
-#define RPI3_MBOX0_CONFIG_OFFSET	ULL(0x0000001C)
-/* ARM -> VideoCore */
-#define RPI3_MBOX1_WRITE_OFFSET		ULL(0x00000020)
-#define RPI3_MBOX1_PEEK_OFFSET		ULL(0x00000030)
-#define RPI3_MBOX1_SENDER_OFFSET	ULL(0x00000034)
-#define RPI3_MBOX1_STATUS_OFFSET	ULL(0x00000038)
-#define RPI3_MBOX1_CONFIG_OFFSET	ULL(0x0000003C)
-/* Mailbox status constants */
-#define RPI3_MBOX_STATUS_FULL_MASK	U(0x80000000) /* Set if full */
-#define RPI3_MBOX_STATUS_EMPTY_MASK	U(0x40000000) /* Set if empty */
 
 /*
  * Power management, reset controller, watchdog.
  */
 #define RPI3_IO_PM_OFFSET		ULL(0x00100000)
 #define RPI3_PM_BASE			(RPI_LEGACY_BASE + RPI3_IO_PM_OFFSET)
-/* Registers on top of RPI3_PM_BASE. */
-#define RPI3_PM_RSTC_OFFSET		ULL(0x0000001C)
-#define RPI3_PM_RSTS_OFFSET		ULL(0x00000020)
-#define RPI3_PM_WDOG_OFFSET		ULL(0x00000024)
-/* Watchdog constants */
-#define RPI3_PM_PASSWORD		U(0x5A000000)
-#define RPI3_PM_RSTC_WRCFG_MASK		U(0x00000030)
-#define RPI3_PM_RSTC_WRCFG_FULL_RESET	U(0x00000020)
-/*
- * The RSTS register is used by the VideoCore firmware when booting the
- * Raspberry Pi to know which partition to boot from. The partition value is
- * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
- * to indicate halt.
- */
-#define RPI3_PM_RSTS_WRCFG_HALT		U(0x00000555)
 
 /*
  * Hardware random number generator.
  */
 #define RPI3_IO_RNG_OFFSET		ULL(0x00104000)
 #define RPI3_RNG_BASE			(RPI_LEGACY_BASE + RPI3_IO_RNG_OFFSET)
-#define RPI3_RNG_CTRL_OFFSET		ULL(0x00000000)
-#define RPI3_RNG_STATUS_OFFSET		ULL(0x00000004)
-#define RPI3_RNG_DATA_OFFSET		ULL(0x00000008)
-#define RPI3_RNG_INT_MASK_OFFSET	ULL(0x00000010)
-/* Enable/disable RNG */
-#define RPI3_RNG_CTRL_ENABLE		U(0x1)
-#define RPI3_RNG_CTRL_DISABLE		U(0x0)
-/* Number of currently available words */
-#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT	U(24)
-#define RPI3_RNG_STATUS_NUM_WORDS_MASK	U(0xFF)
-/* Value to mask interrupts caused by the RNG */
-#define RPI3_RNG_INT_MASK_DISABLE	U(0x1)
 
 /*
  * Serial ports:
diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk
index 42a5416..f17911f 100644
--- a/plat/rpi/rpi4/platform.mk
+++ b/plat/rpi/rpi4/platform.mk
@@ -15,16 +15,18 @@
 PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/aarch64/16550_console.S	\
 				drivers/arm/pl011/aarch64/pl011_console.S \
 				plat/rpi/common/rpi3_common.c		\
+				plat/rpi/common/rpi3_console_dual.c	\
 				${XLAT_TABLES_LIB_SRCS}
 
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a72.S		\
 				plat/rpi/common/aarch64/plat_helpers.S	\
-				plat/rpi/rpi4/aarch64/armstub8_header.S	\
+				plat/rpi/common/aarch64/armstub8_header.S \
 				drivers/delay_timer/delay_timer.c	\
 				drivers/gpio/gpio.c			\
 				drivers/rpi3/gpio/rpi3_gpio.c		\
 				plat/common/plat_gicv2.c                \
-				plat/rpi/rpi4/rpi4_bl31_setup.c		\
+				plat/rpi/common/rpi4_bl31_setup.c	\
+				plat/rpi/rpi4/rpi4_setup.c		\
 				plat/rpi/common/rpi3_pm.c		\
 				plat/common/plat_psci_common.c		\
 				plat/rpi/common/rpi3_topology.c		\
diff --git a/plat/rpi/rpi4/rpi4_setup.c b/plat/rpi/rpi4/rpi4_setup.c
new file mode 100644
index 0000000..82200b9
--- /dev/null
+++ b/plat/rpi/rpi4/rpi4_setup.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+
+#include <rpi_shared.h>
+
+/*
+ * Remove the FDT /memreserve/ entry that covers the region at the very
+ * beginning of memory (if that exists). This is where the secondaries
+ * originally spin, but we pull them out there.
+ * Having overlapping /reserved-memory and /memreserve/ regions confuses
+ * the Linux kernel, so we need to get rid of this one.
+ */
+static void remove_spintable_memreserve(void *dtb)
+{
+	uint64_t addr, size;
+	int regions = fdt_num_mem_rsv(dtb);
+	int i;
+
+	for (i = 0; i < regions; i++) {
+		if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) {
+			return;
+		}
+		if (size == 0U) {
+			return;
+		}
+		/* We only look for the region at the beginning of DRAM. */
+		if (addr != 0U) {
+			continue;
+		}
+		/*
+		 * Currently the region in the existing DTs is exactly 4K
+		 * in size. Should this value ever change, there is probably
+		 * a reason for that, so inform the user about this.
+		 */
+		if (size == 4096U) {
+			fdt_del_mem_rsv(dtb, i);
+			return;
+		}
+		WARN("Keeping unknown /memreserve/ region at 0, size: %" PRId64 "\n",
+		     size);
+	}
+}
+
+static void rpi4_prepare_dtb(void)
+{
+	void *dtb = (void *)rpi4_get_dtb_address();
+	uint32_t gic_int_prop[3];
+	int ret, offs;
+
+	/* Return if no device tree is detected */
+	if (fdt_check_header(dtb) != 0)
+		return;
+
+	ret = fdt_open_into(dtb, dtb, 0x100000);
+	if (ret < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
+		return;
+	}
+
+	if (dt_add_psci_node(dtb)) {
+		ERROR("Failed to add PSCI Device Tree node\n");
+		return;
+	}
+
+	if (dt_add_psci_cpu_enable_methods(dtb)) {
+		ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
+		return;
+	}
+
+	/*
+	 * Remove the original reserved region (used for the spintable), and
+	 * replace it with a region describing the whole of Trusted Firmware.
+	 */
+	remove_spintable_memreserve(dtb);
+	if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000))
+		WARN("Failed to add reserved memory nodes to DT.\n");
+
+	offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400");
+	gic_int_prop[0] = cpu_to_fdt32(1);		// PPI
+	gic_int_prop[1] = cpu_to_fdt32(9);		// PPI #9
+	gic_int_prop[2] = cpu_to_fdt32(0x0f04);		// all cores, level high
+	fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12);
+
+	offs = fdt_path_offset(dtb, "/chosen");
+	fdt_setprop_string(dtb, offs, "stdout-path", "serial0");
+
+	ret = fdt_pack(dtb);
+	if (ret < 0)
+		ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
+
+	clean_dcache_range((uintptr_t)dtb, fdt_blob_size(dtb));
+	INFO("Changed device tree to advertise PSCI.\n");
+}
+
+void plat_rpi_bl31_custom_setup(void)
+{
+	rpi4_prepare_dtb();
+}
diff --git a/plat/rpi/rpi5/include/plat.ld.S b/plat/rpi/rpi5/include/plat.ld.S
new file mode 100644
index 0000000..961c630
--- /dev/null
+++ b/plat/rpi/rpi5/include/plat.ld.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Stub linker script to provide the armstub8.bin header before the actual
+ * code. If the GPU firmware finds a magic value at offset 240 in
+ * armstub8.bin, it will put the DTB and kernel load address in subsequent
+ * words. We can then read those values to find the proper NS entry point
+ * and find our DTB more flexibly.
+ */
+
+MEMORY {
+    PRERAM (rwx): ORIGIN = 0, LENGTH = 4096
+}
+
+SECTIONS
+{
+    .armstub8 . : {
+        *armstub8_header.o(.text*)
+        KEEP(*(.armstub8))
+    } >PRERAM
+}
diff --git a/plat/rpi/rpi5/include/platform_def.h b/plat/rpi/rpi5/include/platform_def.h
new file mode 100644
index 0000000..a4c2f5b
--- /dev/null
+++ b/plat/rpi/rpi5/include/platform_def.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include "rpi_hw.h"
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RPI3_BL31_PLAT_PARAM_VAL	ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE		ULL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define RPI_PRIMARY_CPU			U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * I/O registers.
+ */
+#define DEVICE0_BASE			RPI_IO_BASE
+#define DEVICE0_SIZE			RPI_IO_SIZE
+
+/*
+ * Mailbox to control the secondary cores. All secondary cores are held in a
+ * wait loop in cold boot. To release them perform the following steps (plus
+ * any additional barriers that may be needed):
+ *
+ *     uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT;
+ *     *entrypoint = ADDRESS_TO_JUMP_TO;
+ *
+ *     uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+ *     mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO;
+ *
+ *     sev();
+ */
+/* The secure entry point to be used on warm reset by all CPUs. */
+#define PLAT_RPI3_TM_ENTRYPOINT		0x100
+#define PLAT_RPI3_TM_ENTRYPOINT_SIZE	ULL(8)
+
+/* Hold entries for each CPU. */
+#define PLAT_RPI3_TM_HOLD_BASE		(PLAT_RPI3_TM_ENTRYPOINT + \
+					 PLAT_RPI3_TM_ENTRYPOINT_SIZE)
+#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE	ULL(8)
+#define PLAT_RPI3_TM_HOLD_SIZE		(PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE	(PLAT_RPI3_TM_ENTRYPOINT_SIZE + \
+					 PLAT_RPI3_TM_HOLD_SIZE)
+
+#define PLAT_RPI3_TM_HOLD_STATE_WAIT	ULL(0)
+#define PLAT_RPI3_TM_HOLD_STATE_GO	ULL(1)
+#define PLAT_RPI3_TM_HOLD_STATE_BSP_OFF	ULL(2)
+
+/*
+ * BL31 specific defines.
+ *
+ * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL31_SIZE		ULL(0x80000)
+
+#define BL31_BASE			ULL(0x1000)
+#define BL31_LIMIT			ULL(0x80000)
+#define BL31_PROGBITS_LIMIT		ULL(0x80000)
+
+#define SEC_SRAM_ID			0
+#define SEC_DRAM_ID			1
+
+/*
+ * Other memory-related defines.
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 40)
+
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			4
+
+#define MAX_IO_DEVICES			U(3)
+#define MAX_IO_HANDLES			U(4)
+
+#define MAX_IO_BLOCK_DEVICES		U(1)
+
+/*
+ * Serial-related constants.
+ */
+#define PLAT_RPI_PL011_UART_BASE	RPI4_PL011_UART_BASE
+#define PLAT_RPI_PL011_UART_CLOCK	RPI4_PL011_UART_CLOCK
+#define PLAT_RPI_UART_BAUDRATE		ULL(115200)
+#define PLAT_RPI_CRASH_UART_BASE	PLAT_RPI_PL011_UART_BASE
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	ULL(54000000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi5/include/rpi_hw.h b/plat/rpi/rpi5/include/rpi_hw.h
new file mode 100644
index 0000000..384542e
--- /dev/null
+++ b/plat/rpi/rpi5/include/rpi_hw.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI_HW_H
+#define RPI_HW_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI_IO_BASE			ULL(0x1000000000)
+#define RPI_IO_SIZE			ULL(0x1000000000)
+
+/*
+ * ARM <-> VideoCore mailboxes
+ */
+#define RPI3_MBOX_BASE			(RPI_IO_BASE + ULL(0x7c013880))
+
+/*
+ * Power management, reset controller, watchdog.
+ */
+#define RPI3_PM_BASE			(RPI_IO_BASE + ULL(0x7d200000))
+
+/*
+ * Hardware random number generator.
+ */
+#define RPI3_RNG_BASE			(RPI_IO_BASE + ULL(0x7d208000))
+
+/*
+ * PL011 system serial port
+ */
+#define RPI4_PL011_UART_BASE		(RPI_IO_BASE + ULL(0x7d001000))
+#define RPI4_PL011_UART_CLOCK		ULL(44000000)
+
+/*
+ * GIC interrupt controller
+ */
+#define RPI_HAVE_GIC
+#define RPI4_GIC_GICD_BASE		(RPI_IO_BASE + ULL(0x7fff9000))
+#define RPI4_GIC_GICC_BASE		(RPI_IO_BASE + ULL(0x7fffa000))
+
+#define	RPI4_LOCAL_CONTROL_BASE_ADDRESS		(RPI_IO_BASE + ULL(0x7c280000))
+#define	RPI4_LOCAL_CONTROL_PRESCALER		(RPI_IO_BASE + ULL(0x7c280008))
+
+#endif /* RPI_HW_H */
diff --git a/plat/rpi/rpi5/platform.mk b/plat/rpi/rpi5/platform.mk
new file mode 100644
index 0000000..81b7ded
--- /dev/null
+++ b/plat/rpi/rpi5/platform.mk
@@ -0,0 +1,107 @@
+#
+# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+include drivers/arm/gic/v2/gicv2.mk
+
+PLAT_INCLUDES		:=	-Iplat/rpi/common/include			\
+				-Iplat/rpi/rpi5/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/aarch64/pl011_console.S 	\
+				plat/rpi/common/rpi3_common.c			\
+				plat/rpi/common/rpi3_console_pl011.c		\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a76.S			\
+				plat/rpi/common/aarch64/plat_helpers.S		\
+				plat/rpi/common/aarch64/armstub8_header.S 	\
+				drivers/delay_timer/delay_timer.c		\
+				plat/common/plat_gicv2.c			\
+				plat/rpi/common/rpi4_bl31_setup.c		\
+				plat/rpi/rpi5/rpi5_setup.c			\
+				plat/rpi/common/rpi3_pm.c			\
+				plat/common/plat_psci_common.c			\
+				plat/rpi/common/rpi3_topology.c			\
+				${GICV2_SOURCES}
+
+# For now we only support BL31, using the kernel loaded by the GPU firmware.
+RESET_TO_BL31		:=	1
+
+# All CPUs enter armstub8.bin.
+COLD_BOOT_SINGLE_CPU	:=	0
+
+# Tune compiler for Cortex-A76
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a76
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a76
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a76
+endif
+
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# Enable all errata workarounds for Cortex-A76 r4p1
+ERRATA_A76_1946160		:= 1
+ERRATA_A76_2743102		:= 1
+
+# Add new default target when compiling this platform
+all: bl31
+
+# Build config flags
+# ------------------
+
+# Disable stack protector by default
+ENABLE_STACK_PROTECTOR	 	:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Hardware-managed coherency
+HW_ASSISTED_COHERENCY		:= 1
+USE_COHERENT_MEM		:= 0
+
+# Cortex-A76 is 64-bit only
+CTX_INCLUDE_AARCH32_REGS	:= 0
+
+# Platform build flags
+# --------------------
+
+# There is not much else than a Linux kernel to load at the moment.
+RPI3_DIRECT_LINUX_BOOT		:= 1
+
+# BL33 images can only be AArch64 on this platform.
+RPI3_BL33_IN_AARCH32		:= 0
+
+# UART to use at runtime. -1 means the runtime UART is disabled.
+# Any other value means the default UART will be used.
+RPI3_RUNTIME_UART		:= 0
+
+# Use normal memory mapping for ROM, FIP, SRAM and DRAM
+RPI3_USE_UEFI_MAP		:= 0
+
+# Process platform flags
+# ----------------------
+
+$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
+$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT))
+ifdef RPI3_PRELOADED_DTB_BASE
+$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
+endif
+$(eval $(call add_define,RPI3_RUNTIME_UART))
+$(eval $(call add_define,RPI3_USE_UEFI_MAP))
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on rpi5)
+endif
+
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+PLAT_BL_COMMON_SOURCES	+=	drivers/rpi3/rng/rpi3_rng.c		\
+				plat/rpi/common/rpi3_stack_protector.c
+endif
diff --git a/plat/rpi/rpi5/rpi5_setup.c b/plat/rpi/rpi5/rpi5_setup.c
new file mode 100644
index 0000000..de82300
--- /dev/null
+++ b/plat/rpi/rpi5/rpi5_setup.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <rpi_shared.h>
+
+void plat_rpi_bl31_custom_setup(void)
+{
+	/* Nothing to do here yet. */
+}
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index fd86020..798c033 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -255,11 +255,6 @@
 		mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
 	}
 
-#if STM32MP15
-	/* Disable MCKPROT */
-	mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
-#endif
-
 	/*
 	 * Set minimum reset pulse duration to 31ms for discrete power
 	 * supplied boards.
diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
index b46f4af..245b2d3 100644
--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c
+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -182,6 +182,9 @@
 
 	stm32mp_gic_init();
 
+	/* Disable MCU subsystem protection */
+	stm32mp1_clk_mcuss_protect(false);
+
 	if (stm32_iwdg_init() < 0) {
 		panic();
 	}