Merge changes Id72a0370,I2bafba38,I2bd48441,I164c579c,Iddf8aea0, ... into integration

* changes:
  feat(rpi): add Raspberry Pi 5 support
  fix(rpi): consider MT when calculating core index from MPIDR
  refactor(rpi): move register definitions out of rpi_hw.h
  refactor(rpi): add platform macro for the crash UART base address
  refactor(rpi): split out console registration logic
  refactor(rpi): move more platform-specific code into common
diff --git a/.cz-adapter.cjs b/.cz-adapter.cjs
new file mode 100644
index 0000000..26aaeb2
--- /dev/null
+++ b/.cz-adapter.cjs
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * A workaround for:
+ *
+ *     https://github.com/conventional-changelog/commitlint/issues/3949
+ */
+
+exports.prompter = async (inquirerIns, commit) => {
+    ; (await import('@commitlint/cz-commitlint')).prompter(inquirerIns, commit)
+}
diff --git a/.cz.json b/.cz.json
index 556c39f..969a73b 100644
--- a/.cz.json
+++ b/.cz.json
@@ -1,3 +1,3 @@
 {
-    "path": "@commitlint/cz-commitlint"
+    "path": "./.cz-adapter.cjs"
 }
diff --git a/.husky/commit-msg b/.husky/commit-msg
index c1c9600..b5d407b 100755
--- a/.husky/commit-msg
+++ b/.husky/commit-msg
@@ -1,7 +1,4 @@
 #!/bin/sh
 
-# shellcheck source=./_/husky.sh
-. "$(dirname "$0")/_/husky.sh"
-
 "$(dirname "$0")/commit-msg.gerrit" "$@"
 "$(dirname "$0")/commit-msg.commitlint" "$@"
diff --git a/.husky/pre-commit b/.husky/pre-commit
index afcb1f6..f438ddb 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,6 +1,3 @@
 #!/bin/sh
 
-# shellcheck source=./_/husky.sh
-. "$(dirname "$0")/_/husky.sh"
-
 "$(dirname "$0")/pre-commit.copyright" "$@"
diff --git a/Makefile b/Makefile
index 6a1ea99..800346a 100644
--- a/Makefile
+++ b/Makefile
@@ -155,11 +155,9 @@
 	endif
 
 else ifeq ($($(ARCH)-cc-id),gnu-gcc)
-	ifeq ($(ENABLE_LTO),1)
-		# Enable LTO only for aarch64
-		ifeq (${ARCH},aarch64)
-			LTO_CFLAGS	=	-flto
-		endif
+	# Enable LTO only for aarch64
+	ifeq (${ARCH},aarch64)
+		LTO_CFLAGS	=	$(if $(filter-out 0,$(ENABLE_LTO)),-flto)
 	endif
 endif #(clang)
 
@@ -325,6 +323,7 @@
 	ifeq ($(ENABLE_LTO),1)
 		ifeq (${ARCH},aarch64)
 			TF_LDFLAGS	+=	-flto -fuse-linker-plugin
+			TF_LDFLAGS      +=	-flto-partition=one
 		endif
 	endif #(ENABLE_LTO)
 
@@ -1146,6 +1145,7 @@
 	HARDEN_SLS \
 	HW_ASSISTED_COHERENCY \
 	MEASURED_BOOT \
+	DICE_PROTECTION_ENVIRONMENT \
 	DRTM_SUPPORT \
 	NS_TIMER_SWITCH \
 	OVERRIDE_LIBC \
@@ -1185,6 +1185,7 @@
 	COT_DESC_IN_DTB \
 	USE_SP804_TIMER \
 	PSA_FWU_SUPPORT \
+	PSA_FWU_METADATA_FW_STORE_DESC \
 	ENABLE_MPMM \
 	ENABLE_MPMM_FCONF \
 	FEATURE_DETECTION \
@@ -1312,6 +1313,7 @@
 	HW_ASSISTED_COHERENCY \
 	LOG_LEVEL \
 	MEASURED_BOOT \
+	DICE_PROTECTION_ENVIRONMENT \
 	DRTM_SUPPORT \
 	NS_TIMER_SWITCH \
 	PL011_GENERIC_UART \
@@ -1360,6 +1362,7 @@
 	NR_OF_FW_BANKS \
 	NR_OF_IMAGES_IN_FW_BANK \
 	PSA_FWU_SUPPORT \
+	PSA_FWU_METADATA_FW_STORE_DESC \
 	ENABLE_BRBE_FOR_NS \
 	ENABLE_TRBE_FOR_NS \
 	ENABLE_SYS_REG_TRACE_FOR_NS \
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index c8cc2c7..9807817 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -83,7 +83,7 @@
 /*******************************************************************************
  * Simple function to initialise all BL31 helper libraries.
  ******************************************************************************/
-void __init bl31_lib_init(void)
+static void __init bl31_lib_init(void)
 {
 	cm_init();
 }
diff --git a/bl31/bl31_traps.c b/bl31/bl31_traps.c
index d14a91e..f1b1fa6 100644
--- a/bl31/bl31_traps.c
+++ b/bl31/bl31_traps.c
@@ -97,7 +97,7 @@
  * NOTE: This piece of code must be reviewed every release to ensure that
  * we keep up with new ARCH features which introduces a new SPSR bit.
  */
-static u_register_t create_spsr(u_register_t old_spsr, unsigned int target_el)
+u_register_t create_spsr(u_register_t old_spsr, unsigned int target_el)
 {
 	u_register_t new_spsr = 0;
 	u_register_t sctlr;
diff --git a/bl31/ehf.c b/bl31/ehf.c
index 5b78ebb..3a14635 100644
--- a/bl31/ehf.c
+++ b/bl31/ehf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -203,10 +203,20 @@
 	 * one stashed earlier if there are no more to deactivate.
 	 */
 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
-	if (cur_pri_idx == EHF_INVALID_IDX)
+
+#if GIC600_ERRATA_WA_2384374
+	if (cur_pri_idx == EHF_INVALID_IDX) {
+		old_mask = plat_ic_deactivate_priority(pe_data->init_pri_mask);
+	} else {
+		old_mask = plat_ic_deactivate_priority(priority);
+	}
+#else
+	if (cur_pri_idx == EHF_INVALID_IDX) {
 		old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
-	else
+	} else {
 		old_mask = plat_ic_set_priority_mask(priority);
+	}
+#endif
 
 	if (old_mask > priority) {
 		ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c
index 68c7f10..a2b2c06 100644
--- a/bl31/interrupt_mgmt.c
+++ b/bl31/interrupt_mgmt.c
@@ -34,7 +34,7 @@
  *
  *           All other bits are reserved and SBZ.
  ******************************************************************************/
-typedef struct intr_type_desc {
+typedef struct {
 	interrupt_type_handler_t handler;
 	u_register_t scr_el3[2];
 	uint32_t flags;
diff --git a/changelog.yaml b/changelog.yaml
index 5135d69..3875a48 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -413,6 +413,9 @@
               - title: i.MX 8
                 scope: imx8
 
+              - title: i.MX 8ULP
+                scope: imx8ulp
+
               - title: i.MX 9
                 scope: imx9
 
@@ -804,6 +807,9 @@
         deprecated:
           - lib/psa
 
+      - title: DICE Protection Environment
+        scope: dice
+
       - title: Context Management
         scope: context-mgmt
 
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 4531a03..6d34339 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -524,13 +524,12 @@
 :|G|: `thomas-arm`_
 :|M|: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
 :|G|: `vijayenthiran-arm`_
-:|F|: plat/arm/css/sgi/
-:|F|: plat/arm/board/rde1edge/
-:|F|: plat/arm/board/rdn1edge/
-:|F|: plat/arm/board/rdn2/
-:|F|: plat/arm/board/rdv1/
-:|F|: plat/arm/board/rdv1mc/
-:|F|: plat/arm/board/sgi575/
+:|F|: plat/arm/board/neoverse_rd/common
+:|F|: plat/arm/board/neoverse_rd/platform/rdn1edge/
+:|F|: plat/arm/board/neoverse_rd/platform/rdn2/
+:|F|: plat/arm/board/neoverse_rd/platform/rdv1/
+:|F|: plat/arm/board/neoverse_rd/platform/rdv1mc/
+:|F|: plat/arm/board/neoverse_rd/platform/sgi575/
 
 Arm Total Compute platform port
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -646,6 +645,13 @@
 :|F|: docs/plat/imx8m.rst
 :|F|: plat/imx/imx8m/
 
+NXP i.MX8ULP platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jacky Bai <ping.bai@nxp.com>
+:|G|: `JackyBai`_
+:|F|: docs/plat/imx8ulp.rst
+:|F|: plat/imx/imx8ulp/
+
 NXP i.MX9 platform port
 ^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Jacky Bai <ping.bai@nxp.com>
@@ -811,6 +817,8 @@
 ^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Sumit Garg <sumit.garg@linaro.org>
 :|G|: `b49020`_
+:|M|: Masahisa Kojima <kojima.masahisa@socionext.com>
+:|G|: `masahisak`_
 :|F|: docs/plat/synquacer.rst
 :|F|: plat/socionext/synquacer/
 
@@ -970,6 +978,7 @@
 .. _lachitp: https://github.com/lachitp
 .. _marex: https://github.com/marex
 .. _masahir0y: https://github.com/masahir0y
+.. _masahisak: https://github.com/masahisak
 .. _michalsimek: https://github.com/michalsimek
 .. _mmind: https://github.com/mmind
 .. _MrVan: https://github.com/MrVan
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index 654d65f..d814104 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -81,8 +81,6 @@
 |                                | Date        | after   |                                                         |
 |                                |             | Release |                                                         |
 +================================+=============+=========+=========================================================+
-| Mbedtls-2.x                    |     2.10    |   2.10  | Support for TF-A builds with Mbedtls-2.x will be removed|
-+--------------------------------+-------------+---------+---------------------------------------------------------+
 | STM32MP15_OPTEE_RSV_SHM        |     2.10    |   3.0   | OP-TEE manages its own memory on STM32MP15              |
 +--------------------------------+-------------+---------+---------------------------------------------------------+
 
@@ -103,4 +101,4 @@
 
 --------------
 
-*Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/firmware-update.rst b/docs/components/firmware-update.rst
index 1ba1e1c..eda7852 100644
--- a/docs/components/firmware-update.rst
+++ b/docs/components/firmware-update.rst
@@ -494,4 +494,4 @@
 .. _Universally Unique Identifier: https://tools.ietf.org/rfc/rfc4122.txt
 .. |Flow Diagram| image:: ../resources/diagrams/fwu_flow.png
 .. |FWU state machine| image:: ../resources/diagrams/fwu_states.png
-.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/
diff --git a/docs/components/platform-interrupt-controller-API.rst b/docs/components/platform-interrupt-controller-API.rst
index 4de39d1..8cd4bae 100644
--- a/docs/components/platform-interrupt-controller-API.rst
+++ b/docs/components/platform-interrupt-controller-API.rst
@@ -282,9 +282,28 @@
 that it's overwriting.
 
 In case of Arm standard platforms using GIC, the implementation of the API
-inserts to order memory updates before updating mask, then writes to the GIC
-*Priority Mask Register*, and make sure memory updates are visible before
-potential trigger due to mask update.
+inserts barriers to order memory updates before updating mask,
+then writes to the GIC *Priority Mask Register*, and make sure memory updates
+are visible before potential trigger due to mask update.
+
+Function: unsigned int plat_ic_deactivate_priority(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API performs the operations of plat_ic_set_priority_mask along with
+calling the errata workaround gicv3_apply_errata_wa_2384374(). This is
+performed when priority mask is restored to it's older value. This API returns
+the current priority value that it's overwriting.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+inserts barriers to order memory updates before updating mask, then writes
+to the GIC *Priority Mask Register*, and make sure memory updates
+are visible before potential trigger due to mask update, and
+applies 2384374 GIC errata workaround to process pending interrupt packets.
 
 .. _plat_ic_get_interrupt_id:
 
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index abd9f87..4ee184c 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -787,14 +787,23 @@
   Cortex-X3 CPU. This needs to be enabled only for revisions r0p0 and r1p0
   of the CPU, it is fixed in r1p1.
 
+- ``ERRATA_X3_2372204``: This applies errata 2372204 workaround to
+  Cortex-X3 CPU. This needs to be enabled only for revisions r0p0 and r1p0
+  of the CPU, it is fixed in r1p1.
+
 - ``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.
   It is fixed in r1p1.
 
+- ``ERRATA_X3_2701951``: This applies erratum 2701951 workaround to Cortex-X3
+  CPU and affects system configurations that do not use an ARM interconnect
+  IP. This needs to be applied to revisions r0p0, r1p0 and r1p1. It is fixed
+  in r1p2.
+
 - ``ERRATA_X3_2742421``: This applies errata 2742421 workaround to
   Cortex-X3 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
   r1p1. It is fixed in r1p2.
@@ -807,6 +816,16 @@
   CPU. This needs to be enabled only for revisions r0p0, r1p0 and r1p1 of the
   CPU. It is fixed in r1p2.
 
+For Cortex-X4, the following errata build flags are defined :
+
+- ``ERRATA_X4_2701112``: This applies erratum 2701112 workaround to Cortex-X4
+  CPU and affects system configurations that do not use an Arm interconnect IP.
+  This needs to be enabled for revisions r0p0 and is fixed in r0p1.
+  The workaround for this erratum is not implemented in EL3, but the flag can
+  be enabled/disabled at the platform level. The flag is used when the errata ABI
+  feature is enabled and can assist the Kernel in the process of
+  mitigation of the erratum.
+
 For Cortex-A510, the following errata build flags are defined :
 
 -  ``ERRATA_A510_1922240``: This applies errata 1922240 workaround to
@@ -872,14 +891,36 @@
 
 For Cortex-A715, the following errata build flags are defined :
 
+-  ``ERRATA_A715_2331818``: This applies errata 2331818 workaround to
+   Cortex-A715 CPU. This needs to be enabled for revisions r0p0 and r1p0.
+   It is fixed in r1p1.
+
+- ``ERRATA_A715_2344187``: This applies errata 2344187 workaround to
+   Cortex-A715 CPU. This needs to be enabled for revisions r0p0 and r1p0. It is
+   fixed in r1p1.
+
+-  ``ERRATA_A715_2413290``: This applies errata 2413290 workaround to
+   Cortex-A715 CPU. This needs to be enabled only for revision r1p0 and
+   when SPE(Statistical profiling extension)=True. The errata is fixed
+   in r1p1.
+
+-  ``ERRATA_A715_2420947``: This applies errata 2420947 workaround to
+   Cortex-A715 CPU. This needs to be enabled only for revision r1p0.
+   It is fixed in r1p1.
+
+-  ``ERRATA_A715_2429384``: This applies errata 2429384 workaround to
+   Cortex-A715 CPU. This needs to be enabled for revision r1p0. There is no
+   workaround for revision r0p0. It is fixed in r1p1.
+
 -  ``ERRATA_A715_2561034``: This applies errata 2561034 workaround to
    Cortex-A715 CPU. This needs to be enabled only for revision r1p0.
    It is fixed in r1p1.
 
--  ``ERRATA_A715_2701951``: This applies erratum 2701951 workaround to Cortex-A715
-   CPU and affects system configurations that do not use an ARM interconnect
-   IP. This needs to be applied to revisions r0p0, r1p0 and r1p1. It is fixed
-   in r1p2.
+For Cortex-A720, the following errata build flags are defined :
+
+-  ``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 ba97264..fa06c8e 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -645,6 +645,35 @@
 Data structures used in the BL31 cold boot interface
 ''''''''''''''''''''''''''''''''''''''''''''''''''''
 
+In the cold boot flow, ``entry_point_info`` is used to represent the execution
+state of an image; that is, the state of general purpose registers, PC, and
+SPSR.
+
+There are two variants of this structure, for AArch64:
+
+.. code:: c
+
+   typedef struct entry_point_info {
+        param_header_t h;
+        uintptr_t pc;
+        uint32_t spsr;
+
+        aapcs64_params_t args;
+   }
+
+and, AArch32:
+
+.. code:: c
+
+   typedef struct entry_point_info {
+      param_header_t h;
+      uintptr_t pc;
+      uint32_t spsr;
+
+      uintptr_t lr_svc;
+      aapcs32_params_t args;
+   } entry_point_info_t;
+
 These structures are designed to support compatibility and independent
 evolution of the structures and the firmware images. For example, a version of
 BL31 that can interpret the BL3x image information from different versions of
@@ -662,13 +691,17 @@
         uint8_t type;       /* type of the structure */
         uint8_t version;    /* version of this structure */
         uint16_t size;      /* size of this structure in bytes */
-        uint32_t attr;      /* attributes: unused bits SBZ */
+        uint32_t attr;      /* attributes */
     } param_header_t;
 
-The structures using this format are ``entry_point_info``, ``image_info`` and
-``bl31_params``. The code that allocates and populates these structures must set
-the header fields appropriately, and the ``SET_PARAM_HEAD()`` a macro is defined
-to simplify this action.
+In `entry_point_info`, Bits 0 and 5 of ``attr`` field are used to encode the
+security state; in other words, whether the image is to be executed in Secure,
+Non-Secure, or Realm mode.
+
+Other structures using this format are ``image_info`` and ``bl31_params``. The
+code that allocates and populates these structures must set the header fields
+appropriately, the ``SET_PARAM_HEAD()`` macro is defined to simplify this
+action.
 
 Required CPU state for BL31 Warm boot initialization
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
index 10fb7fb..f10d2e7 100644
--- a/docs/design/trusted-board-boot.rst
+++ b/docs/design/trusted-board-boot.rst
@@ -84,20 +84,20 @@
 
 -  **Root of trust key**
 
-   The private part of this key is used to sign the BL2 content certificate and
-   the trusted key certificate. The public part is the ROTPK.
+   The private part of this key is used to sign the trusted boot firmware
+   certificate and the trusted key certificate. The public part is the ROTPK.
 
 -  **Trusted world key**
 
    The private part is used to sign the key certificates corresponding to the
    secure world images (SCP_BL2, BL31 and BL32). The public part is stored in
-   one of the extension fields in the trusted world certificate.
+   one of the extension fields in the trusted key certificate.
 
 -  **Non-trusted world key**
 
    The private part is used to sign the key certificate corresponding to the
-   non secure world image (BL33). The public part is stored in one of the
-   extension fields in the trusted world certificate.
+   non-secure world image (BL33). The public part is stored in one of the
+   extension fields in the trusted key certificate.
 
 -  **BL3X keys**
 
@@ -116,10 +116,11 @@
 
 The following certificates are used to authenticate the images.
 
--  **BL2 content certificate**
+-  **Trusted boot firmware certificate**
 
-   It is self-signed with the private part of the ROT key. It contains a hash
-   of the BL2 image.
+   It is self-signed with the private part of the ROT key. It contains a hash of
+   the BL2 image and hashes of various firmware configuration files
+   (TB_FW_CONFIG, HW_CONFIG, FW_CONFIG).
 
 -  **Trusted key certificate**
 
@@ -127,45 +128,48 @@
    public part of the trusted world key and the public part of the non-trusted
    world key.
 
--  **SCP_BL2 key certificate**
+-  **SCP firmware key certificate**
 
    It is self-signed with the trusted world key. It contains the public part of
    the SCP_BL2 key.
 
--  **SCP_BL2 content certificate**
+-  **SCP firmware content certificate**
 
    It is self-signed with the SCP_BL2 key. It contains a hash of the SCP_BL2
    image.
 
--  **BL31 key certificate**
+-  **SoC firmware key certificate**
 
    It is self-signed with the trusted world key. It contains the public part of
    the BL31 key.
 
--  **BL31 content certificate**
+-  **SoC firmware content certificate**
 
-   It is self-signed with the BL31 key. It contains a hash of the BL31 image.
+   It is self-signed with the BL31 key. It contains hashes of the BL31 image and
+   its configuration file (SOC_FW_CONFIG).
 
--  **BL32 key certificate**
+-  **Trusted OS key certificate**
 
    It is self-signed with the trusted world key. It contains the public part of
    the BL32 key.
 
--  **BL32 content certificate**
+-  **Trusted OS content certificate**
 
-   It is self-signed with the BL32 key. It contains a hash of the BL32 image.
+   It is self-signed with the BL32 key. It contains hashes of the BL32 image(s)
+   and its configuration file(s) (TOS_FW_CONFIG).
 
--  **BL33 key certificate**
+-  **Non-trusted firmware key certificate**
 
    It is self-signed with the non-trusted world key. It contains the public
    part of the BL33 key.
 
--  **BL33 content certificate**
+-  **Non-trusted firmware content certificate**
 
-   It is self-signed with the BL33 key. It contains a hash of the BL33 image.
+   It is self-signed with the BL33 key. It contains hashes of the BL33 image and
+   its configuration file (NT_FW_CONFIG).
 
-The SCP_BL2 and BL32 certificates are optional, but they must be present if the
-corresponding SCP_BL2 or BL32 images are present.
+The SCP firmware and Trusted OS certificates are optional, but they must be
+present if the corresponding SCP_BL2 or BL32 images are present.
 
 The following diagram summarizes the part of the TBBR CoT enforced by BL2. Some
 images (SCP, debug certificates, secure partitions, configuration files) are not
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 37545ce..f817da0 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -706,6 +706,13 @@
 
    This option defaults to 0.
 
+-  ``DICE_PROTECTION_ENVIRONMENT``: Boolean flag to specify the measured boot
+   backend when ``MEASURED_BOOT`` is enabled. The default value is ``0``. When
+   set to ``1`` then measurements and additional metadata collected during the
+   measured boot process are sent to the DICE Protection Environment for storage
+   and processing. A certificate chain, which represents the boot state of the
+   device, can be queried from the DPE.
+
 -  ``MARCH_DIRECTIVE``: used to pass a -march option from the platform build
    options to the compiler. An example usage:
 
@@ -1340,12 +1347,21 @@
    This flag is used in defining the firmware update metadata structure. This
    flag is by default set to '1'.
 
+- ``PSA_FWU_METADATA_FW_STORE_DESC``: To be enabled when the FWU
+   metadata contains image description. The default value is 1.
+
+   The version 2 of the FWU metadata allows for an opaque metadata
+   structure where a platform can choose to not include the firmware
+   store description in the metadata structure. This option indicates
+   if the firmware store description, which provides information on
+   the updatable images is part of the structure.
+
 --------------
 
 *Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
 
 .. _DEN0115: https://developer.arm.com/docs/den0115/latest
-.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/
 .. _PSA DRTM specification: https://developer.arm.com/documentation/den0113/a
 .. _GCC: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
 .. _Clang: https://clang.llvm.org/docs/DiagnosticsReference.html
diff --git a/docs/getting_started/prerequisites.rst b/docs/getting_started/prerequisites.rst
index 573abdf..9053e34 100644
--- a/docs/getting_started/prerequisites.rst
+++ b/docs/getting_started/prerequisites.rst
@@ -79,6 +79,10 @@
 
 - mbed TLS == 3.4.1 (tag: ``mbedtls-3.4.1``)
 
+The following libraries are required for DICE Protection Environment support:
+
+- QCBOR == 1.2 (tag: ``v1.2``)
+
 These tools are optional:
 
 - Device Tree Compiler (DTC) >= 1.4.7
@@ -184,7 +188,7 @@
 
 --------------
 
-*Copyright (c) 2021-2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2021-2024, Arm Limited. All rights reserved.*
 
 .. _Arm Developer website: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads
 .. _Gerrit Code Review: https://www.gerritcodereview.com/
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 679de2b..c02e938 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -40,6 +40,9 @@
       Common Vulnerabilities and Exposures. A CVE document is commonly used to
       describe a publicly-known security vulnerability.
 
+   DICE
+      Device Identifier Composition Engine
+
    DCE
       DRTM Configuration Environment
 
@@ -52,6 +55,9 @@
    DRTM
       Dynamic Root of Trust for Measurement
 
+   DPE
+      DICE Protection Environment
+
    DS-5
       Arm Development Studio 5
 
diff --git a/docs/index.rst b/docs/index.rst
index cdb237a..c05c0a5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -95,4 +95,4 @@
 .. _System Control and Management Interface (SCMI): http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf
 .. _Software Delegated Exception Interface (SDEI): http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
 .. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
-.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/
diff --git a/docs/license.rst b/docs/license.rst
index 80f1118..8996105 100644
--- a/docs/license.rst
+++ b/docs/license.rst
@@ -85,6 +85,17 @@
 
    See the original `Linux MIT license`_.
 
+-  Some source files originating from the `Open Profile for DICE`_ project.
+   These files are licensed under the Apache License, Version 2.0, which is a
+   permissive license compatible with BSD-3-Clause. Any contributions to this
+   code must also be made under the terms of `Apache License 2.0`_.
+   These files are:
+
+   -  ``include/lib/dice/dice.h``
+
 .. _FreeBSD: http://www.freebsd.org
 .. _Linux MIT license: https://raw.githubusercontent.com/torvalds/linux/master/LICENSES/preferred/MIT
 .. _SCC: http://www.simple-cc.org/
+.. _Open Profile for DICE: https://pigweed.googlesource.com/open-dice/
+.. _Apache License 2.0: https://www.apache.org/licenses/LICENSE-2.0.txt
+
diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst
index 3301067..e1b3ef0 100644
--- a/docs/plat/arm/arm-build-options.rst
+++ b/docs/plat/arm/arm-build-options.rst
@@ -121,17 +121,6 @@
    management operations and for SCP RAM Firmware transfer. If this option
    is set to 1, then SCMI/SDS drivers will be used. Default is 0.
 
- - ``CSS_SGI_CHIP_COUNT``: Configures the number of chips on a SGI/RD platform
-   which supports multi-chip operation. If ``CSS_SGI_CHIP_COUNT`` is set to any
-   valid value greater than 1, the platform code performs required configuration
-   to support multi-chip operation.
-
-- ``CSS_SGI_PLATFORM_VARIANT``: Selects the variant of a SGI/RD platform. A
-    particular SGI/RD platform may have multiple variants which may differ in
-    core count, cluster count or other peripherals. This build option is used
-    to select the appropriate platform variant for the build. The range of
-    valid values is platform specific.
-
 - ``CSS_SYSTEM_GRACEFUL_RESET``: Build option to enable graceful powerdown of
    CPU core on reset. This build option can be used on CSS platforms that
    require all the CPUs to execute the CPU specific power down sequence to
@@ -152,8 +141,22 @@
    AArch64 and facilitates the loading of ``SP_MIN`` and BL33 as AArch32 executable
    images.
 
+Arm Neoverse RD Platform Build Options
+--------------------------------------
+
+ - ``NRD_CHIP_COUNT``: Configures the number of chips on a Neoverse RD platform
+   which supports multi-chip operation. If ``NRD_CHIP_COUNT`` is set to any
+   valid value greater than 1, the platform code performs required configuration
+   to support multi-chip operation.
+
+- ``NRD_PLATFORM_VARIANT``: Selects the variant of a Neoverse RD platform. A
+  particular Neoverse RD platform may have multiple variants which may differ in
+  core count, cluster count or other peripherals. This build option is used to
+  select the appropriate platform variant for the build. The range of valid
+  values is platform specific.
+
 --------------
 
 .. |FIP in a GPT image| image:: ../../resources/diagrams/FIP_in_a_GPT_image.png
 
-*Copyright (c) 2019-2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
diff --git a/docs/plat/imx8ulp.rst b/docs/plat/imx8ulp.rst
new file mode 100644
index 0000000..b6b13e2
--- /dev/null
+++ b/docs/plat/imx8ulp.rst
@@ -0,0 +1,69 @@
+NXP i.MX 8ULP
+==================
+
+i.MX 8ULP is part of the ULP family with emphasis on extreme low-power techniques
+using the 28 nm fully depleted silicon on insulator process. Like i.MX 7ULP,
+i.MX 8ULP continues to be based on asymmetric architecture.
+
+The i.MX 8ULP family of processors features NXP’s advanced implementation of the
+dual Arm Cortex-A35 cores alongside an Arm Cortex-M33. This combined architecture
+enables the device to run a rich operating system (such as Linux) on the Cortex-A35
+core and an RTOS (such as FreeRTOS) on the Cortex-M33 core. It also includes a Cadence
+Tensilica Fusion DSP for low-power audio and a HiFi4 DSP for advanced audio and machine
+learning applications.
+
+The design enables clean separation between two processing domains, where each has
+separate power, clocking and peripheral islands, but the bus fabric of each domain
+is tightly integrated for efficient communication. The part is streamlined to minimize
+pin count, enabling small packages and simple system integration. This microprocessor
+is intended for applications where efficiency and simple system integration is important.
+`i.MX8ULP Applications Processors`_.
+
+Boot Sequence
+-------------
+
+BootROM --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel
+
+How to build
+------------
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Prepare AARCH64 toolchain.
+
+- Get the ELE FW image from NXP linux SDK package
+
+-  Build SPL and u-boot firstly, and get binary images: u-boot-spl.bin,
+   u-boot.bin and dtb
+
+-  Build TF-A
+
+   Build bl31:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
+
+   Target_SoC should be "imx8ulp" for i.MX8ULP SoC.
+
+Deploy TF-A Images
+~~~~~~~~~~~~~~~~~~
+
+TF-A binary(bl31.bin), u-boot-spl.bin u-boot.bin, ELE FW image are combined
+together to generate a binary file called flash.bin, the imx-mkimage tool is
+used to generate flash.bin, and flash.bin needs to be flashed into SD card
+with certain offset for BOOT ROM.
+
+Reference Documentation
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Details on how to prepare, generate & deploy the boot image be found in following documents:
+
+- i.MX Linux User's Guide
+  `link <https://www.nxp.com/design/software/embedded-software/i-mx-software/embedded-linux-for-i-mx-applications-processors:IMXLINUX>`__
+- i.MX Linux Reference Manual
+  `link <https://www.nxp.com/design/software/embedded-software/i-mx-software/embedded-linux-for-i-mx-applications-processors:IMXLINUX>`__
+
+.. _i.MX8ULP Applications Processors: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors/i-mx-8-applications-processors/i-mx-8ulp-applications-processor-family:i.MX8ULP
+
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 795fb09..35cc27d 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -27,6 +27,7 @@
    warp7
    imx8
    imx8m
+   imx8ulp
    imx9
    npcm845x
    nxp/index
@@ -60,7 +61,6 @@
 
    - Arm Neoverse N1 System Development Platform (N1SDP)
    - Arm Neoverse Reference Design N1 Edge (RD-N1-Edge) FVP
-   - Arm Neoverse Reference Design E1 Edge (RD-E1-Edge) FVP
    - Arm SGI-575
    - MediaTek MT8173 SoCs
 
@@ -82,9 +82,9 @@
 +----------------+----------------+--------------------+--------------------+
 |    tc1         |      Arm       |        2.10        |       TBD          |
 +----------------+----------------+--------------------+--------------------+
-|    rde1edge    |      Arm       |        2.9         |       3.0          |
+|    rde1edge    |      Arm       |        2.9         |       2.11         |
 +----------------+----------------+--------------------+--------------------+
 
 --------------
 
-*Copyright (c) 2019-2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
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/plat/xilinx-versal-net.rst b/docs/plat/xilinx-versal-net.rst
index 3f31d40..e9dd772 100644
--- a/docs/plat/xilinx-versal-net.rst
+++ b/docs/plat/xilinx-versal-net.rst
@@ -53,3 +53,46 @@
     -   `5`   : SGI 5
     -   `6`   : SGI 6 (Default)
     -   `7`   : SGI 7
+
+Reference DEN0028E SMC calling convention
+------------------------------------------
+
+Allocated subranges of Function Identifier to SIP services
+-----------------------------------------------------------
+
++-----------------------+-------------------------------------------------------+
+|    SMC Function       | Identifier Service type                               |
++-----------------------+------------------------------+------------------------+
+| 0xC2000000-0xC200FFFF | Fast SMC64 SiP Service Calls as per SMCCC Section 6.1 |
++-----------------------+-------------------------------------------------------+
+
+IPI SMC call ranges
+-------------------------------------------------------------
+
++---------------------------+-----------------------------------------------------------+
+| SMC Function Identifier   | Service type                                              |
++---------------------------+-----------------------------------------------------------+
+| 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
++---------------------------+-----------------------------------------------------------+
+
+PM SMC call ranges
+--------------------------------------------------------
+
++---------------------------+---------------------------------------------------------------------------+
+|   SMC Function Identifier |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
++---------------------------+---------------------------------------------------------------------------+
+
+SMC function IDs for SiP Service queries
+----------------------------------------------
+
++--------------+--------------+--------------+
+|  Service     | Call UID     | Revision     |
++--------------+--------------+--------------+
+|  SiP Service | 0x8200_FF01  | 0x8200_FF03  |
++--------------+--------------+--------------+
+
+Call UID Query – Returns a unique identifier of the service provider.
+
+Revision Query – Returns revision details of the service implementor.
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
index aa094f7..072329a 100644
--- a/docs/plat/xilinx-versal.rst
+++ b/docs/plat/xilinx-versal.rst
@@ -76,3 +76,46 @@
 data structure is passed in the ```PMC_GLOBAL_GLOB_GEN_STORAGE4``` register.
 The register is free to be used by other software once the TF-A is bringing up
 further firmware images.
+
+Reference DEN0028E SMC calling convention
+------------------------------------------
+
+Allocated subranges of Function Identifier to SIP services
+----------------------------------------------------------
+
++-----------------------+-------------------------------------------------------+
+|    SMC Function       | Identifier Service type                               |
++-----------------------+-------------------------------------------------------+
+| 0xC2000000-0xC200FFFF | Fast SMC64 SiP Service Calls as per SMCCC Section 6.1 |
++-----------------------+-------------------------------------------------------+
+
+IPI SMC call ranges
+-------------------
+
++---------------------------+-----------------------------------------------------------+
+| SMC Function Identifier   | Service type                                              |
++---------------------------+-----------------------------------------------------------+
+| 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
++---------------------------+-----------------------------------------------------------+
+
+PM SMC call ranges
+------------------
+
++---------------------------+---------------------------------------------------------------------------+
+|   SMC Function Identifier |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
++---------------------------+---------------------------------------------------------------------------+
+
+SMC function IDs for SiP Service queries
+----------------------------------------
+
++--------------+--------------+--------------+
+|  Service     | Call UID     | Revision     |
++--------------+--------------+--------------+
+|  SiP Service | 0x8200_FF01  | 0x8200_FF03  |
++--------------+--------------+--------------+
+
+Call UID Query – Returns a unique identifier of the service provider.
+
+Revision Query – Returns revision details of the service implementor.
diff --git a/docs/plat/xilinx-zynqmp.rst b/docs/plat/xilinx-zynqmp.rst
index 4fe0d2f..c8ba27f 100644
--- a/docs/plat/xilinx-zynqmp.rst
+++ b/docs/plat/xilinx-zynqmp.rst
@@ -166,3 +166,55 @@
 - TF-A build command:
   make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp RESET_TO_BL31=1
   bl31 CUSTOM_PKG_PATH=<...>
+
+Reference DEN0028E SMC calling convention
+------------------------------------------
+
+Allocated subranges of Function Identifier to SIP services
+------------------------------------------------------------
+
++-----------------------+-------------------------------------------------------+
+|    SMC Function       | Identifier Service type                               |
++-----------------------+-------------------------------------------------------+
+| 0xC2000000-0xC200FFFF | Fast SMC64 SiP Service Calls as per SMCCC Section 6.1 |
++-----------------------+-------------------------------------------------------+
+
+IPI SMC call ranges
+-------------------
+
++---------------------------+-----------------------------------------------------------+
+| SMC Function Identifier   | Service type                                              |
++---------------------------+-----------------------------------------------------------+
+| 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
++---------------------------+-----------------------------------------------------------+
+
+PM SMC call ranges
+------------------
+
++---------------------------+---------------------------------------------------------------------------+
+| SMC Function Identifier   |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
++---------------------------+---------------------------------------------------------------------------+
+
+SMC function IDs for SiP Service queries
+----------------------------------------
+
++--------------+--------------+--------------+
+|  Service     | Call UID     | Revision     |
++--------------+--------------+--------------+
+|  SiP Service | 0x8200_FF01  | 0x8200_FF03  |
++--------------+--------------+--------------+
+
+Call UID Query – Returns a unique identifier of the service provider.
+
+Revision Query – Returns revision details of the service implementor.
+
+CUSTOM SIP service support
+--------------------------
+
++-------------+------------+------------+
+| Service     | 32-bit     | 64-bit     |
++-------------+------------+------------+
+| SiP Service | 0x82002000 | 0xC2002000 |
++-------------+------------+------------+
diff --git a/docs/threat_model/firmware_threat_model/threat_model.rst b/docs/threat_model/firmware_threat_model/threat_model.rst
index 63bdc8a..f8e4f7d 100644
--- a/docs/threat_model/firmware_threat_model/threat_model.rst
+++ b/docs/threat_model/firmware_threat_model/threat_model.rst
@@ -623,6 +623,62 @@
 |                        |   UART interface(s).                                |
 +------------------------+-----------------------------------------------------+
 
++------------------------+-----------------------------------------------------+
+| ID                     | 16                                                  |
++========================+=====================================================+
+| Threat                 | | **An attacker could analyse the timing behaviour  |
+|                        |     of implemented methods in the system to infer   |
+|                        |     sensitive information.**                        |
+|                        |                                                     |
+|                        | | A timing side-channel attack is a type of attack  |
+|                        |   that exploits variations in the time it takes a   |
+|                        |   system to perform different operations. This      |
+|                        |   form of attack focuses on analyzing the time-     |
+|                        |   related information leakage that occurs during    |
+|                        |   the execution of cryptographic algorithms or      |
+|                        |   other security-sensitive processes. By observing  |
+|                        |   these timing differences, an attacker can gain    |
+|                        |   insights into the internal workings of a system   |
+|                        |   and potentially extract sensitive information.    |
+|                        |   Sensitive information that, when revealed even    |
+|                        |   partially, could heighten the susceptibility to   |
+|                        |   traditional attacks like brute-force attacks.     |
++------------------------+-----------------------------------------------------+
+| Diagram Elements       | DF2                                                 |
++------------------------+-----------------------------------------------------+
+| Affected TF-A          | BL1, BL2, BL31                                      |
+| Components             |                                                     |
++------------------------+-----------------------------------------------------+
+| Assets                 | Sensitive Data                                      |
++------------------------+-----------------------------------------------------+
+| Threat Agent           | AppDebug                                            |
++------------------------+-----------------------------------------------------+
+| Threat Type            | Information Disclosure                              |
++------------------------+------------------+----------------+-----------------+
+| Application            | Server           | IoT            | Mobile          |
++------------------------+------------------+----------------+-----------------+
+| Impact                 | Critical (5)     | Critical (5)   | Critical (5)    |
++------------------------+------------------+----------------+-----------------+
+| Likelihood             | Critical (5)     | Critical (5)   | Critical (5)    |
++------------------------+------------------+----------------+-----------------+
+| Total Risk Rating      | Critical (25)    | Critical (25)  | Critical (25)   |
++------------------------+------------------+----------------+-----------------+
+| Mitigations            | |  Ensure that the execution time of critical       |
+|                        |    operations is constant and independent of        |
+|                        |    secret data. This prevents attackers from        |
+|                        |    exploiting timing differences to infer           |
+|                        |    information about sensitive data.                |
+|                        |                                                     |
+|                        | |  Introduce random delays/timing jitter or dummy   |
+|                        |    operations to make the timing behavior of program|
+|                        |    execution less predictable. This can disrupt the |
+|                        |    correlation between the execution time and       |
+|                        |    sensitive data.                                  |
+|                        |                                                     |
++------------------------+-----------------------------------------------------+
+| Mitigations            | |  Not implemented                                  |
+| implemented?           |                                                     |
++------------------------+-----------------------------------------------------+
 
 .. _Boot Firmware Threats:
 
diff --git a/drivers/arm/css/sds/sds.c b/drivers/arm/css/sds/sds.c
index a5e6389..91f0a27 100644
--- a/drivers/arm/css/sds/sds.c
+++ b/drivers/arm/css/sds/sds.c
@@ -250,7 +250,7 @@
 	uintptr_t sds_mem_base = sds_regions[region_id].base;
 
 	if (!IS_SDS_REGION_VALID(sds_mem_base)) {
-		WARN("SDS: No valid SDS Memory Region found\n");
+		VERBOSE("SDS: No valid SDS Memory Region found\n");
 		return SDS_ERR_FAIL;
 	}
 
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/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 3190f66..8ea164c 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -1321,6 +1321,31 @@
 }
 
 /*******************************************************************************
+ * This function restores the PMR register to old value and also triggers
+ * gicv3_apply_errata_wa_2384374() that flushes the GIC buffer allowing any
+ * pending interrupts to processed. Returns the original PMR.
+ ******************************************************************************/
+unsigned int gicv3_deactivate_priority(unsigned int mask)
+{
+
+	unsigned int old_mask, proc_num;
+	uintptr_t gicr_base;
+
+	old_mask = gicv3_set_pmr(mask);
+
+	proc_num = plat_my_core_pos();
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base != 0UL);
+
+	/* Add DSB to ensure visibility of System register writes */
+	dsb();
+
+	gicv3_apply_errata_wa_2384374(gicr_base);
+
+	return old_mask;
+}
+
+/*******************************************************************************
  * This function delegates the responsibility of discovering the corresponding
  * Redistributor frames to each CPU itself. It is a modified version of
  * gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform
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/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
index 6c6f978..6932e61 100644
--- a/drivers/arm/smmu/smmu_v3.c
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -69,16 +69,31 @@
 	return smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U);
 }
 
-/*
- * Initialize the SMMU by invalidating all secure caches and TLBs.
- * Abort all incoming transactions in order to implement a default
- * deny policy on reset
- */
+/* Initialize the SMMU by invalidating all secure caches and TLBs. */
 int __init smmuv3_init(uintptr_t smmu_base)
 {
-	/* Abort all incoming transactions */
-	if (smmuv3_security_init(smmu_base) != 0)
+	/*
+	 * Initiate invalidation of secure caches and TLBs if the SMMU
+	 * supports secure state. If not, it's implementation defined
+	 * as to how SMMU_S_INIT register is accessed.
+	 * As per Arm SMMUv3 specification the SMMU_S_INIT register in a SMMU
+	 * with RME implementation has following properties:
+	 * a) all SMMU registers that are specified to be accessible only in
+	 *    the Secure physical address space are additionally accessible in
+	 *    Root physical address space.
+	 * b) as GPT information is permitted to be cached in a TLB, the
+	 *    SMMU_S_INIT.INV_ALL operation also invalidates all GPT information
+	 *    cached in TLBs.
+	 * Additionally, it is Root firmware’s responsibility to write to
+	 * INV_ALL before enabling SMMU_ROOT_CR0.{ACCESSEN,GPCEN}.
+	 */
+	mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL);
+
+	/* Wait for global invalidation operation to finish */
+	if (smmuv3_poll(smmu_base + SMMU_S_INIT,
+			SMMU_S_INIT_INV_ALL, 0U) != 0) {
 		return -1;
+	}
 
 #if ENABLE_RME
 
@@ -137,23 +152,7 @@
 
 #endif /* ENABLE_RME */
 
-	/*
-	 * Initiate invalidation of secure caches and TLBs if the SMMU
-	 * supports secure state. If not, it's implementation defined
-	 * as to how SMMU_S_INIT register is accessed.
-	 * Arm SMMU Arch RME supplement, section 3.4: all SMMU registers
-	 * specified to be accessible only in secure physical address space are
-	 * additionally accessible in root physical address space in an SMMU
-	 * with RME.
-	 * Section 3.3: as GPT information is permitted to be cached in a TLB,
-	 * the SMMU_S_INIT.INV_ALL mechanism also invalidates GPT information
-	 * cached in TLBs.
-	 */
-	mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL);
-
-	/* Wait for global invalidation operation to finish */
-	return smmuv3_poll(smmu_base + SMMU_S_INIT,
-				SMMU_S_INIT_INV_ALL, 0U);
+	return 0;
 }
 
 int smmuv3_ns_set_abort_all(uintptr_t smmu_base)
diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c
index 608866c..8c5ff9d 100644
--- a/drivers/auth/auth_mod.c
+++ b/drivers/auth/auth_mod.c
@@ -328,7 +328,6 @@
 	unsigned int data_len, len, i;
 	unsigned int plat_nv_ctr;
 	int rc;
-	bool is_trial_run = false;
 
 	/* Get the counter value from current image. The AM expects the IPM
 	 * to return the counter value as a DER encoded integer */
@@ -388,9 +387,14 @@
 		return 1;
 	} else if (*cert_nv_ctr > plat_nv_ctr) {
 #if PSA_FWU_SUPPORT && IMAGE_BL2
-		is_trial_run = fwu_is_trial_run_state();
+		if (fwu_get_active_bank_state() == FWU_BANK_STATE_ACCEPTED) {
+			*need_nv_ctr_upgrade = true;
+		} else {
+			*need_nv_ctr_upgrade = false;
+		}
+#else
+		*need_nv_ctr_upgrade = true;
 #endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */
-		*need_nv_ctr_upgrade = !is_trial_run;
 	}
 
 	return 0;
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
index a2c6430..2bb23f9 100644
--- a/drivers/auth/mbedtls/mbedtls_common.mk
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2015-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -19,16 +19,15 @@
 MBEDTLS_MINOR=$(shell grep -hP "define MBEDTLS_VERSION_MINOR" ${MBEDTLS_DIR}/include/mbedtls/*.h | grep -oe '\([0-9.]*\)')
 $(info MBEDTLS_VERSION_MAJOR is [${MBEDTLS_MAJOR}] MBEDTLS_VERSION_MINOR is [${MBEDTLS_MINOR}])
 
+ifneq (${MBEDTLS_MAJOR}, 3)
+  $(error Error: TF-A only supports MbedTLS versions > 3.x)
+endif
+
 # Specify mbed TLS configuration file
-ifeq (${MBEDTLS_MAJOR}, 2)
-        $(info Deprecation Notice: Please migrate to Mbedtls version 3.x (refer to TF-A documentation for the exact version number))
-	MBEDTLS_CONFIG_FILE             ?=	"<drivers/auth/mbedtls/mbedtls_config-2.h>"
-else ifeq (${MBEDTLS_MAJOR}, 3)
-	ifeq (${PSA_CRYPTO},1)
-		MBEDTLS_CONFIG_FILE     ?=      "<drivers/auth/mbedtls/psa_mbedtls_config.h>"
-	else
-		MBEDTLS_CONFIG_FILE	?=	"<drivers/auth/mbedtls/mbedtls_config-3.h>"
-	endif
+ifeq (${PSA_CRYPTO},1)
+  MBEDTLS_CONFIG_FILE    ?=    "<drivers/auth/mbedtls/psa_mbedtls_config.h>"
+else
+  MBEDTLS_CONFIG_FILE    ?=    "<drivers/auth/mbedtls/mbedtls_config-3.h>"
 endif
 
 $(eval $(call add_define,MBEDTLS_CONFIG_FILE))
@@ -42,11 +41,13 @@
 					cipher.c 			\
 					cipher_wrap.c 			\
 					constant_time.c			\
+					hash_info.c			\
 					memory_buffer_alloc.c		\
 					oid.c 				\
 					platform.c 			\
 					platform_util.c			\
 					bignum.c			\
+					bignum_core.c			\
 					gcm.c 				\
 					md.c				\
 					pk.c 				\
@@ -59,28 +60,17 @@
 					ecp_curves.c			\
 					ecp.c				\
 					rsa.c				\
+					rsa_alt_helpers.c		\
 					x509.c 				\
 					x509_crt.c 			\
 					)
 
-ifeq (${MBEDTLS_MAJOR}, 2)
-	LIBMBEDTLS_SRCS +=  $(addprefix ${MBEDTLS_DIR}/library/,	\
-						rsa_internal.c		\
-						)
-else ifeq (${MBEDTLS_MAJOR}, 3)
-	LIBMBEDTLS_SRCS +=  $(addprefix ${MBEDTLS_DIR}/library/,	\
-						bignum_core.c		\
-						rsa_alt_helpers.c	\
-						hash_info.c		\
-						)
-
-	# Currently on Mbedtls-3 there is outstanding bug due to usage
-	# of redundant declaration[1], So disable redundant-decls
-	# compilation flag to avoid compilation error when compiling with
-	# Mbedtls-3.
-	# [1]: https://github.com/Mbed-TLS/mbedtls/issues/6910
-	LIBMBEDTLS_CFLAGS += -Wno-error=redundant-decls
-endif
+# Currently on Mbedtls-3 there is outstanding bug due to usage
+# of redundant declaration[1], So disable redundant-decls
+# compilation flag to avoid compilation error when compiling with
+# Mbedtls-3.
+# [1]: https://github.com/Mbed-TLS/mbedtls/issues/6910
+LIBMBEDTLS_CFLAGS += -Wno-error=redundant-decls
 
 ifeq (${PSA_CRYPTO},1)
 LIBMBEDTLS_SRCS         += $(addprefix ${MBEDTLS_DIR}/library/,    	\
diff --git a/drivers/fwu/fwu.c b/drivers/fwu/fwu.c
index ff432be..b6f06e0 100644
--- a/drivers/fwu/fwu.c
+++ b/drivers/fwu/fwu.c
@@ -24,6 +24,17 @@
 CASSERT((offsetof(struct fwu_metadata, crc_32) == 0),
 	crc_32_must_be_first_member_of_structure);
 
+/*
+ * Ensure that the NR_OF_FW_BANKS selected by the platform is not
+ * zero and not greater than the maximum number of banks allowed
+ * by the specification.
+ */
+CASSERT((NR_OF_FW_BANKS > 0) && (NR_OF_FW_BANKS <= NR_OF_MAX_FW_BANKS),
+	assert_fwu_num_banks_invalid_value);
+
+#define FWU_METADATA_VERSION		2U
+#define FWU_FW_STORE_DESC_OFFSET	0x20U
+
 static struct fwu_metadata metadata;
 static bool is_metadata_initialized __unused;
 
@@ -51,16 +62,54 @@
 /*******************************************************************************
  * Check the sanity of FWU metadata.
  *
- * return -1 on error, otherwise 0
+ * return -EINVAL on error, otherwise 0
  ******************************************************************************/
 static int fwu_metadata_sanity_check(void)
 {
-	/* ToDo: add more conditions for sanity check */
-	if ((metadata.active_index >= NR_OF_FW_BANKS) ||
-	    (metadata.previous_active_index >= NR_OF_FW_BANKS)) {
-		return -1;
+	if (metadata.version != FWU_METADATA_VERSION) {
+		WARN("Incorrect FWU Metadata version of %u\n",
+		     metadata.version);
+		return -EINVAL;
+	}
+
+	if (metadata.active_index >= NR_OF_FW_BANKS) {
+		WARN("Active Index value(%u) greater than the configured value(%d)",
+		     metadata.active_index, NR_OF_FW_BANKS);
+		return -EINVAL;
+	}
+
+	if (metadata.previous_active_index >= NR_OF_FW_BANKS) {
+		WARN("Previous Active Index value(%u) greater than the configured value(%d)",
+		     metadata.previous_active_index, NR_OF_FW_BANKS);
+		return -EINVAL;
+	}
+
+#if PSA_FWU_METADATA_FW_STORE_DESC
+	if (metadata.fw_desc.num_banks != NR_OF_FW_BANKS) {
+		WARN("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
+		     metadata.fw_desc.num_banks, NR_OF_FW_BANKS);
+		return -EINVAL;
 	}
 
+	if (metadata.fw_desc.num_images != NR_OF_IMAGES_IN_FW_BANK) {
+		WARN("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
+		     metadata.fw_desc.num_images, NR_OF_IMAGES_IN_FW_BANK);
+		return -EINVAL;
+	}
+
+	if (metadata.desc_offset != FWU_FW_STORE_DESC_OFFSET) {
+		WARN("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
+		     metadata.desc_offset);
+		return -EINVAL;
+	}
+#else
+	if (metadata.desc_offset != 0U) {
+		WARN("Descriptor offset has non zero value of 0x%x\n",
+		     metadata.desc_offset);
+		return -EINVAL;
+	}
+#endif
+
 	return 0;
 }
 
@@ -133,28 +182,80 @@
 }
 
 /*******************************************************************************
- * The system runs in the trial run state if any of the images in the active
- * firmware bank has not been accepted yet.
+ * Check for an alternate bank for the platform to boot from. This function will
+ * mostly be called whenever the count of the number of times a platform boots
+ * in the Trial State exceeds a pre-set limit.
+ * The function first checks if the platform can boot from the previously active
+ * bank. If not, it tries to find another bank in the accepted state.
+ * And finally, if both the checks fail, as a last resort, it tries to find
+ * a valid bank.
  *
- * Returns true if the system is running in the trial state.
+ * Returns the index of a bank to boot, else returns invalid index
+ * INVALID_BOOT_IDX.
  ******************************************************************************/
-bool fwu_is_trial_run_state(void)
+uint32_t fwu_get_alternate_boot_bank(void)
 {
-	bool trial_run = false;
+	uint32_t i;
 
-	assert(is_metadata_initialized);
+	/* First check if the previously active bank can be used */
+	if (metadata.bank_state[metadata.previous_active_index] ==
+	    FWU_BANK_STATE_ACCEPTED) {
+		return metadata.previous_active_index;
+	}
 
-	for (unsigned int i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
-		struct fwu_image_entry *entry = &metadata.img_entry[i];
-		struct fwu_image_properties *img_props =
-			&entry->img_props[metadata.active_index];
-		if (img_props->accepted == 0) {
-			trial_run = true;
-			break;
+	/* Now check for any other bank in the accepted state */
+	for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+		if (i == metadata.active_index ||
+		    i == metadata.previous_active_index) {
+			continue;
+		}
+
+		if (metadata.bank_state[i] == FWU_BANK_STATE_ACCEPTED) {
+			return i;
 		}
 	}
 
-	return trial_run;
+	/*
+	 * No accepted bank found. Now try booting from a valid bank.
+	 * Give priority to the previous active bank.
+	 */
+	if (metadata.bank_state[metadata.previous_active_index] ==
+	    FWU_BANK_STATE_VALID) {
+		return metadata.previous_active_index;
+	}
+
+	for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+		if (i == metadata.active_index ||
+		    i == metadata.previous_active_index) {
+			continue;
+		}
+
+		if (metadata.bank_state[i] == FWU_BANK_STATE_VALID) {
+			return i;
+		}
+	}
+
+	return INVALID_BOOT_IDX;
+}
+
+/*******************************************************************************
+ * The platform can be in one of Valid, Invalid or Accepted states.
+ *
+ * Invalid - One or more images in the bank are corrupted, or partially
+ *           overwritten. The bank is not to be used for booting.
+ *
+ * Valid - All images of the bank are valid but at least one image has not
+ *         been accepted. This implies that the platform is in Trial State.
+ *
+ * Accepted - All images of the bank are valid and accepted.
+ *
+ * Returns the state of the current active bank
+ ******************************************************************************/
+uint32_t fwu_get_active_bank_state(void)
+{
+	assert(is_metadata_initialized);
+
+	return metadata.bank_state[metadata.active_index];
 }
 
 const struct fwu_metadata *fwu_get_metadata(void)
diff --git a/drivers/measured_boot/rss/dice_prot_env.c b/drivers/measured_boot/rss/dice_prot_env.c
new file mode 100644
index 0000000..81a21d1
--- /dev/null
+++ b/drivers/measured_boot/rss/dice_prot_env.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <psa/crypto_types.h>
+#include <psa/crypto_values.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/rss/dice_prot_env.h>
+#include <lib/cassert.h>
+#include <lib/psa/dice_protection_environment.h>
+
+#include <platform_def.h>
+
+#define DPE_ALG_SHA512 0
+#define DPE_ALG_SHA384 1
+#define DPE_ALG_SHA256 2
+
+#if DPE_ALG_ID == DPE_ALG_SHA512
+#define	CRYPTO_MD_ID		CRYPTO_MD_SHA512
+#define PSA_CRYPTO_MD_ID	PSA_ALG_SHA_512
+#elif DPE_ALG_ID == DPE_ALG_SHA384
+#define	CRYPTO_MD_ID		CRYPTO_MD_SHA384
+#define PSA_CRYPTO_MD_ID	PSA_ALG_SHA_384
+#elif DPE_ALG_ID == DPE_ALG_SHA256
+#define	CRYPTO_MD_ID		CRYPTO_MD_SHA256
+#define PSA_CRYPTO_MD_ID	PSA_ALG_SHA_256
+#else
+#  error Invalid DPE hash algorithm.
+#endif /* DPE_ALG_ID */
+
+/* Ensure that computed hash values fits into the DiceInputValues structure */
+CASSERT(DICE_HASH_SIZE >= DPE_DIGEST_SIZE,
+	assert_digest_size_bigger_than_allocated_buffer);
+
+static int initial_context_handle;
+
+static void map_metadata_to_dice_inputs(struct dpe_metadata *metadata,
+					DiceInputValues  *dice_inputs)
+{
+	/* Hash of the content certificate signing key (public part) */
+	memcpy(dice_inputs->authority_hash, metadata->signer_id,
+	       DPE_DIGEST_SIZE);
+
+	/* SW type string identifier */
+	assert(metadata->sw_type_size < DICE_CODE_DESCRIPTOR_MAX_SIZE);
+	dice_inputs->code_descriptor = metadata->sw_type;
+	dice_inputs->code_descriptor_size = metadata->sw_type_size;
+}
+
+void dpe_init(struct dpe_metadata *metadata)
+{
+	assert(metadata != NULL);
+
+	/* Init the non-const members of the metadata structure */
+	while (metadata->id != DPE_INVALID_ID) {
+		/* Terminating 0 character is not needed due to CBOR encoding */
+		metadata->sw_type_size =
+			strlen((const char *)&metadata->sw_type);
+		metadata++;
+	}
+
+	plat_dpe_get_context_handle(&initial_context_handle);
+}
+
+int dpe_measure_and_record(struct dpe_metadata *metadata,
+			   uintptr_t data_base, uint32_t data_size,
+			   uint32_t data_id)
+{
+	static int current_context_handle;
+	DiceInputValues dice_inputs = { 0 };
+	int new_parent_context_handle;
+	int new_context_handle;
+	dpe_error_t ret;
+	int rc;
+
+	assert(metadata != NULL);
+
+	/* Get the metadata associated with this image. */
+	while ((metadata->id != DPE_INVALID_ID) && (metadata->id != data_id)) {
+		metadata++;
+	}
+
+	/* If image is not present in metadata array then skip */
+	if (metadata->id == DPE_INVALID_ID) {
+		return 0;
+	}
+
+	/* Calculate hash */
+	rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+				  (void *)data_base, data_size,
+				   dice_inputs.code_hash);
+	if (rc != 0) {
+		return rc;
+	}
+
+	map_metadata_to_dice_inputs(metadata, &dice_inputs);
+
+	/* Only at the first call */
+	if (current_context_handle == 0) {
+		current_context_handle = initial_context_handle;
+	}
+
+	VERBOSE("Calling dpe_derive_context, image_id: %d\n", metadata->id);
+	ret = dpe_derive_context(current_context_handle,
+				 metadata->cert_id,
+				 metadata->retain_parent_context,
+				 metadata->allow_new_context_to_derive,
+				 metadata->create_certificate,
+				 &dice_inputs,
+				 0, /* target_locality */
+				 false, /* return_certificate */
+				 true, /* allow_new_context_to_export */
+				 false, /* export_cdi */
+				 &new_context_handle,
+				 &new_parent_context_handle,
+				 NULL, 0, NULL,  /* new_certificate_* */
+				 NULL, 0, NULL); /* exported_cdi_* */
+	if (ret == DPE_NO_ERROR) {
+		current_context_handle = new_parent_context_handle;
+		if (metadata->allow_new_context_to_derive == true) {
+			/* Share new_context_handle with child component:
+			 * e.g: BL2, BL33.
+			 */
+			VERBOSE("Share new_context_handle with child: 0x%x\n",
+				new_context_handle);
+			plat_dpe_share_context_handle(&new_context_handle);
+		}
+	} else {
+		ERROR("dpe_derive_context failed: %d\n", ret);
+	}
+
+	return (ret == DPE_NO_ERROR) ? 0 : -1;
+}
+
+int dpe_set_signer_id(struct dpe_metadata *metadata,
+		      const void *pk_oid,
+		      const void *pk_ptr,
+		      size_t pk_len)
+{
+	unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+	int rc;
+	bool hash_calc_done = false;
+
+	assert(metadata != NULL);
+
+	/*
+	 * Do an exhaustive search over the platform metadata to find
+	 * all images whose key OID matches the one passed in argument.
+	 *
+	 * Note that it is not an error if do not get any matches.
+	 * The platform may decide not to measure all of the images
+	 * in the system.
+	 */
+	while (metadata->id != DPE_INVALID_ID) {
+		/* Get the metadata associated with this key-oid */
+		if (metadata->pk_oid == pk_oid) {
+			if (hash_calc_done == false) {
+				/* Calculate public key hash */
+				rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+							  (void *)pk_ptr,
+							  pk_len, hash_data);
+				if (rc != 0) {
+					return rc;
+				}
+
+				hash_calc_done = true;
+			}
+
+			/*
+			 * Fill the signer-ID field with the newly/already
+			 * computed hash of the public key and update its
+			 * signer ID size field with compile-time decided
+			 * digest size.
+			 */
+			(void)memcpy(metadata->signer_id,
+				     hash_data,
+				     DPE_DIGEST_SIZE);
+			metadata->signer_id_size = DPE_DIGEST_SIZE;
+		}
+
+		metadata++;
+	}
+
+	return 0;
+}
diff --git a/drivers/measured_boot/rss/dice_prot_env.mk b/drivers/measured_boot/rss/dice_prot_env.mk
new file mode 100644
index 0000000..c5a35e0
--- /dev/null
+++ b/drivers/measured_boot/rss/dice_prot_env.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Hash algorithm for DICE Protection Environment
+# SHA-256 (or stronger) is required.
+DPE_HASH_ALG	:=	sha256
+
+ifeq (${DPE_HASH_ALG}, sha512)
+    DPE_ALG_ID		:=	DPE_ALG_SHA512
+    DPE_DIGEST_SIZE	:=	64U
+else ifeq (${DPE_HASH_ALG}, sha384)
+    DPE_ALG_ID		:=	DPE_ALG_SHA384
+    DPE_DIGEST_SIZE	:=	48U
+else
+    DPE_ALG_ID		:=	DPE_ALG_SHA256
+    DPE_DIGEST_SIZE	:=	32U
+endif #DPE_HASH_ALG
+
+# Set definitions for DICE Protection Environment
+$(eval $(call add_defines,\
+    $(sort \
+        DPE_ALG_ID \
+        DPE_DIGEST_SIZE \
+)))
+
+DPE_SOURCES	+=	drivers/measured_boot/rss/dice_prot_env.c
diff --git a/drivers/measured_boot/rss/qcbor.mk b/drivers/measured_boot/rss/qcbor.mk
new file mode 100644
index 0000000..2146e5d
--- /dev/null
+++ b/drivers/measured_boot/rss/qcbor.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TF-A was tested with v1.2 version of QCBOR
+
+ifeq (${QCBOR_DIR},)
+        $(error Error: QCBOR_DIR not set)
+endif
+
+QCBOR_SOURCES	+=	${QCBOR_DIR}/src/qcbor_encode.c \
+			${QCBOR_DIR}/src/qcbor_decode.c \
+			${QCBOR_DIR}/src/UsefulBuf.c
+
+QCBOR_INCLUDES	+=	${QCBOR_DIR}/inc
+
+# Floating point numbers are not used, so disable the support.
+# This reduces the library size as well.
+$(eval $(call add_define,QCBOR_DISABLE_FLOAT_HW_USE))
+$(eval $(call add_define,USEFULBUF_DISABLE_ALL_FLOAT))
+$(eval $(call add_define,QCBOR_DISABLE_PREFERRED_FLOAT))
diff --git a/drivers/measured_boot/rss/rss_measured_boot.c b/drivers/measured_boot/rss/rss_measured_boot.c
index 258aa8d..c44ec73 100644
--- a/drivers/measured_boot/rss/rss_measured_boot.c
+++ b/drivers/measured_boot/rss/rss_measured_boot.c
@@ -128,7 +128,7 @@
 	while (metadata_ptr->id != RSS_MBOOT_INVALID_ID) {
 		/* Get the metadata associated with this key-oid */
 		if (metadata_ptr->pk_oid == pk_oid) {
-			if (!hash_calc_done) {
+			if (hash_calc_done == false) {
 				/* Calculate public key hash */
 				rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
 							  (void *)pk_ptr,
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index 555fe7f..888a824 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -190,11 +190,11 @@
 static int load_mbr_entries(uintptr_t image_handle)
 {
 	mbr_entry_t mbr_entry;
-	int i;
+	unsigned int i;
 
 	list.entry_count = MBR_PRIMARY_ENTRY_NUMBER;
 
-	for (i = 0; i < list.entry_count; i++) {
+	for (i = 0U; i < list.entry_count; i++) {
 		load_mbr_entry(image_handle, &mbr_entry, i);
 		list.list[i].start = mbr_entry.first_lba * 512;
 		list.list[i].length = mbr_entry.sector_nums * 512;
@@ -244,7 +244,7 @@
 		return result;
 	}
 
-	for (i = 0; i < (unsigned int)list.entry_count; i++) {
+	for (i = 0U; i < list.entry_count; i++) {
 		result = load_gpt_entry(image_handle, &entry);
 		if (result != 0) {
 			VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n",
@@ -441,9 +441,9 @@
  */
 const partition_entry_t *get_partition_entry(const char *name)
 {
-	int i;
+	unsigned int i;
 
-	for (i = 0; i < list.entry_count; i++) {
+	for (i = 0U; i < list.entry_count; i++) {
 		if (strcmp(name, list.list[i].name) == 0) {
 			return &list.list[i];
 		}
@@ -452,14 +452,15 @@
 }
 
 /*
- * Try retrieving a partition table entry based on the GUID.
+ * Try retrieving a partition table entry based on the partition type GUID.
  */
-const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid)
+const partition_entry_t *get_partition_entry_by_type(
+	const struct efi_guid *type_guid)
 {
-	int i;
+	unsigned int i;
 
-	for (i = 0; i < list.entry_count; i++) {
-		if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) {
+	for (i = 0U; i < list.entry_count; i++) {
+		if (guidcmp(type_guid, &list.list[i].type_guid) == 0) {
 			return &list.list[i];
 		}
 	}
@@ -468,14 +469,15 @@
 }
 
 /*
- * Try retrieving a partition table entry based on the UUID.
+ * Try retrieving a partition table entry based on the unique partition GUID.
  */
-const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid)
+const partition_entry_t *get_partition_entry_by_guid(
+	const struct efi_guid *part_guid)
 {
-	int i;
+	unsigned int i;
 
-	for (i = 0; i < list.entry_count; i++) {
-		if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) {
+	for (i = 0U; i < list.entry_count; i++) {
+		if (guidcmp(part_guid, &list.list[i].part_guid) == 0) {
 			return &list.list[i];
 		}
 	}
diff --git a/drivers/scmi-msg/common.h b/drivers/scmi-msg/common.h
index 62f3087..6b186d0 100644
--- a/drivers/scmi-msg/common.h
+++ b/drivers/scmi-msg/common.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause */
 /*
- * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2020, Linaro Limited
  */
 #ifndef SCMI_MSG_COMMON_H
@@ -15,6 +15,7 @@
 #include "clock.h"
 #include "power_domain.h"
 #include "reset_domain.h"
+#include "sensor.h"
 
 #define SCMI_VERSION			0x20000U
 #define SCMI_IMPL_VERSION		0U
@@ -119,6 +120,13 @@
 scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg);
 
 /*
+ * scmi_msg_get_sensor_handler - Return a handler for a sensor message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg);
+
+/*
  * Process Read, process and write response for input SCMI message
  *
  * @msg: SCMI message context
diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c
index 399115c..5ac68e1 100644
--- a/drivers/scmi-msg/entry.c
+++ b/drivers/scmi-msg/entry.c
@@ -15,6 +15,7 @@
 #pragma weak scmi_msg_get_rstd_handler
 #pragma weak scmi_msg_get_pd_handler
 #pragma weak scmi_msg_get_voltage_handler
+#pragma weak scmi_msg_get_sensor_handler
 
 scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg __unused)
 {
@@ -36,6 +37,11 @@
 	return NULL;
 }
 
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg __unused)
+{
+	return NULL;
+}
+
 void scmi_status_response(struct scmi_msg *msg, int32_t status)
 {
 	assert(msg->out && msg->out_size >= sizeof(int32_t));
@@ -75,6 +81,9 @@
 	case SCMI_PROTOCOL_ID_POWER_DOMAIN:
 		handler = scmi_msg_get_pd_handler(msg);
 		break;
+	case SCMI_PROTOCOL_ID_SENSOR:
+		handler = scmi_msg_get_sensor_handler(msg);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/scmi-msg/sensor.c b/drivers/scmi-msg/sensor.c
new file mode 100644
index 0000000..a47018d
--- /dev/null
+++ b/drivers/scmi-msg/sensor.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2021-2024 NXP
+ */
+
+#include <cdefs.h>
+#include <string.h>
+
+#include "common.h"
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+static bool message_id_is_supported(size_t message_id);
+
+uint16_t plat_scmi_sensor_count(unsigned int agent_id __unused)
+{
+	if (sensor_ops.sensor_count != NULL) {
+		return sensor_ops.sensor_count(agent_id);
+	}
+
+	return 0U;
+}
+
+uint8_t plat_scmi_sensor_max_requests(unsigned int agent_id __unused)
+{
+	if (sensor_ops.sensor_max_request != NULL) {
+		return sensor_ops.sensor_max_request(agent_id);
+	}
+
+	return 0U;
+}
+
+uint32_t plat_scmi_sensor_reg(unsigned int agent_id __unused,
+			      unsigned int *addr)
+{
+	if (sensor_ops.get_sensor_req != NULL) {
+		return sensor_ops.get_sensor_req(agent_id, addr);
+	}
+
+	return 0U;
+}
+
+int32_t plat_scmi_sensor_reading_get(uint32_t agent_id __unused,
+				     uint16_t sensor_id __unused,
+				     uint32_t *val __unused)
+{
+	if (sensor_ops.sensor_reading_get != NULL) {
+		return sensor_ops.sensor_reading_get(agent_id, sensor_id, val);
+	}
+
+	return 0;
+}
+
+uint32_t plat_scmi_sensor_description_get(uint32_t agent_id __unused,
+					  uint16_t desc_index __unused,
+					  struct scmi_sensor_desc *desc __unused)
+{
+	if (sensor_ops.sensor_description_get != NULL) {
+		return sensor_ops.sensor_description_get(agent_id, desc_index, desc);
+	}
+
+	return 0U;
+}
+
+uint32_t plat_scmi_sensor_update_interval(uint32_t agent_id __unused,
+					  uint16_t sensor_id __unused)
+{
+	if (sensor_ops.sensor_update_interval != NULL) {
+		return sensor_ops.sensor_update_interval(agent_id, sensor_id);
+	}
+
+	return 0U;
+}
+
+uint32_t plat_scmi_sensor_state(uint32_t agent_id __unused,
+				uint16_t sensor_id __unused)
+{
+	if (sensor_ops.sensor_state != NULL) {
+		return sensor_ops.sensor_state(agent_id, sensor_id);
+	}
+
+	return 0U;
+}
+
+uint32_t plat_scmi_sensor_timestamped(uint32_t agent_id __unused,
+				      uint16_t sensor_id __unused)
+{
+	if (sensor_ops.sensor_timestamped != NULL) {
+		return sensor_ops.sensor_timestamped(agent_id, sensor_id);
+	}
+
+	return 0U;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+	struct scmi_protocol_version_p2a return_values = {
+		.status = SCMI_SUCCESS,
+		.version = SCMI_PROTOCOL_VERSION_SENSOR,
+	};
+
+	if (msg->in_size != 0U) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+	unsigned int addr[2];
+	unsigned int len;
+
+	struct scmi_protocol_attributes_p2a_sensor return_values = {
+		.status = SCMI_SUCCESS,
+	};
+
+	if (msg->in_size != 0U) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	return_values.num_sensors = plat_scmi_sensor_count(msg->agent_id);
+	return_values.max_reqs = plat_scmi_sensor_max_requests(msg->agent_id);
+	len = plat_scmi_sensor_reg(msg->agent_id, addr);
+	if (len != 0U) {
+		return_values.sensor_reg_low = addr[0];
+		return_values.sensor_reg_high = addr[1];
+		return_values.sensor_reg_len = len;
+	}
+
+	scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+	struct scmi_protocol_message_attributes_p2a return_values = {
+		.status = SCMI_SUCCESS,
+		/* For this protocol, attributes shall be zero */
+		.attributes = 0U,
+	};
+
+	if (msg->in_size != sizeof(*in_args)) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	if (!message_id_is_supported(in_args->message_id)) {
+		scmi_status_response(msg, SCMI_NOT_FOUND);
+		return;
+	}
+
+	scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_description_get(struct scmi_msg *msg)
+{
+	const struct scmi_sensor_description_get_a2p *in_args = (void *)msg->in;
+	struct scmi_sensor_description_get_p2a return_values = {
+		.status = SCMI_SUCCESS,
+	};
+	struct scmi_sensor_desc desc;
+	unsigned int desc_index = 0U;
+	unsigned int num_sensor_flags;
+
+	if (msg->in_size != sizeof(*in_args)) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	desc_index = SPECULATION_SAFE_VALUE(in_args->desc_index);
+
+	num_sensor_flags = plat_scmi_sensor_description_get(msg->agent_id, desc_index,
+							    &desc);
+	return_values.num_sensor_flags = num_sensor_flags;
+
+	memcpy(msg->out, &return_values, sizeof(return_values));
+	memcpy(msg->out + sizeof(return_values), &desc, sizeof(desc));
+	msg->out_size_out = sizeof(return_values) + sizeof(struct scmi_sensor_desc);
+}
+
+static void scmi_sensor_config_get(struct scmi_msg *msg)
+{
+	const struct scmi_sensor_config_get_a2p *in_args = (void *)msg->in;
+	struct scmi_sensor_config_get_p2a return_values = {
+		.status = SCMI_SUCCESS,
+	};
+	unsigned int sensor_id = 0U;
+	uint32_t update_interval, state, timestamped;
+
+	if (msg->in_size != sizeof(*in_args)) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
+
+	if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
+		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+		return;
+	}
+
+	update_interval = plat_scmi_sensor_update_interval(msg->agent_id, sensor_id);
+	state = plat_scmi_sensor_state(msg->agent_id, sensor_id);
+	timestamped = plat_scmi_sensor_timestamped(msg->agent_id, sensor_id);
+	return_values.sensor_config = (update_interval << 11) | (timestamped << 1) | state;
+
+	scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_reading_get(struct scmi_msg *msg)
+{
+	const struct scmi_sensor_reading_get_a2p *in_args = (void *)msg->in;
+	struct scmi_sensor_reading_get_p2a return_values = {
+		.status = SCMI_SUCCESS,
+	};
+	unsigned int sensor_id = 0U;
+	int32_t ret;
+
+	if (msg->in_size != sizeof(*in_args)) {
+		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+		return;
+	}
+
+	sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
+
+	if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
+		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+		return;
+	}
+
+	ret = plat_scmi_sensor_reading_get(msg->agent_id, sensor_id,
+					  (uint32_t *)&return_values.val);
+	if (ret) {
+		scmi_status_response(msg, SCMI_HARDWARE_ERROR);
+		return;
+	}
+
+	scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_list_update_intervals(struct scmi_msg *msg)
+{
+	/* TODO */
+	scmi_status_response(msg, SCMI_NOT_SUPPORTED);
+}
+
+static const scmi_msg_handler_t scmi_sensor_handler_table[SCMI_SENSOR_MAX] = {
+	[SCMI_PROTOCOL_VERSION] = report_version,
+	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+	[SCMI_SENSOR_DESCRIPTION_GET] = scmi_sensor_description_get,
+	[SCMI_SENSOR_CONFIG_GET] = scmi_sensor_config_get,
+	[SCMI_SENSOR_LIST_UPDATE_INTERVALS] = scmi_sensor_list_update_intervals,
+	[SCMI_SENSOR_READING_GET] = scmi_sensor_reading_get,
+};
+
+static bool message_id_is_supported(size_t message_id)
+{
+	return scmi_sensor_handler_table[message_id] != NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg)
+{
+	unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+	if (!message_id_is_supported(message_id)) {
+		VERBOSE("pd handle not found %u\n", msg->message_id);
+		return NULL;
+	}
+
+	return scmi_sensor_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/sensor.h b/drivers/scmi-msg/sensor.h
new file mode 100644
index 0000000..28cbb1e
--- /dev/null
+++ b/drivers/scmi-msg/sensor.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2023-2024 NXP
+ */
+
+#ifndef SCMI_MSG_SENSOR_H
+#define SCMI_MSG_SENSOR_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_SENSOR	0x20000U
+
+/*
+ * Identifiers of the SCMI SENSOR Protocol commands
+ */
+enum scmi_sensor_command_id {
+	SCMI_SENSOR_DESCRIPTION_GET = 0x003,
+	SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x004,
+	SCMI_SENSOR_TRIP_POINT_CONFIG = 0x005,
+	SCMI_SENSOR_READING_GET = 0x006,
+	SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x007,
+	SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x008,
+	SCMI_SENSOR_CONFIG_GET = 0x009,
+	SCMI_SENSOR_CONFIG_SET = 0x00A,
+	SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0x00B,
+	SCMI_SENSOR_MAX = 0x00C,
+};
+
+/* Protocol attributes */
+struct scmi_protocol_attributes_p2a_sensor {
+	int32_t status;
+	int16_t num_sensors;
+	uint8_t max_reqs;
+	uint8_t res;
+	uint32_t sensor_reg_low;
+	uint32_t sensor_reg_high;
+	uint32_t sensor_reg_len;
+};
+
+#define SCMI_SENSOR_NAME_LENGTH_MAX	16U
+
+struct scmi_sensor_desc {
+	uint32_t id;
+	uint32_t attr_low;
+	uint32_t attr_high;
+	uint8_t name[SCMI_SENSOR_NAME_LENGTH_MAX];
+	uint32_t power;
+	uint32_t resolution;
+	int32_t min_range_low;
+	int32_t min_range_high;
+	int32_t max_range_low;
+	int32_t max_range_high;
+};
+
+struct scmi_sensor_description_get_a2p {
+	uint32_t desc_index;
+};
+
+struct scmi_sensor_description_get_p2a {
+	int32_t status;
+	uint32_t num_sensor_flags;
+};
+
+struct scmi_sensor_config_get_a2p {
+	uint32_t sensor_id;
+};
+
+struct scmi_sensor_config_get_p2a {
+	int32_t status;
+	uint32_t sensor_config;
+};
+
+/*
+ * Sensor Reading Get
+ */
+struct scmi_sensor_reading_get_a2p {
+	uint32_t sensor_id;
+	uint32_t flags;
+};
+
+struct scmi_sensor_val {
+	uint32_t value_low;
+	uint32_t value_high;
+	uint32_t timestap_low;
+	uint32_t timestap_high;
+};
+
+struct scmi_sensor_reading_get_p2a {
+	int32_t status;
+	struct scmi_sensor_val val;
+};
+
+typedef struct {
+	uint16_t (*sensor_count)(unsigned int agent_id);
+	uint8_t (*sensor_max_request)(unsigned int agent_id);
+	uint32_t (*get_sensor_req)(unsigned int agent_id, unsigned int *addr);
+	int32_t (*sensor_reading_get)(uint32_t agent_id, uint16_t sensor_id,
+				      uint32_t *val);
+	uint32_t (*sensor_description_get)(unsigned int agent_id, uint16_t sensor_id,
+					  struct scmi_sensor_desc *desc);
+	uint32_t (*sensor_update_interval)(uint32_t agent_id, uint16_t sensor_id);
+	uint32_t (*sensor_state)(uint32_t agent_id, uint16_t sensor_id);
+	uint16_t (*sensor_timestamped)(uint32_t agent_id, uint16_t sensor_id);
+} plat_scmi_sensor_ops_t;
+
+#define REGISTER_SCMI_SENSOR_OPS(_sensor_count, _sensor_max_request, \
+				 _get_sensor_req, _sensor_reading_get, \
+				 _sensor_description_get, _sensor_update_interval, \
+				 _sensor_state, _sensor_timestamped) \
+	const plat_scmi_sensor_ops_t sensor_ops = { \
+		.sensor_count = _sensor_count, \
+		.sensor_max_request = _sensor_max_request, \
+		.get_sensor_req = _get_sensor_req, \
+		.sensor_reading_get = _sensor_reading_get, \
+		.sensor_description_get = _sensor_description_get, \
+		.sensor_update_interval = _sensor_update_interval, \
+		.sensor_state = _sensor_state, \
+		.sensor_timestamped = _sensor_timestamped, \
+	}
+
+extern const plat_scmi_sensor_ops_t sensor_ops;
+
+#endif /* SCMI_MSG_SENSOR_H */
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/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
index be722f3..66988d7 100644
--- a/drivers/st/mmc/stm32_sdmmc2.c
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2023, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2018-2024, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -129,7 +129,11 @@
 #define DT_SDMMC2_COMPAT		"st,stm32-sdmmc2"
 #endif
 
+#if STM32MP13 || STM32MP15
 #define SDMMC_FIFO_SIZE			64U
+#else
+#define SDMMC_FIFO_SIZE			1024U
+#endif
 
 #define STM32MP_MMC_INIT_FREQ			U(400000)	/*400 KHz*/
 #define STM32MP_SD_NORMAL_SPEED_MAX_FREQ	U(25000000)	/*25 MHz*/
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 8a4c071..ee86b7e 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020-2022, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -1401,6 +1401,8 @@
 #define RGSR_EL1		S3_0_C1_C0_5
 #define GCR_EL1			S3_0_C1_C0_6
 
+#define GCR_EL1_RRND_BIT	(UL(1) << 16)
+
 /*******************************************************************************
  * Armv8.5 - Random Number Generator Registers
  ******************************************************************************/
diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h
index 1d58ef9..ed5374e 100644
--- a/include/bl31/bl31.h
+++ b/include/bl31/bl31.h
@@ -22,6 +22,5 @@
 void bl31_register_rmm_init(int32_t (*func)(void));
 void bl31_warm_entrypoint(void);
 void bl31_main(void);
-void bl31_lib_init(void);
 
 #endif /* BL31_H */
diff --git a/include/bl31/sync_handle.h b/include/bl31/sync_handle.h
index ae61f31..394252b 100644
--- a/include/bl31/sync_handle.h
+++ b/include/bl31/sync_handle.h
@@ -58,6 +58,8 @@
 /* Handler for injecting UNDEF exception to lower EL */
 void inject_undef64(cpu_context_t *ctx);
 
+u_register_t create_spsr(u_register_t old_spsr, unsigned int target_el);
+
 /* Prototypes for system register emulation handlers provided by platforms. */
 int plat_handle_impdef_trap(uint64_t esr_el3, cpu_context_t *ctx);
 int plat_handle_rng_trap(uint64_t esr_el3, cpu_context_t *ctx);
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index cf6a746..bfda31b 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -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
  */
@@ -588,6 +588,7 @@
 void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
 void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
 unsigned int gicv3_set_pmr(unsigned int mask);
+unsigned int gicv3_deactivate_priority(unsigned int mask);
 
 void gicv3_get_component_prodid_rev(const uintptr_t gicd_base,
 				    unsigned int *gic_prod_id,
diff --git a/include/drivers/auth/mbedtls/mbedtls_config-2.h b/include/drivers/auth/mbedtls/mbedtls_config-2.h
deleted file mode 100644
index 01e261a..0000000
--- a/include/drivers/auth/mbedtls/mbedtls_config-2.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2015-2022, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#ifndef MBEDTLS_CONFIG_H
-#define MBEDTLS_CONFIG_H
-
-/*
- * Key algorithms currently supported on mbed TLS libraries
- */
-#define TF_MBEDTLS_RSA			1
-#define TF_MBEDTLS_ECDSA		2
-#define TF_MBEDTLS_RSA_AND_ECDSA	3
-
-#define TF_MBEDTLS_USE_RSA (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA \
-		|| TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
-#define TF_MBEDTLS_USE_ECDSA (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA \
-		|| TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
-
-/*
- * Hash algorithms currently supported on mbed TLS libraries
- */
-#define TF_MBEDTLS_SHA256		1
-#define TF_MBEDTLS_SHA384		2
-#define TF_MBEDTLS_SHA512		3
-
-/*
- * Configuration file to build mbed TLS with the required features for
- * Trusted Boot
- */
-
-#define MBEDTLS_PLATFORM_MEMORY
-#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
-/* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */
-#define MBEDTLS_PLATFORM_SNPRINTF_ALT
-
-#define MBEDTLS_PKCS1_V21
-
-#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
-#define MBEDTLS_X509_CHECK_KEY_USAGE
-#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
-
-#define MBEDTLS_ASN1_PARSE_C
-#define MBEDTLS_ASN1_WRITE_C
-
-#define MBEDTLS_BASE64_C
-#define MBEDTLS_BIGNUM_C
-
-#define MBEDTLS_ERROR_C
-#define MBEDTLS_MD_C
-
-#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
-#define MBEDTLS_OID_C
-
-#define MBEDTLS_PK_C
-#define MBEDTLS_PK_PARSE_C
-#define MBEDTLS_PK_WRITE_C
-
-#define MBEDTLS_PLATFORM_C
-
-#if TF_MBEDTLS_USE_ECDSA
-#define MBEDTLS_ECDSA_C
-#define MBEDTLS_ECP_C
-#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
-#define MBEDTLS_ECP_NO_INTERNAL_RNG
-#endif
-#if TF_MBEDTLS_USE_RSA
-#define MBEDTLS_RSA_C
-#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
-#endif
-
-#define MBEDTLS_SHA256_C
-
-/*
- * If either Trusted Boot or Measured Boot require a stronger algorithm than
- * SHA-256, pull in SHA-512 support.
- */
-#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256) /* TBB hash algo */
-#define	MBEDTLS_SHA512_C
-#else
-   /* TBB uses SHA-256, what about measured boot? */
-#if defined(TF_MBEDTLS_MBOOT_USE_SHA512)
-#define MBEDTLS_SHA512_C
-#endif
-#endif
-
-#define MBEDTLS_VERSION_C
-
-#define MBEDTLS_X509_USE_C
-#define MBEDTLS_X509_CRT_PARSE_C
-
-#if TF_MBEDTLS_USE_AES_GCM
-#define MBEDTLS_AES_C
-#define MBEDTLS_CIPHER_C
-#define MBEDTLS_GCM_C
-#endif
-
-/* MPI / BIGNUM options */
-#define MBEDTLS_MPI_WINDOW_SIZE			2
-
-#if TF_MBEDTLS_USE_RSA
-#if TF_MBEDTLS_KEY_SIZE <= 2048
-#define MBEDTLS_MPI_MAX_SIZE			256
-#else
-#define MBEDTLS_MPI_MAX_SIZE			512
-#endif
-#else
-#define MBEDTLS_MPI_MAX_SIZE			256
-#endif
-
-/* Memory buffer allocator options */
-#define MBEDTLS_MEMORY_ALIGN_MULTIPLE		8
-
-/*
- * Prevent the use of 128-bit division which
- * creates dependency on external libraries.
- */
-#define MBEDTLS_NO_UDBL_DIVISION
-
-#ifndef __ASSEMBLER__
-/* System headers required to build mbed TLS with the current configuration */
-#include <stdlib.h>
-#include <mbedtls/check_config.h>
-#endif
-
-/*
- * Determine Mbed TLS heap size
- * 13312 = 13*1024
- * 11264 = 11*1024
- * 7168  = 7*1024
- */
-#if TF_MBEDTLS_USE_ECDSA
-#define TF_MBEDTLS_HEAP_SIZE		U(13312)
-#elif TF_MBEDTLS_USE_RSA
-#if TF_MBEDTLS_KEY_SIZE <= 2048
-#define TF_MBEDTLS_HEAP_SIZE		U(7168)
-#else
-#define TF_MBEDTLS_HEAP_SIZE		U(11264)
-#endif
-#endif
-
-/*
- * Warn if errors from certain functions are ignored.
- *
- * The warnings are always enabled (where supported) for critical functions
- * where ignoring the return value is almost always a bug. This macro extends
- * the warnings to more functions.
- */
-#define MBEDTLS_CHECK_RETURN_WARNING
-
-#endif /* MBEDTLS_CONFIG_H */
diff --git a/include/drivers/fwu/fwu.h b/include/drivers/fwu/fwu.h
index 9f18e22..18e8a31 100644
--- a/include/drivers/fwu/fwu.h
+++ b/include/drivers/fwu/fwu.h
@@ -9,8 +9,15 @@
 
 #include <stdbool.h>
 
+#define FWU_BANK_STATE_ACCEPTED		0xFCU
+#define FWU_BANK_STATE_VALID		0xFEU
+#define FWU_BANK_STATE_INVALID		0xFFU
+
+#define INVALID_BOOT_IDX		0xFFFFFFFFU
+
 void fwu_init(void);
-bool fwu_is_trial_run_state(void);
+uint32_t fwu_get_active_bank_state(void);
+uint32_t fwu_get_alternate_boot_bank(void);
 const struct fwu_metadata *fwu_get_metadata(void);
 
 #endif /* FWU_H */
diff --git a/include/drivers/fwu/fwu_metadata.h b/include/drivers/fwu/fwu_metadata.h
index 2e88de5..b441300 100644
--- a/include/drivers/fwu/fwu_metadata.h
+++ b/include/drivers/fwu/fwu_metadata.h
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * FWU metadata information as per the specification section 4.1:
- * https://developer.arm.com/documentation/den0118/a/
+ * https://developer.arm.com/documentation/den0118/latest/
  *
  */
 
@@ -14,11 +14,13 @@
 #include <stdint.h>
 #include <tools_share/uuid.h>
 
+#define NR_OF_MAX_FW_BANKS	4
+
 /* Properties of image in a bank */
-struct fwu_image_properties {
+struct fwu_image_bank_info {
 
-	/* UUID of the image in this bank */
-	uuid_t img_uuid;
+	/* GUID of the image in this bank */
+	struct efi_guid img_guid;
 
 	/* [0]: bit describing the image acceptance status –
 	 *      1 means the image is accepted
@@ -34,17 +36,40 @@
 /* Image entry information */
 struct fwu_image_entry {
 
-	/* UUID identifying the image type */
-	uuid_t img_type_uuid;
+	/* GUID identifying the image type */
+	struct efi_guid img_type_guid;
 
-	/* UUID of the storage volume where the image is located */
-	uuid_t location_uuid;
+	/* GUID of the storage volume where the image is located */
+	struct efi_guid location_guid;
 
-	/* Properties of images with img_type_uuid in the different FW banks */
-	struct fwu_image_properties img_props[NR_OF_FW_BANKS];
+	/* Properties of images with img_type_guid in the different FW banks */
+	struct fwu_image_bank_info img_bank_info[NR_OF_FW_BANKS];
 
 } __packed;
 
+/* Firmware Image descriptor */
+struct fwu_fw_store_descriptor {
+
+	/* Number of Banks */
+	uint8_t num_banks;
+
+	/* Reserved */
+	uint8_t reserved;
+
+	/* Number of images per bank */
+	uint16_t num_images;
+
+	/* Size of image_entry(all banks) in bytes */
+	uint16_t img_entry_size;
+
+	/* Size of image bank info structure in bytes */
+	uint16_t bank_info_entry_size;
+
+	/* Array of fwu_image_entry structs */
+	struct fwu_image_entry img_entry[NR_OF_IMAGES_IN_FW_BANK];
+
+} __packed;
+
 /*
  * FWU metadata filled by the updater and consumed by TF-A for
  * various purposes as below:
@@ -66,8 +91,25 @@
 	/* Previous bank index with which device booted successfully */
 	uint32_t previous_active_index;
 
+	/* Size of the entire metadata in bytes */
+	uint32_t metadata_size;
+
+	/* Offset of the image descriptor structure */
+	uint16_t desc_offset;
+
+	/* Reserved */
+	uint16_t reserved1;
+
+	/* Bank state */
+	uint8_t bank_state[NR_OF_MAX_FW_BANKS];
+
+	/* Reserved */
+	uint32_t reserved2;
+
+#if PSA_FWU_METADATA_FW_STORE_DESC
 	/* Image entry information */
-	struct fwu_image_entry img_entry[NR_OF_IMAGES_IN_FW_BANK];
+	struct fwu_fw_store_descriptor fw_desc;
+#endif
 
 } __packed;
 
diff --git a/include/drivers/measured_boot/event_log/event_log.h b/include/drivers/measured_boot/event_log/event_log.h
index 794d613..b44526a 100644
--- a/include/drivers/measured_boot/event_log/event_log.h
+++ b/include/drivers/measured_boot/event_log/event_log.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -43,51 +43,6 @@
 
 #define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
 
-/*
- * Each event log entry has some metadata (i.e. a string) that identifies
- * what is measured.These macros define these strings.
- * Note that these strings follow the standardization recommendations
- * defined in the Arm Server Base Security Guide (a.k.a. SBSG, Arm DEN 0086),
- * where applicable. They should not be changed in the code.
- * Where the SBSG does not make recommendations, we are free to choose any
- * naming convention.
- * The key thing is to choose meaningful strings so that when the TPM event
- * log is used in attestation, the different components can be identified.
- */
-#define EVLOG_BL2_STRING		"BL_2"
-#define EVLOG_BL31_STRING		"SECURE_RT_EL3"
-#if defined(SPD_opteed)
-#define EVLOG_BL32_STRING		"SECURE_RT_EL1_OPTEE"
-#elif defined(SPD_tspd)
-#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TSPD"
-#elif defined(SPD_tlkd)
-#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TLKD"
-#elif defined(SPD_trusty)
-#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TRUSTY"
-#else
-#define EVLOG_BL32_STRING		"SECURE_RT_EL1_UNKNOWN"
-#endif
-#define	EVLOG_BL32_EXTRA1_STRING	"SECURE_RT_EL1_OPTEE_EXTRA1"
-#define	EVLOG_BL32_EXTRA2_STRING	"SECURE_RT_EL1_OPTEE_EXTRA2"
-#define EVLOG_BL33_STRING		"BL_33"
-#define EVLOG_FW_CONFIG_STRING		"FW_CONFIG"
-#define EVLOG_HW_CONFIG_STRING		"HW_CONFIG"
-#define EVLOG_NT_FW_CONFIG_STRING	"NT_FW_CONFIG"
-#define EVLOG_SCP_BL2_STRING		"SYS_CTRL_2"
-#define EVLOG_SOC_FW_CONFIG_STRING	"SOC_FW_CONFIG"
-#define EVLOG_STM32_STRING		"STM32"
-#define EVLOG_TB_FW_CONFIG_STRING	"TB_FW_CONFIG"
-#define	EVLOG_TOS_FW_CONFIG_STRING	"TOS_FW_CONFIG"
-#define EVLOG_RMM_STRING 		"RMM"
-#define EVLOG_SP1_STRING		"SP1"
-#define EVLOG_SP2_STRING		"SP2"
-#define EVLOG_SP3_STRING		"SP3"
-#define EVLOG_SP4_STRING		"SP4"
-#define EVLOG_SP5_STRING		"SP5"
-#define EVLOG_SP6_STRING		"SP6"
-#define EVLOG_SP7_STRING		"SP7"
-#define EVLOG_SP8_STRING		"SP8"
-
 typedef struct {
 	unsigned int id;
 	const char *name;
diff --git a/include/drivers/measured_boot/metadata.h b/include/drivers/measured_boot/metadata.h
new file mode 100644
index 0000000..5e17a83
--- /dev/null
+++ b/include/drivers/measured_boot/metadata.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_H
+#define METADATA_H
+
+/* Minimum measurement value size that can be requested to store */
+#define MEASUREMENT_VALUE_MIN_SIZE	32U
+/* Maximum measurement value size that can be requested to store */
+#define MEASUREMENT_VALUE_MAX_SIZE	64U
+/* Minimum signer id size that can be requested to store */
+#define SIGNER_ID_MIN_SIZE		MEASUREMENT_VALUE_MIN_SIZE
+/* Maximum signer id size that can be requested to store */
+#define SIGNER_ID_MAX_SIZE		MEASUREMENT_VALUE_MAX_SIZE
+/* The theoretical maximum image version is: "255.255.65535\0" */
+#define VERSION_MAX_SIZE		14U
+/* Example sw_type: "BL_2, BL_33, etc." */
+#define SW_TYPE_MAX_SIZE		32U
+
+/*
+ * Images, measured during the boot process, have some associated metadata.
+ * One of these types of metadata is the image identifier strings. These macros
+ * define these strings. They are used across the different measured boot
+ * backends.
+ * Note that these strings follow the standardization recommendations
+ * defined in the Arm Server Base Security Guide (a.k.a. SBSG, Arm DEN 0086),
+ * where applicable. They should not be changed in the code.
+ * Where the SBSG does not make recommendations, we are free to choose any
+ * naming convention.
+ * The key thing is to choose meaningful strings so that when the measured boot
+ * metadata is used in attestation, the different components can be identified.
+ */
+#define MBOOT_BL2_IMAGE_STRING		"BL_2"
+#define MBOOT_BL31_IMAGE_STRING		"SECURE_RT_EL3"
+#if defined(SPD_opteed)
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_OPTEE"
+#elif defined(SPD_tspd)
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_TSPD"
+#elif defined(SPD_tlkd)
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_TLKD"
+#elif defined(SPD_trusty)
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_TRUSTY"
+#elif defined(SPD_spmd)
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_SPMD"
+#else
+#define MBOOT_BL32_IMAGE_STRING		"SECURE_RT_EL1_UNKNOWN"
+#endif /* SPD_opteed */
+#define MBOOT_BL32_EXTRA1_IMAGE_STRING	"SECURE_RT_EL1_OPTEE_EXTRA1"
+#define MBOOT_BL32_EXTRA2_IMAGE_STRING	"SECURE_RT_EL1_OPTEE_EXTRA2"
+#define MBOOT_BL33_IMAGE_STRING		"BL_33"
+#define MBOOT_FW_CONFIG_STRING		"FW_CONFIG"
+#define MBOOT_HW_CONFIG_STRING		"HW_CONFIG"
+#define MBOOT_NT_FW_CONFIG_STRING	"NT_FW_CONFIG"
+#define MBOOT_SCP_BL2_IMAGE_STRING	"SYS_CTRL_2"
+#define MBOOT_SOC_FW_CONFIG_STRING	"SOC_FW_CONFIG"
+#define MBOOT_STM32_STRING		"STM32"
+#define MBOOT_TB_FW_CONFIG_STRING	"TB_FW_CONFIG"
+#define MBOOT_TOS_FW_CONFIG_STRING	"TOS_FW_CONFIG"
+#define MBOOT_RMM_IMAGE_STRING		"RMM"
+#define MBOOT_SP1_STRING		"SP1"
+#define MBOOT_SP2_STRING		"SP2"
+#define MBOOT_SP3_STRING		"SP3"
+#define MBOOT_SP4_STRING		"SP4"
+#define MBOOT_SP5_STRING		"SP5"
+#define MBOOT_SP6_STRING		"SP6"
+#define MBOOT_SP7_STRING		"SP7"
+#define MBOOT_SP8_STRING		"SP8"
+
+#endif /* METADATA_H */
diff --git a/include/drivers/measured_boot/rss/dice_prot_env.h b/include/drivers/measured_boot/rss/dice_prot_env.h
new file mode 100644
index 0000000..6f754f5
--- /dev/null
+++ b/include/drivers/measured_boot/rss/dice_prot_env.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DICE_PROT_ENV_H
+#define DICE_PROT_ENV_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <drivers/measured_boot/metadata.h>
+
+#define DPE_INVALID_ID	UINT32_MAX
+
+struct dpe_metadata {
+	unsigned int id;
+	uint32_t cert_id;
+	uint8_t signer_id[SIGNER_ID_MAX_SIZE];
+	size_t  signer_id_size;
+	uint8_t version[VERSION_MAX_SIZE];
+	size_t  version_size;
+	uint8_t sw_type[SW_TYPE_MAX_SIZE];
+	size_t  sw_type_size;
+	bool allow_new_context_to_derive;
+	bool retain_parent_context;
+	bool create_certificate;
+	void *pk_oid;
+};
+
+void dpe_init(struct dpe_metadata *metadata);
+
+/* Returns 0 in case of success otherwise -1. */
+int dpe_measure_and_record(struct dpe_metadata *metadata,
+			   uintptr_t data_base, uint32_t data_size,
+			   uint32_t data_id);
+
+int dpe_set_signer_id(struct dpe_metadata *metadata,
+		      const void *pk_oid, const void *pk_ptr, size_t pk_len);
+
+/* Child components inherit their first valid context handle from their parents.
+ * How to share context handle is platform specific.
+ */
+void plat_dpe_share_context_handle(int *ctx_handle);
+void plat_dpe_get_context_handle(int *ctx_handle);
+
+#endif /* DICE_PROT_ENV_H */
diff --git a/include/drivers/measured_boot/rss/rss_measured_boot.h b/include/drivers/measured_boot/rss/rss_measured_boot.h
index 7ab517c..38f7d4e 100644
--- a/include/drivers/measured_boot/rss/rss_measured_boot.h
+++ b/include/drivers/measured_boot/rss/rss_measured_boot.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,27 +10,10 @@
 #include <stdint.h>
 
 #include <common/debug.h>
-#include <measured_boot.h>
+#include <drivers/measured_boot/metadata.h>
 
 #define RSS_MBOOT_INVALID_ID	UINT32_MAX
 
-/*
- * Each boot measurement has some metadata (i.e. a string) that identifies
- * what was measured and how. The sw_type field of the rss_mboot_metadata
- * structure represents the role of the software component that was measured.
- * The below macros define strings suitable for the sw_type.
- * The key thing is to choose meaningful strings so that when the attestation
- * token is verified, then the different components can be identified.
- */
-#define RSS_MBOOT_BL2_STRING		"BL_2"
-#define RSS_MBOOT_BL31_STRING		"SECURE_RT_EL3"
-#define RSS_MBOOT_HW_CONFIG_STRING	"HW_CONFIG"
-#define RSS_MBOOT_FW_CONFIG_STRING	"FW_CONFIG"
-#define RSS_MBOOT_TB_FW_CONFIG_STRING	"TB_FW_CONFIG"
-#define RSS_MBOOT_SOC_FW_CONFIG_STRING	"SOC_FW_CONFIG"
-#define RSS_MBOOT_RMM_STRING		"RMM"
-
-
 struct rss_mboot_metadata {
 	unsigned int id;
 	uint8_t slot;
diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h
index d567d4c..9e22d34 100644
--- a/include/drivers/partition/partition.h
+++ b/include/drivers/partition/partition.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -41,13 +41,15 @@
 
 typedef struct partition_entry_list {
 	partition_entry_t	list[PLAT_PARTITION_MAX_ENTRIES];
-	int			entry_count;
+	unsigned int		entry_count;
 } partition_entry_list_t;
 
 int load_partition_table(unsigned int image_id);
 const partition_entry_t *get_partition_entry(const char *name);
-const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_guid);
-const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid);
+const partition_entry_t *get_partition_entry_by_type(
+	const struct efi_guid *type_guid);
+const partition_entry_t *get_partition_entry_by_guid(
+	const struct efi_guid *part_guid);
 const partition_entry_list_t *get_partition_entry_list(void);
 void partition_init(unsigned int image_id);
 int gpt_partition_init(void);
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_a715.h b/include/lib/cpus/aarch64/cortex_a715.h
index 366894d..c7f50db 100644
--- a/include/lib/cpus/aarch64/cortex_a715.h
+++ b/include/lib/cpus/aarch64/cortex_a715.h
@@ -13,6 +13,11 @@
 #define CORTEX_A715_BHB_LOOP_COUNT				U(38)
 
 /*******************************************************************************
+ * CPU Auxiliary Control register 1 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A715_CPUACTLR_EL1				S3_0_C15_C1_0
+
+/*******************************************************************************
  * CPU Auxiliary Control register 2 specific definitions.
  ******************************************************************************/
 #define CORTEX_A715_CPUACTLR2_EL1				S3_0_C15_C1_1
@@ -22,6 +27,11 @@
  ******************************************************************************/
 #define CORTEX_A715_CPUECTLR_EL1				S3_0_C15_C1_4
 
+#define CORTEX_A715_CPUPSELR_EL3				S3_6_C15_C8_0
+#define CORTEX_A715_CPUPCR_EL3					S3_6_C15_C8_1
+#define CORTEX_A715_CPUPOR_EL3					S3_6_C15_C8_2
+#define CORTEX_A715_CPUPMR_EL3					S3_6_C15_C8_3
+
 /*******************************************************************************
  * CPU Power Control register specific definitions
  ******************************************************************************/
diff --git a/include/lib/cpus/aarch64/cortex_a720.h b/include/lib/cpus/aarch64/cortex_a720.h
index 47bbbc0..e542d4e 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,11 @@
 #define CORTEX_A720_BHB_LOOP_COUNT				U(132)
 
 /*******************************************************************************
+ * 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/dice/dice.h b/include/lib/dice/dice.h
new file mode 100644
index 0000000..cf54942
--- /dev/null
+++ b/include/lib/dice/dice.h
@@ -0,0 +1,166 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef DICE_DICE_H_
+#define DICE_DICE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DICE_CDI_SIZE 32
+#define DICE_HASH_SIZE 64
+#define DICE_HIDDEN_SIZE 64
+#define DICE_INLINE_CONFIG_SIZE 64
+#define DICE_PRIVATE_KEY_SEED_SIZE 32
+#define DICE_ID_SIZE 20
+
+typedef enum {
+  kDiceResultOk,
+  kDiceResultInvalidInput,
+  kDiceResultBufferTooSmall,
+  kDiceResultPlatformError,
+} DiceResult;
+
+typedef enum {
+  kDiceModeNotInitialized,
+  kDiceModeNormal,
+  kDiceModeDebug,
+  kDiceModeMaintenance,
+} DiceMode;
+
+typedef enum {
+  kDiceConfigTypeInline,
+  kDiceConfigTypeDescriptor,
+} DiceConfigType;
+
+// Contains a full set of input values describing the target program or system.
+// See the Open Profile for DICE specification for a detailed explanation of
+// these inputs.
+//
+// Fields:
+//    code_hash: A hash or similar representation of the target code.
+//    code_descriptor: An optional descriptor to be included in the certificate.
+//        This descriptor is opaque to the DICE flow and is included verbatim
+//        in the certificate with no validation. May be null.
+//    code_descriptor_size: The size in bytes of |code_descriptor|.
+//    config_type: Indicates how to interpret the remaining config-related
+//        fields. If the type is 'inline', then the 64 byte configuration input
+//        value must be provided in |config_value| and |config_descriptor| is
+//        ignored. If the type is 'descriptor', then |config_descriptor| is
+//        hashed to get the configuration input value and |config_value| is
+//        ignored.
+//    config_value: A 64-byte configuration input value when |config_type| is
+//        kDiceConfigTypeInline. Otherwise, this field is ignored.
+//    config_descriptor: A descriptor to be hashed for the configuration input
+//        value when |config_type| is kDiceConfigTypeDescriptor. Otherwise,
+//        this field is ignored and may be null.
+//    config_descriptor_size: The size in bytes of |config_descriptor|.
+//    authority_hash: A hash or similar representation of the authority used to
+//        verify the target code. If the code is not verified or the authority
+//        is implicit, for example hard coded as part of the code currently
+//        executing, then this value should be set to all zero bytes.
+//    authority_descriptor: An optional descriptor to be included in the
+//        certificate. This descriptor is opaque to the DICE flow and is
+//        included verbatim in the certificate with no validation. May be null.
+//    authority_descriptor_size: The size in bytes of |authority_descriptor|.
+//    mode: The current operating mode.
+//    hidden: Additional input which will not appear in certificates. If this is
+//        not used it should be set to all zero bytes.
+typedef struct DiceInputValues_ {
+  uint8_t code_hash[DICE_HASH_SIZE];
+  const uint8_t* code_descriptor;
+  size_t code_descriptor_size;
+  DiceConfigType config_type;
+  uint8_t config_value[DICE_INLINE_CONFIG_SIZE];
+  const uint8_t* config_descriptor;
+  size_t config_descriptor_size;
+  uint8_t authority_hash[DICE_HASH_SIZE];
+  const uint8_t* authority_descriptor;
+  size_t authority_descriptor_size;
+  DiceMode mode;
+  uint8_t hidden[DICE_HIDDEN_SIZE];
+} DiceInputValues;
+
+// Derives a |cdi_private_key_seed| from a |cdi_attest| value. On success
+// populates |cdi_private_key_seed| and returns kDiceResultOk.
+DiceResult DiceDeriveCdiPrivateKeySeed(
+    void* context, const uint8_t cdi_attest[DICE_CDI_SIZE],
+    uint8_t cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE]);
+
+// Derives an |id| from a |cdi_public_key| value. Because public keys can vary
+// in length depending on the algorithm, the |cdi_public_key_size| in bytes must
+// be provided. When interpreted as an integer, |id| is big-endian. On success
+// populates |id| and returns kDiceResultOk.
+DiceResult DiceDeriveCdiCertificateId(void* context,
+                                      const uint8_t* cdi_public_key,
+                                      size_t cdi_public_key_size,
+                                      uint8_t id[DICE_ID_SIZE]);
+
+// Executes the main DICE flow.
+//
+// Given a full set of input values and the current CDI values, computes the
+// next CDI values and a matching certificate. See the Open Profile for DICE
+// specification for a detailed explanation of this flow.
+// In certain cases, the caller may not need to generate the CDI certificate.
+// The caller should signal this by setting the certificate parameters to
+// null/zero values appropriately.
+//
+// Parameters:
+//    context: Context provided by the caller that is opaque to this library
+//        but is passed through to the integration-provided operations in
+//        dice/ops.h. The value is, therefore, integration-specific and may be
+//        null.
+//    current_cdi_attest, current_cdi_seal: The current CDI values as produced
+//        by a previous DICE flow. If this is the first DICE flow in a system,
+//        the Unique Device Secret (UDS) should be used for both of these
+//        arguments.
+//    input_values: A set of input values describing the target program or
+//        system.
+//    next_cdi_certificate_buffer_size: The size in bytes of the buffer pointed
+//        to by the |next_cdi_certificate| argument. This should be set to zero
+//        if next CDI certificate should not be computed.
+//    next_cdi_certificate: On success, will be populated with the generated
+//        certificate, up to |next_cdi_certificate_buffer_size| in size. If the
+//        certificate cannot fit in the buffer, |next_cdi_certificate_size| is
+//        populated with the required size and kDiceResultBufferTooSmall is
+//        returned. This should be set to NULL if next CDI certificate should
+//        not be computed.
+//    next_cdi_certificate_actual_size: On success, will be populated with the
+//        size, in bytes, of the certificate data written to
+//        |next_cdi_certificate|. If kDiceResultBufferTooSmall is returned, will
+//        be populated with the required buffer size. This should be set to NULL
+//        if next CDI certificate should not be computed.
+//    next_cdi_attest: On success, will be populated with the next CDI value for
+//        attestation.
+//    next_cdi_seal: On success, will be populated with the next CDI value for
+//        sealing.
+DiceResult DiceMainFlow(void* context,
+                        const uint8_t current_cdi_attest[DICE_CDI_SIZE],
+                        const uint8_t current_cdi_seal[DICE_CDI_SIZE],
+                        const DiceInputValues* input_values,
+                        size_t next_cdi_certificate_buffer_size,
+                        uint8_t* next_cdi_certificate,
+                        size_t* next_cdi_certificate_actual_size,
+                        uint8_t next_cdi_attest[DICE_CDI_SIZE],
+                        uint8_t next_cdi_seal[DICE_CDI_SIZE]);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // DICE_DICE_H_
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index d5bd890..44efee5 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -7,6 +7,7 @@
 #ifndef CONTEXT_H
 #define CONTEXT_H
 
+#include <lib/el3_runtime/context_el2.h>
 #include <lib/el3_runtime/cpu_data.h>
 #include <lib/utils_def.h>
 
@@ -157,102 +158,11 @@
  */
 #define CTX_EL1_SYSREGS_END		CTX_MTE_REGS_END
 
-/*
- * EL2 register set
- */
-
-#if CTX_INCLUDE_EL2_REGS
-/* For later discussion
- * ICH_AP0R<n>_EL2
- * ICH_AP1R<n>_EL2
- * AMEVCNTVOFF0<n>_EL2
- * AMEVCNTVOFF1<n>_EL2
- * ICH_LR<n>_EL2
- */
-#define CTX_EL2_SYSREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
-
-#define CTX_ACTLR_EL2		U(0x0)
-#define CTX_AFSR0_EL2		U(0x8)
-#define CTX_AFSR1_EL2		U(0x10)
-#define CTX_AMAIR_EL2		U(0x18)
-#define CTX_CNTHCTL_EL2		U(0x20)
-#define CTX_CNTVOFF_EL2		U(0x28)
-#define CTX_CPTR_EL2		U(0x30)
-#define CTX_DBGVCR32_EL2	U(0x38)
-#define CTX_ELR_EL2		U(0x40)
-#define CTX_ESR_EL2		U(0x48)
-#define CTX_FAR_EL2		U(0x50)
-#define CTX_HACR_EL2		U(0x58)
-#define CTX_HCR_EL2		U(0x60)
-#define CTX_HPFAR_EL2		U(0x68)
-#define CTX_HSTR_EL2		U(0x70)
-#define CTX_ICC_SRE_EL2		U(0x78)
-#define CTX_ICH_HCR_EL2		U(0x80)
-#define CTX_ICH_VMCR_EL2	U(0x88)
-#define CTX_MAIR_EL2		U(0x90)
-#define CTX_MDCR_EL2		U(0x98)
-#define CTX_PMSCR_EL2		U(0xa0)
-#define CTX_SCTLR_EL2		U(0xa8)
-#define CTX_SPSR_EL2		U(0xb0)
-#define CTX_SP_EL2		U(0xb8)
-#define CTX_TCR_EL2		U(0xc0)
-#define CTX_TPIDR_EL2		U(0xc8)
-#define CTX_TTBR0_EL2		U(0xd0)
-#define CTX_VBAR_EL2		U(0xd8)
-#define CTX_VMPIDR_EL2		U(0xe0)
-#define CTX_VPIDR_EL2		U(0xe8)
-#define CTX_VTCR_EL2		U(0xf0)
-#define CTX_VTTBR_EL2		U(0xf8)
-
-// Only if MTE registers in use
-#define CTX_TFSR_EL2		U(0x100)
-
-// Starting with Armv8.6
-#define CTX_HDFGRTR_EL2		U(0x108)
-#define CTX_HAFGRTR_EL2		U(0x110)
-#define CTX_HDFGWTR_EL2		U(0x118)
-#define CTX_HFGITR_EL2		U(0x120)
-#define CTX_HFGRTR_EL2		U(0x128)
-#define CTX_HFGWTR_EL2		U(0x130)
-#define CTX_CNTPOFF_EL2		U(0x138)
-
-// Starting with Armv8.4
-#define CTX_CONTEXTIDR_EL2	U(0x140)
-#define CTX_TTBR1_EL2		U(0x148)
-#define CTX_VDISR_EL2		U(0x150)
-#define CTX_VSESR_EL2		U(0x158)
-#define CTX_VNCR_EL2		U(0x160)
-#define CTX_TRFCR_EL2		U(0x168)
-
-// Starting with Armv8.5
-#define CTX_SCXTNUM_EL2		U(0x170)
-
-// Register for FEAT_HCX
-#define CTX_HCRX_EL2            U(0x178)
-
-// Starting with Armv8.9
-#define CTX_TCR2_EL2            U(0x180)
-#define CTX_POR_EL2             U(0x188)
-#define CTX_PIRE0_EL2           U(0x190)
-#define CTX_PIR_EL2             U(0x198)
-#define CTX_S2PIR_EL2		U(0x1a0)
-#define CTX_GCSCR_EL2           U(0x1a8)
-#define CTX_GCSPR_EL2           U(0x1b0)
-
-/* Align to the next 16 byte boundary */
-#define CTX_EL2_SYSREGS_END	U(0x1c0)
-
-#endif /* CTX_INCLUDE_EL2_REGS */
-
 /*******************************************************************************
  * Constants that allow assembler code to access members of and the 'fp_regs'
  * structure at their correct offsets.
  ******************************************************************************/
-#if CTX_INCLUDE_EL2_REGS
-# define CTX_FPREGS_OFFSET	(CTX_EL2_SYSREGS_OFFSET + CTX_EL2_SYSREGS_END)
-#else
 # define CTX_FPREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
-#endif
 #if CTX_INCLUDE_FPREGS
 #define CTX_FP_Q0		U(0x0)
 #define CTX_FP_Q1		U(0x10)
@@ -293,10 +203,10 @@
 #define CTX_FPREGS_END		U(0x220) /* Align to the next 16 byte boundary */
 #else
 #define CTX_FPREGS_END		U(0x210) /* Align to the next 16 byte boundary */
-#endif
+#endif /* CTX_INCLUDE_AARCH32_REGS */
 #else
 #define CTX_FPREGS_END		U(0)
-#endif
+#endif /* CTX_INCLUDE_FPREGS */
 
 /*******************************************************************************
  * Registers related to CVE-2018-3639
@@ -373,9 +283,7 @@
 /* Constants to determine the size of individual context structures */
 #define CTX_GPREG_ALL		(CTX_GPREGS_END >> DWORD_SHIFT)
 #define CTX_EL1_SYSREGS_ALL	(CTX_EL1_SYSREGS_END >> DWORD_SHIFT)
-#if CTX_INCLUDE_EL2_REGS
-# define CTX_EL2_SYSREGS_ALL	(CTX_EL2_SYSREGS_END >> DWORD_SHIFT)
-#endif
+
 #if CTX_INCLUDE_FPREGS
 # define CTX_FPREG_ALL		(CTX_FPREGS_END >> DWORD_SHIFT)
 #endif
@@ -403,15 +311,6 @@
  */
 DEFINE_REG_STRUCT(el1_sysregs, CTX_EL1_SYSREGS_ALL);
 
-
-/*
- * AArch64 EL2 system register context structure for preserving the
- * architectural state during world switches.
- */
-#if CTX_INCLUDE_EL2_REGS
-DEFINE_REG_STRUCT(el2_sysregs, CTX_EL2_SYSREGS_ALL);
-#endif
-
 /*
  * AArch64 floating point register context structure for preserving
  * the floating point state during switches from one security state to
@@ -460,19 +359,24 @@
 	gp_regs_t gpregs_ctx;
 	el3_state_t el3state_ctx;
 	el1_sysregs_t el1_sysregs_ctx;
-#if CTX_INCLUDE_EL2_REGS
-	el2_sysregs_t el2_sysregs_ctx;
-#endif
+
 #if CTX_INCLUDE_FPREGS
 	fp_regs_t fpregs_ctx;
 #endif
 	cve_2018_3639_t cve_2018_3639_ctx;
+
 #if CTX_INCLUDE_PAUTH_REGS
 	pauth_t pauth_ctx;
 #endif
+
 #if CTX_INCLUDE_MPAM_REGS
 	mpam_t	mpam_ctx;
 #endif
+
+#if CTX_INCLUDE_EL2_REGS
+	el2_sysregs_t el2_sysregs_ctx;
+#endif
+
 } cpu_context_t;
 
 /*
@@ -512,28 +416,30 @@
  */
 CASSERT(CTX_GPREGS_OFFSET == __builtin_offsetof(cpu_context_t, gpregs_ctx),
 	assert_core_context_gp_offset_mismatch);
+
+CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx),
+	assert_core_context_el3state_offset_mismatch);
+
 CASSERT(CTX_EL1_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el1_sysregs_ctx),
 	assert_core_context_el1_sys_offset_mismatch);
-#if CTX_INCLUDE_EL2_REGS
-CASSERT(CTX_EL2_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el2_sysregs_ctx),
-	assert_core_context_el2_sys_offset_mismatch);
-#endif
+
 #if CTX_INCLUDE_FPREGS
 CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx),
 	assert_core_context_fp_offset_mismatch);
-#endif
-CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx),
-	assert_core_context_el3state_offset_mismatch);
+#endif /* CTX_INCLUDE_FPREGS */
+
 CASSERT(CTX_CVE_2018_3639_OFFSET == __builtin_offsetof(cpu_context_t, cve_2018_3639_ctx),
 	assert_core_context_cve_2018_3639_offset_mismatch);
+
 #if CTX_INCLUDE_PAUTH_REGS
 CASSERT(CTX_PAUTH_REGS_OFFSET == __builtin_offsetof(cpu_context_t, pauth_ctx),
 	assert_core_context_pauth_offset_mismatch);
-#endif
+#endif /* CTX_INCLUDE_PAUTH_REGS */
+
 #if CTX_INCLUDE_MPAM_REGS
 CASSERT(CTX_MPAM_REGS_OFFSET == __builtin_offsetof(cpu_context_t, mpam_ctx),
 	assert_core_context_mpam_offset_mismatch);
-#endif
+#endif /* CTX_INCLUDE_MPAM_REGS */
 
 /*
  * Helper macro to set the general purpose registers that correspond to
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
new file mode 100644
index 0000000..4ad9634
--- /dev/null
+++ b/include/lib/el3_runtime/context_el2.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_EL2_H
+#define CONTEXT_EL2_H
+
+#ifndef __ASSEMBLER__
+/*******************************************************************************
+ * EL2 Registers:
+ * AArch64 EL2 system register context structure for preserving the
+ * architectural state during world switches.
+ ******************************************************************************/
+#if CTX_INCLUDE_EL2_REGS
+typedef struct el2_common_regs {
+	uint64_t actlr_el2;
+	uint64_t afsr0_el2;
+	uint64_t afsr1_el2;
+	uint64_t amair_el2;
+	uint64_t cnthctl_el2;
+	uint64_t cntvoff_el2;
+	uint64_t cptr_el2;
+	uint64_t dbgvcr32_el2;
+	uint64_t elr_el2;
+	uint64_t esr_el2;
+	uint64_t far_el2;
+	uint64_t hacr_el2;
+	uint64_t hcr_el2;
+	uint64_t hpfar_el2;
+	uint64_t hstr_el2;
+	uint64_t icc_sre_el2;
+	uint64_t ich_hcr_el2;
+	uint64_t ich_vmcr_el2;
+	uint64_t mair_el2;
+	uint64_t mdcr_el2;
+	uint64_t pmscr_el2;
+	uint64_t sctlr_el2;
+	uint64_t spsr_el2;
+	uint64_t sp_el2;
+	uint64_t tcr_el2;
+	uint64_t tpidr_el2;
+	uint64_t ttbr0_el2;
+	uint64_t vbar_el2;
+	uint64_t vmpidr_el2;
+	uint64_t vpidr_el2;
+	uint64_t vtcr_el2;
+	uint64_t vttbr_el2;
+} el2_common_regs_t;
+
+typedef struct el2_mte_regs {
+	uint64_t tfsr_el2;
+} el2_mte_regs_t;
+
+typedef struct el2_fgt_regs {
+	uint64_t hdfgrtr_el2;
+	uint64_t hafgrtr_el2;
+	uint64_t hdfgwtr_el2;
+	uint64_t hfgitr_el2;
+	uint64_t hfgrtr_el2;
+	uint64_t hfgwtr_el2;
+} el2_fgt_regs_t;
+
+typedef struct el2_ecv_regs {
+	uint64_t cntpoff_el2;
+} el2_ecv_regs_t;
+
+typedef struct el2_vhe_regs {
+	uint64_t contextidr_el2;
+	uint64_t ttbr1_el2;
+} el2_vhe_regs_t;
+
+typedef struct el2_ras_regs {
+	uint64_t vdisr_el2;
+	uint64_t vsesr_el2;
+} el2_ras_regs_t;
+
+typedef struct el2_neve_regs {
+	uint64_t vncr_el2;
+} el2_neve_regs_t;
+
+typedef struct el2_trf_regs {
+	uint64_t trfcr_el2;
+} el2_trf_regs_t;
+
+typedef struct el2_csv2_regs {
+	uint64_t scxtnum_el2;
+} el2_csv2_regs_t;
+
+typedef struct el2_hcx_regs {
+	uint64_t hcrx_el2;
+} el2_hcx_regs_t;
+
+typedef struct el2_tcr2_regs {
+	uint64_t tcr2_el2;
+} el2_tcr2_regs_t;
+
+typedef struct el2_sxpoe_regs {
+	uint64_t por_el2;
+} el2_sxpoe_regs_t;
+
+typedef struct el2_sxpie_regs {
+	uint64_t pire0_el2;
+	uint64_t pir_el2;
+} el2_sxpie_regs_t;
+
+typedef struct el2_s2pie_regs {
+	uint64_t s2pir_el2;
+} el2_s2pie_regs_t;
+
+typedef struct el2_gcs_regs {
+	uint64_t gcscr_el2;
+	uint64_t gcspr_el2;
+} el2_gcs_regs_t;
+
+typedef struct el2_sysregs {
+
+	el2_common_regs_t common;
+
+#if ENABLE_FEAT_MTE
+	el2_mte_regs_t mte;
+#endif
+
+#if ENABLE_FEAT_FGT
+	el2_fgt_regs_t fgt;
+#endif
+
+#if ENABLE_FEAT_ECV
+	el2_ecv_regs_t ecv;
+#endif
+
+#if ENABLE_FEAT_VHE
+	el2_vhe_regs_t vhe;
+#endif
+
+#if ENABLE_FEAT_RAS
+	el2_ras_regs_t ras;
+#endif
+
+#if CTX_INCLUDE_NEVE_REGS
+	el2_neve_regs_t neve;
+#endif
+
+#if ENABLE_TRF_FOR_NS
+	el2_trf_regs_t trf;
+#endif
+
+#if ENABLE_FEAT_CSV2_2
+	el2_csv2_regs_t csv2;
+#endif
+
+#if ENABLE_FEAT_HCX
+	el2_hcx_regs_t hcx;
+#endif
+
+#if ENABLE_FEAT_TCR2
+	el2_tcr2_regs_t tcr2;
+#endif
+
+#if (ENABLE_FEAT_S1POE || ENABLE_FEAT_S2POE)
+	el2_sxpoe_regs_t sxpoe;
+#endif
+
+#if (ENABLE_FEAT_S1PIE || ENABLE_FEAT_S2PIE)
+	el2_sxpie_regs_t sxpie;
+#endif
+
+#if ENABLE_FEAT_S2PIE
+	el2_s2pie_regs_t s2pie;
+#endif
+
+#if ENABLE_FEAT_GCS
+	el2_gcs_regs_t gcs;
+#endif
+
+} el2_sysregs_t;
+
+/*
+ * Macros to access members related to individual features of the el2_sysregs_t
+ * structures.
+ */
+#define read_el2_ctx_common(ctx, reg)		(((ctx)->common).reg)
+
+#define write_el2_ctx_common(ctx, reg, val)	((((ctx)->common).reg)	\
+							= (uint64_t) (val))
+
+#if ENABLE_FEAT_MTE
+#define read_el2_ctx_mte(ctx, reg)		(((ctx)->mte).reg)
+#define write_el2_ctx_mte(ctx, reg, val)	((((ctx)->mte).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_mte(ctx, reg)		ULL(0)
+#define write_el2_ctx_mte(ctx, reg, val)
+#endif /* ENABLE_FEAT_MTE */
+
+#if ENABLE_FEAT_FGT
+#define read_el2_ctx_fgt(ctx, reg)		(((ctx)->fgt).reg)
+#define write_el2_ctx_fgt(ctx, reg, val)	((((ctx)->fgt).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_fgt(ctx, reg)		ULL(0)
+#define write_el2_ctx_fgt(ctx, reg, val)
+#endif /* ENABLE_FEAT_FGT */
+
+#if ENABLE_FEAT_ECV
+#define read_el2_ctx_ecv(ctx, reg)		(((ctx)->ecv).reg)
+#define write_el2_ctx_ecv(ctx, reg, val)	((((ctx)->ecv).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_ecv(ctx, reg)		ULL(0)
+#define write_el2_ctx_ecv(ctx, reg, val)
+#endif /* ENABLE_FEAT_ECV */
+
+#if ENABLE_FEAT_VHE
+#define read_el2_ctx_vhe(ctx, reg)		(((ctx)->vhe).reg)
+#define write_el2_ctx_vhe(ctx, reg, val)	((((ctx)->vhe).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_vhe(ctx, reg)		ULL(0)
+#define write_el2_ctx_vhe(ctx, reg, val)
+#endif /* ENABLE_FEAT_VHE */
+
+#if ENABLE_FEAT_RAS
+#define read_el2_ctx_ras(ctx, reg)		(((ctx)->ras).reg)
+#define write_el2_ctx_ras(ctx, reg, val)	((((ctx)->ras).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_ras(ctx, reg)		ULL(0)
+#define write_el2_ctx_ras(ctx, reg, val)
+#endif /* ENABLE_FEAT_RAS */
+
+#if CTX_INCLUDE_NEVE_REGS
+#define read_el2_ctx_neve(ctx, reg)		(((ctx)->neve).reg)
+#define write_el2_ctx_neve(ctx, reg, val)	((((ctx)->neve).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_neve(ctx, reg)		ULL(0)
+#define write_el2_ctx_neve(ctx, reg, val)
+#endif /* CTX_INCLUDE_NEVE_REGS */
+
+#if ENABLE_TRF_FOR_NS
+#define read_el2_ctx_trf(ctx, reg)		(((ctx)->trf).reg)
+#define write_el2_ctx_trf(ctx, reg, val)	((((ctx)->trf).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_trf(ctx, reg)		ULL(0)
+#define write_el2_ctx_trf(ctx, reg, val)
+#endif /* ENABLE_TRF_FOR_NS */
+
+#if ENABLE_FEAT_CSV2_2
+#define read_el2_ctx_csv2_2(ctx, reg)		(((ctx)->csv2).reg)
+#define write_el2_ctx_csv2_2(ctx, reg, val)	((((ctx)->csv2).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_csv2_2(ctx, reg)		ULL(0)
+#define write_el2_ctx_csv2_2(ctx, reg, val)
+#endif /* ENABLE_FEAT_CSV2_2 */
+
+#if ENABLE_FEAT_HCX
+#define read_el2_ctx_hcx(ctx, reg)		(((ctx)->hcx).reg)
+#define write_el2_ctx_hcx(ctx, reg, val)	((((ctx)->hcx).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_hcx(ctx, reg)		ULL(0)
+#define write_el2_ctx_hcx(ctx, reg, val)
+#endif /* ENABLE_FEAT_HCX */
+
+#if ENABLE_FEAT_TCR2
+#define read_el2_ctx_tcr2(ctx, reg)		(((ctx)->tcr2).reg)
+#define write_el2_ctx_tcr2(ctx, reg, val)	((((ctx)->tcr2).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_tcr2(ctx, reg)		ULL(0)
+#define write_el2_ctx_tcr2(ctx, reg, val)
+#endif /* ENABLE_FEAT_TCR2 */
+
+#if (ENABLE_FEAT_S1POE || ENABLE_FEAT_S2POE)
+#define read_el2_ctx_sxpoe(ctx, reg)		(((ctx)->sxpoe).reg)
+#define write_el2_ctx_sxpoe(ctx, reg, val)	((((ctx)->sxpoe).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_sxpoe(ctx, reg)		ULL(0)
+#define write_el2_ctx_sxpoe(ctx, reg, val)
+#endif /*(ENABLE_FEAT_S1POE || ENABLE_FEAT_S2POE) */
+
+#if (ENABLE_FEAT_S1PIE || ENABLE_FEAT_S2PIE)
+#define read_el2_ctx_sxpie(ctx, reg)		(((ctx)->sxpie).reg)
+#define write_el2_ctx_sxpie(ctx, reg, val)	((((ctx)->sxpie).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_sxpie(ctx, reg)		ULL(0)
+#define write_el2_ctx_sxpie(ctx, reg, val)
+#endif /*(ENABLE_FEAT_S1PIE || ENABLE_FEAT_S2PIE) */
+
+#if ENABLE_FEAT_S2PIE
+#define read_el2_ctx_s2pie(ctx, reg)		(((ctx)->s2pie).reg)
+#define write_el2_ctx_s2pie(ctx, reg, val)	((((ctx)->s2pie).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_s2pie(ctx, reg)		ULL(0)
+#define write_el2_ctx_s2pie(ctx, reg, val)
+#endif /* ENABLE_FEAT_S2PIE */
+
+#if ENABLE_FEAT_GCS
+#define read_el2_ctx_gcs(ctx, reg)		(((ctx)->gcs).reg)
+#define write_el2_ctx_gcs(ctx, reg, val)	((((ctx)->gcs).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_gcs(ctx, reg)		ULL(0)
+#define write_el2_ctx_gcs(ctx, reg, val)
+#endif /* ENABLE_FEAT_GCS */
+
+#endif /* CTX_INCLUDE_EL2_REGS */
+/******************************************************************************/
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CONTEXT_EL2_H */
diff --git a/include/lib/psa/dice_protection_environment.h b/include/lib/psa/dice_protection_environment.h
new file mode 100644
index 0000000..61b6482
--- /dev/null
+++ b/include/lib/psa/dice_protection_environment.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DICE_PROTECTION_ENVIRONMENT_H
+#define DICE_PROTECTION_ENVIRONMENT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <dice.h>
+
+/* Additional defines for max size limit. These limits are set by DPE in RSS. */
+#define DICE_AUTHORITY_DESCRIPTOR_MAX_SIZE	64
+#define DICE_CONFIG_DESCRIPTOR_MAX_SIZE		64
+#define DICE_CODE_DESCRIPTOR_MAX_SIZE		32
+
+typedef int32_t dpe_error_t;
+
+#define DPE_NO_ERROR			((dpe_error_t)0)
+#define DPE_INTERNAL_ERROR		((dpe_error_t)1)
+#define DPE_INVALID_COMMAND		((dpe_error_t)2)
+#define DPE_INVALID_ARGUMENT		((dpe_error_t)3)
+#define DPE_ARGUMENT_NOT_SUPPORTED	((dpe_error_t)4)
+#define DPE_SESSION_EXHAUSTED		((dpe_error_t)5)
+
+/* Custom values in RSS based DPE implementation */
+#define DPE_INSUFFICIENT_MEMORY		((dpe_error_t)128)
+#define DPE_ERR_CBOR_FORMATTING		((dpe_error_t)129)
+
+/**
+ * Client facing API. Parameters are according to the DPE spec version r0.9
+ *
+ * \brief Performs the DICE computation to derive a new context and optionally
+ *        creates an intermediate certificate. Software component measurement
+ *        must be provided in dice_inputs.
+ *
+ * \param[in]  context_handle              Input context handle for the DPE
+ *                                         context.
+ * \param[in]  cert_id                     Logical certificate id to which derived
+ *                                         context belongs to.
+ * \param[in]  retain_parent_context       Flag to indicate whether to retain the
+ *                                         parent context. True only if a client
+ *                                         will call further DPE commands on the
+ *                                         same context.
+ * \param[in]  allow_new_context_to_derive Flag to indicate whether derived context
+ *                                         can derive further. True only if the
+ *                                         new context will load further components.
+ * \param[in]  create_certificate          Flag to indicate whether to create an
+ *                                         intermediate certificate. True only if
+ *                                         it is the last component in the layer.
+ * \param[in]  dice_inputs                 DICE input values.
+ * \param[in]  target_locality             Identifies the locality to which the
+ *                                         derived context will be bound. Could be
+ *                                         MHU id.
+ * \param[in]  return_certificate          Indicates whether to return the generated
+ *                                         certificate when create_certificate is true.
+ * \param[in]  allow_new_context_to_export Indicates whether the DPE permits export of
+ *                                         the CDI from the newly derived context.
+ * \param[in]  export_cdi                  Indicates whether to export derived CDI.
+ * \param[out] new_context_handle          New handle for the derived context.
+ * \param[out] new_parent_context_handle   New handle for the parent context.
+ * \param[out] new_certificate_buf         If create_certificate and return_certificate
+ *                                         are both true, this argument holds the new
+ *                                         certificate generated for the new context
+ * \param[in]  new_certificate_buf_size    Size of the allocated buffer for
+ *                                         new certificate.
+ * \param[out] new_certificate_actual_size Actual size of the new certificate.
+ * \param[out] exported_cdi_buf            If export_cdi is true, this is the
+ *                                         exported CDI value.
+ * \param[in]  exported_cdi_buf_size       Size of the allocated buffer for
+ *                                         exported cdi.
+ * \param[out] exported_cdi_actual_size    Actual size of the exported cdi.
+ *
+ * \return Returns error code of type dpe_error_t
+ */
+dpe_error_t dpe_derive_context(int      context_handle,
+			       uint32_t cert_id,
+			       bool     retain_parent_context,
+			       bool     allow_new_context_to_derive,
+			       bool     create_certificate,
+			       const DiceInputValues *dice_inputs,
+			       int32_t  target_locality,
+			       bool     return_certificate,
+			       bool     allow_new_context_to_export,
+			       bool     export_cdi,
+			       int     *new_context_handle,
+			       int     *new_parent_context_handle,
+			       uint8_t *new_certificate_buf,
+			       size_t   new_certificate_buf_size,
+			       size_t  *new_certificate_actual_size,
+			       uint8_t *exported_cdi_buf,
+			       size_t   exported_cdi_buf_size,
+			       size_t  *exported_cdi_actual_size);
+
+#endif /* DICE_PROTECTION_ENVIRONMENT_H */
diff --git a/include/lib/psa/measured_boot.h b/include/lib/psa/measured_boot.h
index af624a6..79cdfa0 100644
--- a/include/lib/psa/measured_boot.h
+++ b/include/lib/psa/measured_boot.h
@@ -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
  *
@@ -14,21 +14,6 @@
 
 #include "psa/error.h"
 
-/* Minimum measurement value size that can be requested to store */
-#define MEASUREMENT_VALUE_MIN_SIZE	32U
-/* Maximum measurement value size that can be requested to store */
-#define MEASUREMENT_VALUE_MAX_SIZE	64U
-/* Minimum signer id size that can be requested to store */
-#define SIGNER_ID_MIN_SIZE		MEASUREMENT_VALUE_MIN_SIZE
-/* Maximum signer id size that can be requested to store */
-#define SIGNER_ID_MAX_SIZE		MEASUREMENT_VALUE_MAX_SIZE
-/* The theoretical maximum image version is: "255.255.65535\0" */
-#define VERSION_MAX_SIZE		14U
-/* Example sw_type: "BL_2, BL_33, etc." */
-#define SW_TYPE_MAX_SIZE		20U
-#define NUM_OF_MEASUREMENT_SLOTS	32U
-
-
 /**
  * Extends and stores a measurement to the requested slot.
  *
diff --git a/include/lib/psa/psa_manifest/sid.h b/include/lib/psa/psa_manifest/sid.h
index 7183112..6c15656 100644
--- a/include/lib/psa/psa_manifest/sid.h
+++ b/include/lib/psa/psa_manifest/sid.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -17,7 +17,10 @@
 /******** PSA_SP_MEASURED_BOOT ********/
 #define RSS_MEASURED_BOOT_HANDLE			(0x40000110U)
 
-/******** PSA_SP_DELAGATED_ATTESTATION ********/
+/******** PSA_SP_DELEGATED_ATTESTATION ********/
 #define RSS_DELEGATED_SERVICE_HANDLE			(0x40000111U)
 
+/******** PSA_SP_DICE_PROTECTION_ENVIRONMENT ********/
+#define RSS_DPE_SERVICE_HANDLE				(0x40000112U)
+
 #endif /* PSA_MANIFEST_SID_H */
diff --git a/include/plat/arm/common/arm_tzc_dram.ld.S b/include/plat/arm/common/arm_tzc_dram.ld.S
index c790bb9..08990f6 100644
--- a/include/plat/arm/common/arm_tzc_dram.ld.S
+++ b/include/plat/arm/common/arm_tzc_dram.ld.S
@@ -18,6 +18,9 @@
 	ASSERT(. == ALIGN(PAGE_SIZE),
 	"ARM_EL3_TZC_DRAM_BASE address is not aligned on a page boundary.")
 	.el3_tzc_dram (NOLOAD) : ALIGN(PAGE_SIZE) {
+	__PLAT_SPMC_SHMEM_DATASTORE_START__ = .;
+	*(.arm_spmc_shmem_datastore)
+	__PLAT_SPMC_SHMEM_DATASTORE_END__ = .;
 	__EL3_SEC_DRAM_START__ = .;
 	*(.arm_el3_tzc_dram)
 	__EL3_SEC_DRAM_UNALIGNED_END__ = .;
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 4c425a7..828d43a 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -290,6 +290,12 @@
 int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
 
 #if MEASURED_BOOT
+#if DICE_PROTECTION_ENVIRONMENT
+int arm_set_nt_fw_info(int *ctx_handle);
+int arm_set_tb_fw_info(int *ctx_handle);
+int arm_get_tb_fw_info(int *ctx_handle);
+#else
+/* Specific to event log backend */
 int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size);
 int arm_set_nt_fw_info(
 /*
@@ -304,6 +310,7 @@
 		       size_t log_max_size);
 int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size,
 		       size_t *log_max_size);
+#endif /* DICE_PROTECTION_ENVIRONMENT */
 #endif /* MEASURED_BOOT */
 
 /*
diff --git a/include/plat/common/plat_drtm.h b/include/plat/common/plat_drtm.h
index e96e719..07545a6 100644
--- a/include/plat/common/plat_drtm.h
+++ b/include/plat/common/plat_drtm.h
@@ -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
  */
@@ -17,7 +17,7 @@
 
 typedef struct {
 	bool tpm_based_hash_support;
-	uint32_t firmware_hash_algorithm;
+	uint16_t firmware_hash_algorithm;
 } plat_drtm_tpm_features_t;
 
 typedef struct {
@@ -26,7 +26,7 @@
 } __attribute__((packed)) drtm_mem_region_t;
 
 /*
- * Memory region descriptor table structure as per DRTM beta0 section 3.13
+ * Memory region descriptor table structure as per DRTM 1.0 section 3.13
  * Table 11 MEMORY_REGION_DESCRIPTOR_TABLE
  */
 typedef struct {
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 4d1b1c1..4fe3620 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -136,6 +136,7 @@
 void plat_ic_set_interrupt_pending(unsigned int id);
 void plat_ic_clear_interrupt_pending(unsigned int id);
 unsigned int plat_ic_set_priority_mask(unsigned int mask);
+unsigned int plat_ic_deactivate_priority(unsigned int mask);
 unsigned int plat_ic_get_interrupt_id(unsigned int raw);
 
 /*******************************************************************************
@@ -242,7 +243,7 @@
 int bl1_plat_handle_pre_image_load(unsigned int image_id);
 int bl1_plat_handle_post_image_load(unsigned int image_id);
 
-#if MEASURED_BOOT
+#if (MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT)
 void bl1_plat_mboot_init(void);
 void bl1_plat_mboot_finish(void);
 #else
@@ -252,7 +253,7 @@
 static inline void bl1_plat_mboot_finish(void)
 {
 }
-#endif /* MEASURED_BOOT */
+#endif /* MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT */
 
 /*******************************************************************************
  * Mandatory BL2 functions
@@ -272,7 +273,7 @@
 /*******************************************************************************
  * Optional BL2 functions (may be overridden)
  ******************************************************************************/
-#if MEASURED_BOOT
+#if (MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT)
 void bl2_plat_mboot_init(void);
 void bl2_plat_mboot_finish(void);
 #else
@@ -282,7 +283,7 @@
 static inline void bl2_plat_mboot_finish(void)
 {
 }
-#endif /* MEASURED_BOOT */
+#endif /* MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENTs */
 
 /*******************************************************************************
  * Mandatory BL2 at EL3 functions: Must be implemented
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/include/services/drtm_svc.h b/include/services/drtm_svc.h
index 69b314f..f0d3c63 100644
--- a/include/services/drtm_svc.h
+++ b/include/services/drtm_svc.h
@@ -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
  *
@@ -54,10 +54,10 @@
 	(((_fid) >= ARM_DRTM_SVC_VERSION) && ((_fid) <= ARM_DRTM_SVC_LOCK_TCB_HASH))
 
 /* ARM DRTM Service Calls version numbers */
-#define ARM_DRTM_VERSION_MAJOR		U(0)
+#define ARM_DRTM_VERSION_MAJOR		U(1)
 #define ARM_DRTM_VERSION_MAJOR_SHIFT	16
 #define ARM_DRTM_VERSION_MAJOR_MASK	U(0x7FFF)
-#define ARM_DRTM_VERSION_MINOR		U(1)
+#define ARM_DRTM_VERSION_MINOR		U(0)
 #define ARM_DRTM_VERSION_MINOR_SHIFT	0
 #define ARM_DRTM_VERSION_MINOR_MASK	U(0xFFFF)
 
@@ -74,7 +74,7 @@
 #define ARM_DRTM_FEAT_ID_MASK	ULL(0xff)
 
 /*
- * Definitions for DRTM features as per DRTM beta0 section 3.3,
+ * Definitions for DRTM features as per DRTM 1.0 section 3.3,
  * Table 6 DRTM_FEATURES
  */
 #define ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_SHIFT		U(33)
@@ -87,7 +87,7 @@
 #define ARM_DRTM_TPM_FEATURES_TPM_HASH_SUPPORTED	ULL(0x1)
 
 #define ARM_DRTM_TPM_FEATURES_FW_HASH_SHIFT		U(0)
-#define ARM_DRTM_TPM_FEATURES_FW_HASH_MASK		ULL(0xFFFFFFFF)
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_MASK		ULL(0xFFFF)
 #define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA256		ULL(0xB)
 #define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA384		ULL(0xC)
 #define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA512		ULL(0xD)
diff --git a/include/tools_share/tbbr_oid.h b/include/tools_share/tbbr_oid.h
index 9881d1a..1a2e355 100644
--- a/include/tools_share/tbbr_oid.h
+++ b/include/tools_share/tbbr_oid.h
@@ -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
  */
@@ -170,6 +170,12 @@
 #define SOC_FW_CONFIG_KEY_OID			SOC_FW_CONTENT_CERT_PK_OID
 #define HW_CONFIG_KEY_OID			ZERO_OID
 
+#define SCP_BL2_IMAGE_KEY_OID			SCP_FW_CONTENT_CERT_PK_OID
+#define BL32_IMAGE_KEY_OID			TRUSTED_OS_FW_CONTENT_CERT_PK_OID
+#define TOS_FW_CONFIG_KEY_OID			TRUSTED_OS_FW_CONTENT_CERT_PK_OID
+#define BL33_IMAGE_KEY_OID			NON_TRUSTED_FW_CONTENT_CERT_PK_OID
+#define NT_FW_CONFIG_KEY_OID			NON_TRUSTED_FW_CONTENT_CERT_PK_OID
+
 #ifdef PLAT_DEF_OID
 #include <platform_oid.h>
 #endif
diff --git a/lib/cpus/aarch64/cortex_a715.S b/lib/cpus/aarch64/cortex_a715.S
index 0faa276..abd649c 100644
--- a/lib/cpus/aarch64/cortex_a715.S
+++ b/lib/cpus/aarch64/cortex_a715.S
@@ -26,9 +26,68 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A715_BHB_LOOP_COUNT, cortex_a715
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-workaround_runtime_start cortex_a715, ERRATUM(2561034), ERRATA_A715_2561034
+workaround_reset_start cortex_a715, ERRATUM(2331818), ERRATA_A715_2331818
+        sysreg_bit_set CORTEX_A715_CPUACTLR2_EL1, BIT(20)
+workaround_reset_end cortex_a715, ERRATUM(2331818)
+
+check_erratum_ls cortex_a715, ERRATUM(2331818), CPU_REV(1, 0)
+
+workaround_reset_start cortex_a715, ERRATUM(2344187), ERRATA_A715_2344187
+	/* GCR_EL1 is only present with FEAT_MTE2. */
+	mrs x1, ID_AA64PFR1_EL1
+	ubfx x0, x1, ID_AA64PFR1_EL1_MTE_SHIFT, #4
+	cmp x0, #MTE_IMPLEMENTED_ELX
+	bne #1f
+	sysreg_bit_set GCR_EL1, GCR_EL1_RRND_BIT
+
+1:
+	/* Mitigation upon ERETAA and ERETAB. */
+	mov x0, #2
+	msr CORTEX_A715_CPUPSELR_EL3, x0
+	isb
+	ldr x0, =0xd69f0bff
+	msr CORTEX_A715_CPUPOR_EL3, x0
+	ldr x0, =0xfffffbff
+	msr CORTEX_A715_CPUPMR_EL3, x0
+	mov x1, #0
+	orr x1, x1, #(1<<0)
+	orr x1, x1, #(3<<4)
+	orr x1, x1, #(0xf<<6)
+	orr x1, x1, #(1<<13)
+	orr x1, x1, #(1<<53)
+	msr CORTEX_A715_CPUPCR_EL3, x1
+workaround_reset_end cortex_a715, ERRATUM(2344187)
+
+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. */
+	mrs x1, id_aa64dfr0_el1
+	ubfx x0, x1, ID_AA64DFR0_PMS_SHIFT, #4
+	cbz x0, 1f
+	sysreg_bit_set CORTEX_A715_CPUACTLR_EL1, BIT(57)
+	sysreg_bit_set CORTEX_A715_CPUACTLR_EL1, BIT(58)
+1:
+workaround_reset_end cortex_a715, ERRATUM(2413290)
+
+check_erratum_range cortex_a715, ERRATUM(2413290), CPU_REV(1,0), CPU_REV(1, 0)
+
+workaround_reset_start cortex_a715, ERRATUM(2420947), ERRATA_A715_2420947
+        sysreg_bit_set CORTEX_A715_CPUACTLR2_EL1, BIT(33)
+workaround_reset_end cortex_a715, ERRATUM(2420947)
+
+check_erratum_range cortex_a715, ERRATUM(2420947), CPU_REV(1, 0), CPU_REV(1, 0)
+
+workaround_reset_start cortex_a715, ERRATUM(2429384), ERRATA_A715_2429384
+        sysreg_bit_set CORTEX_A715_CPUACTLR2_EL1, BIT(27)
+workaround_reset_end cortex_a715, ERRATUM(2429384)
+
+check_erratum_range cortex_a715, ERRATUM(2429384), CPU_REV(1, 0), CPU_REV(1, 0)
+
+workaround_reset_start cortex_a715, ERRATUM(2561034), ERRATA_A715_2561034
 	sysreg_bit_set	CORTEX_A715_CPUACTLR2_EL1, BIT(26)
-workaround_runtime_end cortex_a715, ERRATUM(2561034), NO_ISB
+workaround_reset_end cortex_a715, ERRATUM(2561034)
 
 check_erratum_range cortex_a715, ERRATUM(2561034), 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..2075acd 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,12 @@
         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(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/cortex_x3.S b/lib/cpus/aarch64/cortex_x3.S
index e5a05fc..49e9ad1 100644
--- a/lib/cpus/aarch64/cortex_x3.S
+++ b/lib/cpus/aarch64/cortex_x3.S
@@ -51,6 +51,13 @@
 
 check_erratum_ls cortex_x3, ERRATUM(2313909), CPU_REV(1, 0)
 
+workaround_reset_start cortex_x3, ERRATUM(2372204), ERRATA_X3_2372204
+	/* Set bit 40 in CPUACTLR2_EL1 */
+	sysreg_bit_set CORTEX_X3_CPUACTLR2_EL1, BIT(40)
+workaround_reset_end cortex_x3, ERRATUM(2372204)
+
+check_erratum_ls cortex_x3, ERRATUM(2372204), CPU_REV(1, 0)
+
 workaround_reset_start cortex_x3, ERRATUM(2615812), ERRATA_X3_2615812
 	/* Disable retention control for WFI and WFE. */
 	mrs	x0, CORTEX_X3_CPUPWRCTLR_EL1
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index dcbeba1..a7a8c8a 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -790,14 +790,22 @@
 # to revisions r0p0 and r1p0 of the Cortex-X3 cpu, it is fixed in r1p1.
 CPU_FLAG_LIST += ERRATA_X3_2313909
 
+# Flag to apply erratum 2372204 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0 of the Cortex-X3 cpu, it is fixed in r1p1.
+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
 # to revisions r0p0 and r1p0 of the Cortex-X3 cpu, it is fixed in r1p1.
 CPU_FLAG_LIST += ERRATA_X3_2641945
 
+# Flag to apply erratum 2701951 workaround for non-arm interconnect ip.
+# This erratum applies to revisions r0p0, r1p0, and r1p1. Its is fixed in r1p2.
+CPU_FLAG_LIST += ERRATA_X3_2701951
+
 # Flag to apply erratum 2742421 workaround on reset. This erratum applies
 # to revisions r0p0, r1p0 and r1p1 of the Cortex-X3 cpu, it is fixed in r1p2.
 CPU_FLAG_LIST += ERRATA_X3_2742421
@@ -810,6 +818,11 @@
 # to revisions r0p0, r1p0, r1p1 of the Cortex-X3 cpu, it is fixed in r1p2.
 CPU_FLAG_LIST += ERRATA_X3_2779509
 
+# Flag to apply erratum 2701112 workaround for platforms that do not use an
+# Arm interconnect IP. This erratum applies to revisions r0p0 of the Cortex-X4
+# cpu and is fixed in r0p1.
+CPU_FLAG_LIST += ERRATA_X4_2701112
+
 # Flag to apply erratum 1922240 workaround during reset. This erratum applies
 # to revision r0p0 of the Cortex-A510 cpu and is fixed in r0p1.
 CPU_FLAG_LIST += ERRATA_A510_1922240
@@ -903,13 +916,33 @@
 # This erratum applies to revisions r0p0, r0p1. Fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_V2_2801372
 
+# Flag to apply erratum 2331818 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0. It is fixed in r1p1.
+CPU_FLAG_LIST += ERRATA_A715_2331818
+
+# Flag to apply erratum 2344187 workaround during reset. This erratum applies
+# to revisions r0p0, and r1p0. It is fixed in r1p1.
+CPU_FLAG_LIST += ERRATA_A715_2344187
+
+# Flag to apply erratum 2413290 workaround during reset. This erratum applies
+# only to revision r1p0. It is fixed in r1p1.
+CPU_FLAG_LIST += ERRATA_A715_2413290
+
+# Flag to apply erratum 2420947 workaround during reset. This erratum applies
+# only to revision r1p0. It is fixed in r1p1.
+CPU_FLAG_LIST += ERRATA_A715_2420947
+
+# Flag to apply erratum 2429384 workaround during reset. This erratum applies
+# to revision r1p0. There is no workaround for r0p0. It is fixed in r1p1.
+CPU_FLAG_LIST += ERRATA_A715_2429384
+
 # Flag to apply erratum 2561034 workaround during reset. This erratum applies
 # only to revision r1p0. It is fixed in r1p1.
 CPU_FLAG_LIST += ERRATA_A715_2561034
 
-# Flag to apply erratum 2701951 workaround for non-arm interconnect ip.
-# This erratum applies to revisions r0p0, r1p0, and r1p1. Its is fixed in r1p2.
-CPU_FLAG_LIST += ERRATA_A715_2701951
+# 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.
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 922b2cf..ee94dfd 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
 	/*
@@ -262,10 +264,10 @@
 	 * Initialize SCTLR_EL2 context register using Endianness value
 	 * taken from the entrypoint attribute.
 	 */
-	u_register_t sctlr_el2 = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0UL;
-	sctlr_el2 |= SCTLR_EL2_RES1;
-	write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_SCTLR_EL2,
-			sctlr_el2);
+	u_register_t sctlr_el2_val = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0UL;
+	sctlr_el2_val |= SCTLR_EL2_RES1;
+	write_el2_ctx_common(get_el2_sysregs_ctx(ctx), sctlr_el2, sctlr_el2_val);
+
 
 	if (is_feat_hcx_supported()) {
 		/*
@@ -276,7 +278,7 @@
 		 * this feature if not properly initialized, especially when
 		 * it comes to those bits that enable/disable traps.
 		 */
-		write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_HCRX_EL2,
+		write_el2_ctx_hcx(get_el2_sysregs_ctx(ctx), hcrx_el2,
 			HCRX_EL2_INIT_VAL);
 	}
 
@@ -286,13 +288,14 @@
 		 * systems unaware of FEAT_FGT do not get trapped due to their lack
 		 * of initialization for this feature.
 		 */
-		write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_HFGITR_EL2,
+		write_el2_ctx_fgt(get_el2_sysregs_ctx(ctx), hfgitr_el2,
 			HFGITR_EL2_INIT_VAL);
-		write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_HFGRTR_EL2,
+		write_el2_ctx_fgt(get_el2_sysregs_ctx(ctx), hfgrtr_el2,
 			HFGRTR_EL2_INIT_VAL);
-		write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_HFGWTR_EL2,
+		write_el2_ctx_fgt(get_el2_sysregs_ctx(ctx), hfgwtr_el2,
 			HFGWTR_EL2_INIT_VAL);
 	}
+
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 	manage_extensions_nonsecure(ctx);
@@ -330,9 +333,9 @@
 	 * These bits are set in the gicv3 driver. Losing them (especially the
 	 * SRE bit) is problematic for all worlds. Henceforth recreate them.
 	 */
-	u_register_t icc_sre_el2 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT |
+	u_register_t icc_sre_el2_val = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT |
 				   ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT;
-	write_ctx_reg(el2_ctx, CTX_ICC_SRE_EL2, icc_sre_el2);
+	write_el2_ctx_common(el2_ctx, icc_sre_el2, icc_sre_el2_val);
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 	/* Start with a clean SCR_EL3 copy as all relevant values are set */
@@ -958,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.
@@ -985,29 +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);
 }
@@ -1016,26 +1022,26 @@
 
 static void el2_sysregs_context_save_fgt(el2_sysregs_t *ctx)
 {
-	write_ctx_reg(ctx, CTX_HDFGRTR_EL2, read_hdfgrtr_el2());
+	write_el2_ctx_fgt(ctx, hdfgrtr_el2, read_hdfgrtr_el2());
 	if (is_feat_amu_supported()) {
-		write_ctx_reg(ctx, CTX_HAFGRTR_EL2, read_hafgrtr_el2());
+		write_el2_ctx_fgt(ctx, hafgrtr_el2, read_hafgrtr_el2());
 	}
-	write_ctx_reg(ctx, CTX_HDFGWTR_EL2, read_hdfgwtr_el2());
-	write_ctx_reg(ctx, CTX_HFGITR_EL2, read_hfgitr_el2());
-	write_ctx_reg(ctx, CTX_HFGRTR_EL2, read_hfgrtr_el2());
-	write_ctx_reg(ctx, CTX_HFGWTR_EL2, read_hfgwtr_el2());
+	write_el2_ctx_fgt(ctx, hdfgwtr_el2, read_hdfgwtr_el2());
+	write_el2_ctx_fgt(ctx, hfgitr_el2, read_hfgitr_el2());
+	write_el2_ctx_fgt(ctx, hfgrtr_el2, read_hfgrtr_el2());
+	write_el2_ctx_fgt(ctx, hfgwtr_el2, read_hfgwtr_el2());
 }
 
 static void el2_sysregs_context_restore_fgt(el2_sysregs_t *ctx)
 {
-	write_hdfgrtr_el2(read_ctx_reg(ctx, CTX_HDFGRTR_EL2));
+	write_hdfgrtr_el2(read_el2_ctx_fgt(ctx, hdfgrtr_el2));
 	if (is_feat_amu_supported()) {
-		write_hafgrtr_el2(read_ctx_reg(ctx, CTX_HAFGRTR_EL2));
+		write_hafgrtr_el2(read_el2_ctx_fgt(ctx, hafgrtr_el2));
 	}
-	write_hdfgwtr_el2(read_ctx_reg(ctx, CTX_HDFGWTR_EL2));
-	write_hfgitr_el2(read_ctx_reg(ctx, CTX_HFGITR_EL2));
-	write_hfgrtr_el2(read_ctx_reg(ctx, CTX_HFGRTR_EL2));
-	write_hfgwtr_el2(read_ctx_reg(ctx, CTX_HFGWTR_EL2));
+	write_hdfgwtr_el2(read_el2_ctx_fgt(ctx, hdfgwtr_el2));
+	write_hfgitr_el2(read_el2_ctx_fgt(ctx, hfgitr_el2));
+	write_hfgrtr_el2(read_el2_ctx_fgt(ctx, hfgrtr_el2));
+	write_hfgwtr_el2(read_el2_ctx_fgt(ctx, hfgwtr_el2));
 }
 
 #if CTX_INCLUDE_MPAM_REGS
@@ -1148,38 +1154,37 @@
 static void el2_sysregs_context_save_gic(el2_sysregs_t *ctx)
 {
 #if defined(SPD_spmd) && SPMD_SPM_AT_SEL2
-	write_ctx_reg(ctx, CTX_ICC_SRE_EL2, read_icc_sre_el2());
+	write_el2_ctx_common(ctx, icc_sre_el2, read_icc_sre_el2());
 #else
 	u_register_t scr_el3 = read_scr_el3();
 	write_scr_el3(scr_el3 | SCR_NS_BIT);
 	isb();
 
-	write_ctx_reg(ctx, CTX_ICC_SRE_EL2, read_icc_sre_el2());
+	write_el2_ctx_common(ctx, icc_sre_el2, read_icc_sre_el2());
 
 	write_scr_el3(scr_el3);
 	isb();
-
 #endif
-	write_ctx_reg(ctx, CTX_ICH_HCR_EL2, read_ich_hcr_el2());
-	write_ctx_reg(ctx, CTX_ICH_VMCR_EL2, read_ich_vmcr_el2());
+	write_el2_ctx_common(ctx, ich_hcr_el2, read_ich_hcr_el2());
+	write_el2_ctx_common(ctx, ich_vmcr_el2, read_ich_vmcr_el2());
 }
 
 static void el2_sysregs_context_restore_gic(el2_sysregs_t *ctx)
 {
 #if defined(SPD_spmd) && SPMD_SPM_AT_SEL2
-	write_icc_sre_el2(read_ctx_reg(ctx, CTX_ICC_SRE_EL2));
+	write_icc_sre_el2(read_el2_ctx_common(ctx, icc_sre_el2));
 #else
 	u_register_t scr_el3 = read_scr_el3();
 	write_scr_el3(scr_el3 | SCR_NS_BIT);
 	isb();
 
-	write_icc_sre_el2(read_ctx_reg(ctx, CTX_ICC_SRE_EL2));
+	write_icc_sre_el2(read_el2_ctx_common(ctx, icc_sre_el2));
 
 	write_scr_el3(scr_el3);
 	isb();
 #endif
-	write_ich_hcr_el2(read_ctx_reg(ctx, CTX_ICH_HCR_EL2));
-	write_ich_vmcr_el2(read_ctx_reg(ctx, CTX_ICH_VMCR_EL2));
+	write_ich_hcr_el2(read_el2_ctx_common(ctx, ich_hcr_el2));
+	write_ich_vmcr_el2(read_el2_ctx_common(ctx, ich_vmcr_el2));
 }
 
 /* -----------------------------------------------------
@@ -1190,70 +1195,70 @@
  */
 static void el2_sysregs_context_save_common(el2_sysregs_t *ctx)
 {
-	write_ctx_reg(ctx, CTX_ACTLR_EL2, read_actlr_el2());
-	write_ctx_reg(ctx, CTX_AFSR0_EL2, read_afsr0_el2());
-	write_ctx_reg(ctx, CTX_AFSR1_EL2, read_afsr1_el2());
-	write_ctx_reg(ctx, CTX_AMAIR_EL2, read_amair_el2());
-	write_ctx_reg(ctx, CTX_CNTHCTL_EL2, read_cnthctl_el2());
-	write_ctx_reg(ctx, CTX_CNTVOFF_EL2, read_cntvoff_el2());
-	write_ctx_reg(ctx, CTX_CPTR_EL2, read_cptr_el2());
+	write_el2_ctx_common(ctx, actlr_el2, read_actlr_el2());
+	write_el2_ctx_common(ctx, afsr0_el2, read_afsr0_el2());
+	write_el2_ctx_common(ctx, afsr1_el2, read_afsr1_el2());
+	write_el2_ctx_common(ctx, amair_el2, read_amair_el2());
+	write_el2_ctx_common(ctx, cnthctl_el2, read_cnthctl_el2());
+	write_el2_ctx_common(ctx, cntvoff_el2, read_cntvoff_el2());
+	write_el2_ctx_common(ctx, cptr_el2, read_cptr_el2());
 	if (CTX_INCLUDE_AARCH32_REGS) {
-		write_ctx_reg(ctx, CTX_DBGVCR32_EL2, read_dbgvcr32_el2());
+		write_el2_ctx_common(ctx, dbgvcr32_el2, read_dbgvcr32_el2());
 	}
-	write_ctx_reg(ctx, CTX_ELR_EL2, read_elr_el2());
-	write_ctx_reg(ctx, CTX_ESR_EL2, read_esr_el2());
-	write_ctx_reg(ctx, CTX_FAR_EL2, read_far_el2());
-	write_ctx_reg(ctx, CTX_HACR_EL2, read_hacr_el2());
-	write_ctx_reg(ctx, CTX_HCR_EL2, read_hcr_el2());
-	write_ctx_reg(ctx, CTX_HPFAR_EL2, read_hpfar_el2());
-	write_ctx_reg(ctx, CTX_HSTR_EL2, read_hstr_el2());
-	write_ctx_reg(ctx, CTX_MAIR_EL2, read_mair_el2());
-	write_ctx_reg(ctx, CTX_MDCR_EL2, read_mdcr_el2());
-	write_ctx_reg(ctx, CTX_SCTLR_EL2, read_sctlr_el2());
-	write_ctx_reg(ctx, CTX_SPSR_EL2, read_spsr_el2());
-	write_ctx_reg(ctx, CTX_SP_EL2, read_sp_el2());
-	write_ctx_reg(ctx, CTX_TCR_EL2, read_tcr_el2());
-	write_ctx_reg(ctx, CTX_TPIDR_EL2, read_tpidr_el2());
-	write_ctx_reg(ctx, CTX_TTBR0_EL2, read_ttbr0_el2());
-	write_ctx_reg(ctx, CTX_VBAR_EL2, read_vbar_el2());
-	write_ctx_reg(ctx, CTX_VMPIDR_EL2, read_vmpidr_el2());
-	write_ctx_reg(ctx, CTX_VPIDR_EL2, read_vpidr_el2());
-	write_ctx_reg(ctx, CTX_VTCR_EL2, read_vtcr_el2());
-	write_ctx_reg(ctx, CTX_VTTBR_EL2, read_vttbr_el2());
+	write_el2_ctx_common(ctx, elr_el2, read_elr_el2());
+	write_el2_ctx_common(ctx, esr_el2, read_esr_el2());
+	write_el2_ctx_common(ctx, far_el2, read_far_el2());
+	write_el2_ctx_common(ctx, hacr_el2, read_hacr_el2());
+	write_el2_ctx_common(ctx, hcr_el2, read_hcr_el2());
+	write_el2_ctx_common(ctx, hpfar_el2, read_hpfar_el2());
+	write_el2_ctx_common(ctx, hstr_el2, read_hstr_el2());
+	write_el2_ctx_common(ctx, mair_el2, read_mair_el2());
+	write_el2_ctx_common(ctx, mdcr_el2, read_mdcr_el2());
+	write_el2_ctx_common(ctx, sctlr_el2, read_sctlr_el2());
+	write_el2_ctx_common(ctx, spsr_el2, read_spsr_el2());
+	write_el2_ctx_common(ctx, sp_el2, read_sp_el2());
+	write_el2_ctx_common(ctx, tcr_el2, read_tcr_el2());
+	write_el2_ctx_common(ctx, tpidr_el2, read_tpidr_el2());
+	write_el2_ctx_common(ctx, ttbr0_el2, read_ttbr0_el2());
+	write_el2_ctx_common(ctx, vbar_el2, read_vbar_el2());
+	write_el2_ctx_common(ctx, vmpidr_el2, read_vmpidr_el2());
+	write_el2_ctx_common(ctx, vpidr_el2, read_vpidr_el2());
+	write_el2_ctx_common(ctx, vtcr_el2, read_vtcr_el2());
+	write_el2_ctx_common(ctx, vttbr_el2, read_vttbr_el2());
 }
 
 static void el2_sysregs_context_restore_common(el2_sysregs_t *ctx)
 {
-	write_actlr_el2(read_ctx_reg(ctx, CTX_ACTLR_EL2));
-	write_afsr0_el2(read_ctx_reg(ctx, CTX_AFSR0_EL2));
-	write_afsr1_el2(read_ctx_reg(ctx, CTX_AFSR1_EL2));
-	write_amair_el2(read_ctx_reg(ctx, CTX_AMAIR_EL2));
-	write_cnthctl_el2(read_ctx_reg(ctx, CTX_CNTHCTL_EL2));
-	write_cntvoff_el2(read_ctx_reg(ctx, CTX_CNTVOFF_EL2));
-	write_cptr_el2(read_ctx_reg(ctx, CTX_CPTR_EL2));
+	write_actlr_el2(read_el2_ctx_common(ctx, actlr_el2));
+	write_afsr0_el2(read_el2_ctx_common(ctx, afsr0_el2));
+	write_afsr1_el2(read_el2_ctx_common(ctx, afsr1_el2));
+	write_amair_el2(read_el2_ctx_common(ctx, amair_el2));
+	write_cnthctl_el2(read_el2_ctx_common(ctx, cnthctl_el2));
+	write_cntvoff_el2(read_el2_ctx_common(ctx, cntvoff_el2));
+	write_cptr_el2(read_el2_ctx_common(ctx, cptr_el2));
 	if (CTX_INCLUDE_AARCH32_REGS) {
-		write_dbgvcr32_el2(read_ctx_reg(ctx, CTX_DBGVCR32_EL2));
+		write_dbgvcr32_el2(read_el2_ctx_common(ctx, dbgvcr32_el2));
 	}
-	write_elr_el2(read_ctx_reg(ctx, CTX_ELR_EL2));
-	write_esr_el2(read_ctx_reg(ctx, CTX_ESR_EL2));
-	write_far_el2(read_ctx_reg(ctx, CTX_FAR_EL2));
-	write_hacr_el2(read_ctx_reg(ctx, CTX_HACR_EL2));
-	write_hcr_el2(read_ctx_reg(ctx, CTX_HCR_EL2));
-	write_hpfar_el2(read_ctx_reg(ctx, CTX_HPFAR_EL2));
-	write_hstr_el2(read_ctx_reg(ctx, CTX_HSTR_EL2));
-	write_mair_el2(read_ctx_reg(ctx, CTX_MAIR_EL2));
-	write_mdcr_el2(read_ctx_reg(ctx, CTX_MDCR_EL2));
-	write_sctlr_el2(read_ctx_reg(ctx, CTX_SCTLR_EL2));
-	write_spsr_el2(read_ctx_reg(ctx, CTX_SPSR_EL2));
-	write_sp_el2(read_ctx_reg(ctx, CTX_SP_EL2));
-	write_tcr_el2(read_ctx_reg(ctx, CTX_TCR_EL2));
-	write_tpidr_el2(read_ctx_reg(ctx, CTX_TPIDR_EL2));
-	write_ttbr0_el2(read_ctx_reg(ctx, CTX_TTBR0_EL2));
-	write_vbar_el2(read_ctx_reg(ctx, CTX_VBAR_EL2));
-	write_vmpidr_el2(read_ctx_reg(ctx, CTX_VMPIDR_EL2));
-	write_vpidr_el2(read_ctx_reg(ctx, CTX_VPIDR_EL2));
-	write_vtcr_el2(read_ctx_reg(ctx, CTX_VTCR_EL2));
-	write_vttbr_el2(read_ctx_reg(ctx, CTX_VTTBR_EL2));
+	write_elr_el2(read_el2_ctx_common(ctx, elr_el2));
+	write_esr_el2(read_el2_ctx_common(ctx, esr_el2));
+	write_far_el2(read_el2_ctx_common(ctx, far_el2));
+	write_hacr_el2(read_el2_ctx_common(ctx, hacr_el2));
+	write_hcr_el2(read_el2_ctx_common(ctx, hcr_el2));
+	write_hpfar_el2(read_el2_ctx_common(ctx, hpfar_el2));
+	write_hstr_el2(read_el2_ctx_common(ctx, hstr_el2));
+	write_mair_el2(read_el2_ctx_common(ctx, mair_el2));
+	write_mdcr_el2(read_el2_ctx_common(ctx, mdcr_el2));
+	write_sctlr_el2(read_el2_ctx_common(ctx, sctlr_el2));
+	write_spsr_el2(read_el2_ctx_common(ctx, spsr_el2));
+	write_sp_el2(read_el2_ctx_common(ctx, sp_el2));
+	write_tcr_el2(read_el2_ctx_common(ctx, tcr_el2));
+	write_tpidr_el2(read_el2_ctx_common(ctx, tpidr_el2));
+	write_ttbr0_el2(read_el2_ctx_common(ctx, ttbr0_el2));
+	write_vbar_el2(read_el2_ctx_common(ctx, vbar_el2));
+	write_vmpidr_el2(read_el2_ctx_common(ctx, vmpidr_el2));
+	write_vpidr_el2(read_el2_ctx_common(ctx, vpidr_el2));
+	write_vtcr_el2(read_el2_ctx_common(ctx, vtcr_el2));
+	write_vttbr_el2(read_el2_ctx_common(ctx, vttbr_el2));
 }
 
 /*******************************************************************************
@@ -1272,8 +1277,8 @@
 	el2_sysregs_context_save_common(el2_sysregs_ctx);
 	el2_sysregs_context_save_gic(el2_sysregs_ctx);
 
-	if (is_feat_mte2_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_TFSR_EL2, read_tfsr_el2());
+	if (is_feat_mte_supported()) {
+		write_el2_ctx_mte(el2_sysregs_ctx, tfsr_el2, read_tfsr_el2());
 	}
 
 #if CTX_INCLUDE_MPAM_REGS
@@ -1288,51 +1293,57 @@
 	}
 
 	if (is_feat_ecv_v2_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_CNTPOFF_EL2, read_cntpoff_el2());
+		write_el2_ctx_ecv(el2_sysregs_ctx, cntpoff_el2, read_cntpoff_el2());
 	}
 
 	if (is_feat_vhe_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_CONTEXTIDR_EL2, read_contextidr_el2());
-		write_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2, read_ttbr1_el2());
+		write_el2_ctx_vhe(el2_sysregs_ctx, contextidr_el2,
+					read_contextidr_el2());
+		write_el2_ctx_vhe(el2_sysregs_ctx, ttbr1_el2, read_ttbr1_el2());
 	}
 
 	if (is_feat_ras_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_VDISR_EL2, read_vdisr_el2());
-		write_ctx_reg(el2_sysregs_ctx, CTX_VSESR_EL2, read_vsesr_el2());
+		write_el2_ctx_ras(el2_sysregs_ctx, vdisr_el2, read_vdisr_el2());
+		write_el2_ctx_ras(el2_sysregs_ctx, vsesr_el2, read_vsesr_el2());
 	}
 
 	if (is_feat_nv2_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_VNCR_EL2, read_vncr_el2());
+		write_el2_ctx_neve(el2_sysregs_ctx, vncr_el2, read_vncr_el2());
 	}
 
 	if (is_feat_trf_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_TRFCR_EL2, read_trfcr_el2());
+		write_el2_ctx_trf(el2_sysregs_ctx, trfcr_el2, read_trfcr_el2());
 	}
 
-	/* CSV2 version 2 and above */
 	if (is_feat_csv2_2_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_SCXTNUM_EL2, read_scxtnum_el2());
+		write_el2_ctx_csv2_2(el2_sysregs_ctx, scxtnum_el2,
+					read_scxtnum_el2());
 	}
 
 	if (is_feat_hcx_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_HCRX_EL2, read_hcrx_el2());
+		write_el2_ctx_hcx(el2_sysregs_ctx, hcrx_el2, read_hcrx_el2());
 	}
+
 	if (is_feat_tcr2_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_TCR2_EL2, read_tcr2_el2());
+		write_el2_ctx_tcr2(el2_sysregs_ctx, tcr2_el2, read_tcr2_el2());
 	}
+
 	if (is_feat_sxpie_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_PIRE0_EL2, read_pire0_el2());
-		write_ctx_reg(el2_sysregs_ctx, CTX_PIR_EL2, read_pir_el2());
-	}
-	if (is_feat_s2pie_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_S2PIR_EL2, read_s2pir_el2());
+		write_el2_ctx_sxpie(el2_sysregs_ctx, pire0_el2, read_pire0_el2());
+		write_el2_ctx_sxpie(el2_sysregs_ctx, pir_el2, read_pir_el2());
 	}
+
 	if (is_feat_sxpoe_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_POR_EL2, read_por_el2());
+		write_el2_ctx_sxpoe(el2_sysregs_ctx, por_el2, read_por_el2());
 	}
+
+	if (is_feat_s2pie_supported()) {
+		write_el2_ctx_s2pie(el2_sysregs_ctx, s2pir_el2, read_s2pir_el2());
+	}
+
 	if (is_feat_gcs_supported()) {
-		write_ctx_reg(el2_sysregs_ctx, CTX_GCSPR_EL2, read_gcspr_el2());
-		write_ctx_reg(el2_sysregs_ctx, CTX_GCSCR_EL2, read_gcscr_el2());
+		write_el2_ctx_gcs(el2_sysregs_ctx, gcscr_el2, read_gcspr_el2());
+		write_el2_ctx_gcs(el2_sysregs_ctx, gcspr_el2, read_gcscr_el2());
 	}
 }
 
@@ -1352,8 +1363,8 @@
 	el2_sysregs_context_restore_common(el2_sysregs_ctx);
 	el2_sysregs_context_restore_gic(el2_sysregs_ctx);
 
-	if (is_feat_mte2_supported()) {
-		write_tfsr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TFSR_EL2));
+	if (is_feat_mte_supported()) {
+		write_tfsr_el2(read_el2_ctx_mte(el2_sysregs_ctx, tfsr_el2));
 	}
 
 #if CTX_INCLUDE_MPAM_REGS
@@ -1368,50 +1379,57 @@
 	}
 
 	if (is_feat_ecv_v2_supported()) {
-		write_cntpoff_el2(read_ctx_reg(el2_sysregs_ctx, CTX_CNTPOFF_EL2));
+		write_cntpoff_el2(read_el2_ctx_ecv(el2_sysregs_ctx, cntpoff_el2));
 	}
 
 	if (is_feat_vhe_supported()) {
-		write_contextidr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_CONTEXTIDR_EL2));
-		write_ttbr1_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2));
+		write_contextidr_el2(read_el2_ctx_vhe(el2_sysregs_ctx,
+					contextidr_el2));
+		write_ttbr1_el2(read_el2_ctx_vhe(el2_sysregs_ctx, ttbr1_el2));
 	}
 
 	if (is_feat_ras_supported()) {
-		write_vdisr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VDISR_EL2));
-		write_vsesr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VSESR_EL2));
+		write_vdisr_el2(read_el2_ctx_ras(el2_sysregs_ctx, vdisr_el2));
+		write_vsesr_el2(read_el2_ctx_ras(el2_sysregs_ctx, vsesr_el2));
 	}
 
 	if (is_feat_nv2_supported()) {
-		write_vncr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VNCR_EL2));
+		write_vncr_el2(read_el2_ctx_neve(el2_sysregs_ctx, vncr_el2));
 	}
+
 	if (is_feat_trf_supported()) {
-		write_trfcr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TRFCR_EL2));
+		write_trfcr_el2(read_el2_ctx_trf(el2_sysregs_ctx, trfcr_el2));
 	}
 
-	/* CSV2 version 2 and above */
 	if (is_feat_csv2_2_supported()) {
-		write_scxtnum_el2(read_ctx_reg(el2_sysregs_ctx, CTX_SCXTNUM_EL2));
+		write_scxtnum_el2(read_el2_ctx_csv2_2(el2_sysregs_ctx,
+					scxtnum_el2));
 	}
 
 	if (is_feat_hcx_supported()) {
-		write_hcrx_el2(read_ctx_reg(el2_sysregs_ctx, CTX_HCRX_EL2));
+		write_hcrx_el2(read_el2_ctx_hcx(el2_sysregs_ctx, hcrx_el2));
 	}
+
 	if (is_feat_tcr2_supported()) {
-		write_tcr2_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TCR2_EL2));
+		write_tcr2_el2(read_el2_ctx_tcr2(el2_sysregs_ctx, tcr2_el2));
 	}
+
 	if (is_feat_sxpie_supported()) {
-		write_pire0_el2(read_ctx_reg(el2_sysregs_ctx, CTX_PIRE0_EL2));
-		write_pir_el2(read_ctx_reg(el2_sysregs_ctx, CTX_PIR_EL2));
-	}
-	if (is_feat_s2pie_supported()) {
-		write_s2pir_el2(read_ctx_reg(el2_sysregs_ctx, CTX_S2PIR_EL2));
+		write_pire0_el2(read_el2_ctx_sxpie(el2_sysregs_ctx, pire0_el2));
+		write_pir_el2(read_el2_ctx_sxpie(el2_sysregs_ctx, pir_el2));
 	}
+
 	if (is_feat_sxpoe_supported()) {
-		write_por_el2(read_ctx_reg(el2_sysregs_ctx, CTX_POR_EL2));
+		write_por_el2(read_el2_ctx_sxpoe(el2_sysregs_ctx, por_el2));
 	}
+
+	if (is_feat_s2pie_supported()) {
+		write_s2pir_el2(read_el2_ctx_s2pie(el2_sysregs_ctx, s2pir_el2));
+	}
+
 	if (is_feat_gcs_supported()) {
-		write_gcscr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_GCSCR_EL2));
-		write_gcspr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_GCSPR_EL2));
+		write_gcscr_el2(read_el2_ctx_gcs(el2_sysregs_ctx, gcscr_el2));
+		write_gcspr_el2(read_el2_ctx_gcs(el2_sysregs_ctx, gcspr_el2));
 	}
 }
 #endif /* CTX_INCLUDE_EL2_REGS */
diff --git a/lib/extensions/pmuv3/aarch64/pmuv3.c b/lib/extensions/pmuv3/aarch64/pmuv3.c
index 61fc47d..71aa303 100644
--- a/lib/extensions/pmuv3/aarch64/pmuv3.c
+++ b/lib/extensions/pmuv3/aarch64/pmuv3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -24,11 +24,11 @@
 void pmuv3_enable(cpu_context_t *ctx)
 {
 #if CTX_INCLUDE_EL2_REGS
-	u_register_t mdcr_el2;
+	u_register_t mdcr_el2_val;
 
-	mdcr_el2 = read_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_MDCR_EL2);
-	mdcr_el2 = init_mdcr_el2_hpmn(mdcr_el2);
-	write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_MDCR_EL2, mdcr_el2);
+	mdcr_el2_val = read_el2_ctx_common(get_el2_sysregs_ctx(ctx), mdcr_el2);
+	mdcr_el2_val = init_mdcr_el2_hpmn(mdcr_el2_val);
+	write_el2_ctx_common(get_el2_sysregs_ctx(ctx), mdcr_el2, mdcr_el2_val);
 #endif /* CTX_INCLUDE_EL2_REGS */
 }
 
diff --git a/lib/psa/dice_protection_environment.c b/lib/psa/dice_protection_environment.c
new file mode 100644
index 0000000..44a5848
--- /dev/null
+++ b/lib/psa/dice_protection_environment.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <qcbor/qcbor_decode.h>
+#include <qcbor/qcbor_encode.h>
+#include <qcbor/qcbor_spiffy_decode.h>
+
+#include <common/debug.h>
+#include <dice.h>
+#include <dice_protection_environment.h>
+#include <psa/client.h>
+#include <psa_manifest/sid.h>
+
+enum dpe_command_id_t {
+	/* Standard commands */
+	DPE_GET_PROFILE = 1,
+	DPE_OPEN_SESSION = 2,
+	DPE_CLOSE_SESSION = 3,
+	DPE_SYNC_SESSION = 4,
+	DPE_EXPORT_SESSION = 5,
+	DPE_IMPORT_SESSION = 6,
+	DPE_INITIALIZE_CONTEXT = 7,
+	DPE_DERIVE_CONTEXT = 8,
+	DPE_CERTIFY_KEY = 9,
+	DPE_SIGN = 10,
+	DPE_SEAL = 11,
+	DPE_UNSEAL = 12,
+	DPE_DERIVE_SEALING_PUBLIC_KEY = 13,
+	DPE_ROTATE_CONTEXT_HANDLE = 14,
+	DPE_DESTROY_CONTEXT = 15,
+};
+
+enum dice_input_labels_t {
+	DICE_CODE_HASH = 1,
+	DICE_CODE_DESCRIPTOR = 2,
+	DICE_CONFIG_TYPE = 3,
+	DICE_CONFIG_VALUE = 4,
+	DICE_CONFIG_DESCRIPTOR = 5,
+	DICE_AUTHORITY_HASH = 6,
+	DICE_AUTHORITY_DESCRIPTOR = 7,
+	DICE_MODE = 8,
+	DICE_HIDDEN = 9,
+};
+
+enum dpe_derive_context_input_labels_t {
+	DPE_DERIVE_CONTEXT_CONTEXT_HANDLE = 1,
+	DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT = 2,
+	DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE = 3,
+	DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE = 4,
+	DPE_DERIVE_CONTEXT_NEW_SESSION_INITIATOR_HANDSHAKE = 5,
+	DPE_DERIVE_CONTEXT_INPUT_DATA = 6,
+	DPE_DERIVE_CONTEXT_INTERNAL_INPUTS = 7,
+	DPE_DERIVE_CONTEXT_TARGET_LOCALITY = 8,
+	DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE = 9,
+	DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT = 10,
+	DPE_DERIVE_CONTEXT_EXPORT_CDI = 11,
+	/* enum values 256 and onwards are reserved for custom arguments */
+	DPE_DERIVE_CONTEXT_CERT_ID = 256,
+};
+
+enum dpe_derive_context_output_labels_t {
+	DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE = 1,
+	DPE_DERIVE_CONTEXT_NEW_SESSION_RESPONDER_HANDSHAKE = 2,
+	DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE = 3,
+	DPE_DERIVE_CONTEXT_NEW_CERTIFICATE = 4,
+	DPE_DERIVE_CONTEXT_EXPORTED_CDI = 5,
+};
+
+struct derive_context_input_t {
+	int context_handle;
+	uint32_t cert_id;
+	bool retain_parent_context;
+	bool allow_new_context_to_derive;
+	bool create_certificate;
+	const DiceInputValues *dice_inputs;
+	int32_t target_locality;
+	bool return_certificate;
+	bool allow_new_context_to_export;
+	bool export_cdi;
+};
+
+struct derive_context_output_t {
+	int new_context_handle;
+	int new_parent_context_handle;
+	const uint8_t *new_certificate;
+	size_t new_certificate_size;
+	const uint8_t *exported_cdi;
+	size_t exported_cdi_size;
+};
+
+static void encode_dice_inputs(QCBOREncodeContext *encode_ctx,
+			       const DiceInputValues *input)
+{
+	/* Wrap the DICE inputs into a byte string */
+	QCBOREncode_BstrWrapInMapN(encode_ctx, DPE_DERIVE_CONTEXT_INPUT_DATA);
+
+	/* Inside the byte string the DICE inputs are encoded as a map */
+	QCBOREncode_OpenMap(encode_ctx);
+
+	QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_HASH,
+				  (UsefulBufC) { input->code_hash,
+						 sizeof(input->code_hash) });
+
+	QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_DESCRIPTOR,
+				   (UsefulBufC) { input->code_descriptor,
+						  input->code_descriptor_size });
+
+	QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_CONFIG_TYPE,
+				   input->config_type);
+
+	if (input->config_type == kDiceConfigTypeInline) {
+		QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_VALUE,
+					   (UsefulBufC) { input->config_value,
+							  sizeof(input->config_value) });
+	} else {
+		QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_DESCRIPTOR,
+					   (UsefulBufC) { input->config_descriptor,
+							  input->config_descriptor_size });
+	}
+
+	QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_HASH,
+				   (UsefulBufC) { input->authority_hash,
+						  sizeof(input->authority_hash) });
+
+	QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_DESCRIPTOR,
+				   (UsefulBufC) { input->authority_descriptor,
+						  input->authority_descriptor_size });
+
+	QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_MODE, input->mode);
+
+	QCBOREncode_AddBytesToMapN(encode_ctx, DICE_HIDDEN,
+				   (UsefulBufC) { input->hidden,
+						  sizeof(input->hidden) });
+
+	QCBOREncode_CloseMap(encode_ctx);
+	QCBOREncode_CloseBstrWrap2(encode_ctx, true, NULL);
+}
+
+static QCBORError encode_derive_context(const struct derive_context_input_t *args,
+					UsefulBuf buf,
+					UsefulBufC *encoded_buf)
+{
+	QCBOREncodeContext encode_ctx;
+
+	QCBOREncode_Init(&encode_ctx, buf);
+
+	QCBOREncode_OpenArray(&encode_ctx);
+	QCBOREncode_AddUInt64(&encode_ctx, DPE_DERIVE_CONTEXT);
+
+	/* Encode DeriveContext command */
+	QCBOREncode_OpenMap(&encode_ctx);
+	QCBOREncode_AddBytesToMapN(&encode_ctx,
+				   DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
+				   (UsefulBufC) { &args->context_handle,
+						  sizeof(args->context_handle) });
+	QCBOREncode_AddUInt64ToMapN(&encode_ctx,
+				    DPE_DERIVE_CONTEXT_CERT_ID,
+				    args->cert_id);
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
+				  args->retain_parent_context);
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
+				  args->allow_new_context_to_derive);
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
+				  args->create_certificate);
+	encode_dice_inputs(&encode_ctx, args->dice_inputs);
+	QCBOREncode_AddBytesToMapN(&encode_ctx,
+				   DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
+				   (UsefulBufC) { &args->target_locality,
+						  sizeof(args->target_locality) });
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
+				  args->return_certificate);
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
+				  args->allow_new_context_to_export);
+	QCBOREncode_AddBoolToMapN(&encode_ctx,
+				  DPE_DERIVE_CONTEXT_EXPORT_CDI,
+				  args->export_cdi);
+	QCBOREncode_CloseMap(&encode_ctx);
+
+	QCBOREncode_CloseArray(&encode_ctx);
+
+	return QCBOREncode_Finish(&encode_ctx, encoded_buf);
+}
+
+static QCBORError decode_derive_context_response(UsefulBufC encoded_buf,
+						 struct derive_context_output_t *args,
+						 dpe_error_t *dpe_err)
+{
+	QCBORDecodeContext decode_ctx;
+	UsefulBufC out;
+	int64_t response_dpe_err;
+
+	QCBORDecode_Init(&decode_ctx, encoded_buf, QCBOR_DECODE_MODE_NORMAL);
+
+	QCBORDecode_EnterArray(&decode_ctx, NULL);
+
+	/* Get the error code from the response. DPE returns int32_t */
+	QCBORDecode_GetInt64(&decode_ctx, &response_dpe_err);
+	*dpe_err = (dpe_error_t)response_dpe_err;
+
+	/* Decode DeriveContext response if successful */
+	if (*dpe_err == DPE_NO_ERROR) {
+		QCBORDecode_EnterMap(&decode_ctx, NULL);
+
+		QCBORDecode_GetByteStringInMapN(&decode_ctx,
+						DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
+						&out);
+		if (out.len != sizeof(args->new_context_handle)) {
+			return QCBORDecode_Finish(&decode_ctx);
+		}
+		memcpy(&args->new_context_handle, out.ptr, out.len);
+
+		QCBORDecode_GetByteStringInMapN(&decode_ctx,
+						DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
+						&out);
+		if (out.len != sizeof(args->new_parent_context_handle)) {
+			return QCBORDecode_Finish(&decode_ctx);
+		}
+		memcpy(&args->new_parent_context_handle, out.ptr, out.len);
+
+		QCBORDecode_GetByteStringInMapN(&decode_ctx,
+						DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
+						&out);
+		args->new_certificate = out.ptr;
+		args->new_certificate_size = out.len;
+
+		QCBORDecode_GetByteStringInMapN(&decode_ctx,
+						DPE_DERIVE_CONTEXT_EXPORTED_CDI,
+						&out);
+		args->exported_cdi = out.ptr;
+		args->exported_cdi_size = out.len;
+
+		QCBORDecode_ExitMap(&decode_ctx);
+	}
+
+	QCBORDecode_ExitArray(&decode_ctx);
+
+	return QCBORDecode_Finish(&decode_ctx);
+}
+
+static int32_t dpe_client_call(const char *cmd_input, size_t cmd_input_size,
+			       char *cmd_output, size_t *cmd_output_size)
+{
+	int32_t err;
+
+	psa_invec in_vec[] = {
+		{ cmd_input, cmd_input_size },
+	};
+	psa_outvec out_vec[] = {
+		{ cmd_output, *cmd_output_size },
+	};
+
+	err = psa_call(RSS_DPE_SERVICE_HANDLE, 0,
+			in_vec, IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	if (err == PSA_SUCCESS) {
+		*cmd_output_size = out_vec[0].len;
+	}
+
+	return err;
+}
+
+dpe_error_t dpe_derive_context(int context_handle,
+			       uint32_t cert_id,
+			       bool retain_parent_context,
+			       bool allow_new_context_to_derive,
+			       bool create_certificate,
+			       const DiceInputValues *dice_inputs,
+			       int32_t target_locality,
+			       bool return_certificate,
+			       bool allow_new_context_to_export,
+			       bool export_cdi,
+			       int *new_context_handle,
+			       int *new_parent_context_handle,
+			       uint8_t *new_certificate_buf,
+			       size_t new_certificate_buf_size,
+			       size_t *new_certificate_actual_size,
+			       uint8_t *exported_cdi_buf,
+			       size_t exported_cdi_buf_size,
+			       size_t *exported_cdi_actual_size)
+{
+	int32_t service_err;
+	dpe_error_t dpe_err;
+	QCBORError qcbor_err;
+	UsefulBufC encoded_buf;
+	UsefulBuf_MAKE_STACK_UB(cmd_buf, 612);
+
+	const struct derive_context_input_t in_args = {
+		context_handle,
+		cert_id,
+		retain_parent_context,
+		allow_new_context_to_derive,
+		create_certificate,
+		dice_inputs,
+		target_locality,
+		return_certificate,
+		allow_new_context_to_export,
+		export_cdi,
+	};
+	struct derive_context_output_t out_args;
+
+	/*
+	 * Validate the output params here because they are not sent to the
+	 * service. Input params are validated by the DPE service.
+	 */
+	if ((new_context_handle == NULL) ||
+	    (retain_parent_context == true && new_parent_context_handle == NULL) ||
+	    (return_certificate == true &&
+		(new_certificate_buf == NULL || new_certificate_actual_size == NULL)) ||
+	    (export_cdi == true &&
+		(exported_cdi_buf == NULL || exported_cdi_actual_size == NULL))) {
+		return DPE_INVALID_ARGUMENT;
+	}
+
+	qcbor_err = encode_derive_context(&in_args, cmd_buf, &encoded_buf);
+	if (qcbor_err != QCBOR_SUCCESS) {
+		return DPE_INTERNAL_ERROR;
+	}
+
+	service_err = dpe_client_call(encoded_buf.ptr, encoded_buf.len,
+				      cmd_buf.ptr, &cmd_buf.len);
+	if (service_err != 0) {
+		return DPE_INTERNAL_ERROR;
+	}
+
+	qcbor_err = decode_derive_context_response(UsefulBuf_Const(cmd_buf),
+						   &out_args, &dpe_err);
+	if (qcbor_err != QCBOR_SUCCESS) {
+		return DPE_INTERNAL_ERROR;
+	} else if (dpe_err != DPE_NO_ERROR) {
+		return dpe_err;
+	}
+
+	/* Copy returned values into caller's memory */
+	*new_context_handle = out_args.new_context_handle;
+
+	if (retain_parent_context == true) {
+		*new_parent_context_handle = out_args.new_parent_context_handle;
+	}
+
+	if (return_certificate == true) {
+		if (out_args.new_certificate_size > new_certificate_buf_size) {
+			return DPE_INVALID_ARGUMENT;
+		}
+
+		memcpy(new_certificate_buf, out_args.new_certificate,
+			out_args.new_certificate_size);
+		*new_certificate_actual_size = out_args.new_certificate_size;
+	}
+
+	if (export_cdi == true) {
+		if (out_args.exported_cdi_size > exported_cdi_buf_size) {
+			return DPE_INVALID_ARGUMENT;
+		}
+
+		memcpy(exported_cdi_buf, out_args.exported_cdi,
+			out_args.exported_cdi_size);
+		*exported_cdi_actual_size = out_args.exported_cdi_size;
+	}
+
+	return DPE_NO_ERROR;
+}
diff --git a/lib/psa/measured_boot.c b/lib/psa/measured_boot.c
index 38990b5..ff1f45d 100644
--- a/lib/psa/measured_boot.c
+++ b/lib/psa/measured_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <common/debug.h>
+#include <drivers/measured_boot/metadata.h>
 #include <measured_boot.h>
 #include <psa/client.h>
 #include <psa_manifest/sid.h>
diff --git a/lib/psa/measured_boot_private.h b/lib/psa/measured_boot_private.h
index 80d2c19..b8ca31d 100644
--- a/lib/psa/measured_boot_private.h
+++ b/lib/psa/measured_boot_private.h
@@ -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
  *
@@ -10,6 +10,8 @@
 
 #include <stdint.h>
 
+#include <drivers/measured_boot/metadata.h>
+
 /* Measured boot message types that distinguish its services */
 #define RSS_MEASURED_BOOT_READ		1001U
 #define RSS_MEASURED_BOOT_EXTEND	1002U
diff --git a/licenses/LICENSE-APACHE-2.0.txt b/licenses/LICENSE-APACHE-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/licenses/LICENSE-APACHE-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 1802077..26d2a00 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -176,6 +176,9 @@
 # Option to build TF with Measured Boot support
 MEASURED_BOOT			:= 0
 
+# Option to enable the DICE Protection Environmnet as a Measured Boot backend
+DICE_PROTECTION_ENVIRONMENT	:=0
+
 # NS timer register save and restore
 NS_TIMER_SWITCH			:= 0
 
@@ -351,6 +354,14 @@
 # Disable Firmware update support by default
 PSA_FWU_SUPPORT			:= 0
 
+# Enable image description in FWU metadata by default when PSA_FWU_SUPPORT
+# is enabled.
+ifeq ($(PSA_FWU_SUPPORT),1)
+PSA_FWU_METADATA_FW_STORE_DESC	:= 1
+else
+PSA_FWU_METADATA_FW_STORE_DESC	:= 0
+endif
+
 # Dynamic Root of Trust for Measurement support
 DRTM_SUPPORT			:= 0
 
diff --git a/package-lock.json b/package-lock.json
index 7753a38..e60c44e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,6 @@
     "": {
       "name": "trusted-firmware-a",
       "version": "2.10.0",
-      "hasInstallScript": true,
       "license": "BSD-3-Clause",
       "devDependencies": {
         "@commitlint/cli": "^19.0.0",
diff --git a/package.json b/package.json
index 43c897e..7ad5c58 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
   "type": "module",
   "private": true,
   "scripts": {
-    "postinstall": "husky install",
+    "prepare": "husky",
     "release": "standard-version"
   },
   "engines": {
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
index a32124a..1863292 100644
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -187,6 +187,7 @@
 	/* Change the DTB if the configuration requires so. */
 	sunxi_prepare_dtb(fdt);
 
+	console_flush();
 	console_switch_state(CONSOLE_FLAG_RUNTIME);
 }
 
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
index c9c248f..ec0b19e 100644
--- a/plat/arm/board/arm_fpga/platform.mk
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -127,8 +127,14 @@
 $(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,bl31))
 $(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,bl31))
 
+ifeq ($($(ARCH)-ld-id),gnu-gcc)
+        PLAT_LDFLAGS	+=	-Wl,--strip-debug
+else
+        PLAT_LDFLAGS	+=	--strip-debug
+endif
+
 bl31.axf: bl31 dtbs ${BUILD_PLAT}/rom_trampoline.o ${BUILD_PLAT}/kernel_trampoline.o ${BUILD_PLAT}/build_axf.ld
 	$(ECHO) "  LD      $@"
-	$(Q)$($(ARCH)-ld) -T ${BUILD_PLAT}/build_axf.ld -L ${BUILD_PLAT} --strip-debug -s -n -o ${BUILD_PLAT}/bl31.axf
+	$(Q)$($(ARCH)-ld) -T ${BUILD_PLAT}/build_axf.ld -L ${BUILD_PLAT} $(TF_LDFLAGS) $(PLAT_LDFLAGS) -s -n -o ${BUILD_PLAT}/bl31.axf
 
 all: bl31.axf
diff --git a/plat/arm/board/fvp/fvp_bl1_measured_boot.c b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
index 477ae27..f14dbff 100644
--- a/plat/arm/board/fvp/fvp_bl1_measured_boot.c
+++ b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
@@ -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
  */
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
 #include <plat/arm/common/plat_arm.h>
 #include <tools_share/zero_oid.h>
 
@@ -15,9 +16,9 @@
 
 /* FVP table with platform specific image IDs, names and PCRs */
 const event_log_metadata_t fvp_event_log_metadata[] = {
-	{ FW_CONFIG_ID, EVLOG_FW_CONFIG_STRING, PCR_0 },
-	{ TB_FW_CONFIG_ID, EVLOG_TB_FW_CONFIG_STRING, PCR_0 },
-	{ BL2_IMAGE_ID, EVLOG_BL2_STRING, PCR_0 },
+	{ FW_CONFIG_ID, MBOOT_FW_CONFIG_STRING, PCR_0 },
+	{ TB_FW_CONFIG_ID, MBOOT_TB_FW_CONFIG_STRING, PCR_0 },
+	{ BL2_IMAGE_ID, MBOOT_BL2_IMAGE_STRING, PCR_0 },
 
 	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
 };
diff --git a/plat/arm/board/fvp/fvp_bl2_measured_boot.c b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
index 369bcb4..8bf7dad 100644
--- a/plat/arm/board/fvp/fvp_bl2_measured_boot.c
+++ b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
@@ -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
  */
@@ -8,6 +8,7 @@
 
 #include <common/tbbr/tbbr_img_def.h>
 #include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
 #if defined(ARM_COT_cca)
 #include <tools_share/cca_oid.h>
 #else
@@ -28,27 +29,27 @@
 
 /* FVP table with platform specific image IDs, names and PCRs */
 const event_log_metadata_t fvp_event_log_metadata[] = {
-	{ BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
-	{ BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
-	{ BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
-	{ BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
-	{ BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
-	{ HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 },
-	{ NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 },
-	{ SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
-	{ SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
-	{ TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
-	{ RMM_IMAGE_ID, EVLOG_RMM_STRING, PCR_0},
+	{ BL31_IMAGE_ID, MBOOT_BL31_IMAGE_STRING, PCR_0 },
+	{ BL32_IMAGE_ID, MBOOT_BL32_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA1_IMAGE_ID, MBOOT_BL32_EXTRA1_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA2_IMAGE_ID, MBOOT_BL32_EXTRA2_IMAGE_STRING, PCR_0 },
+	{ BL33_IMAGE_ID, MBOOT_BL33_IMAGE_STRING, PCR_0 },
+	{ HW_CONFIG_ID, MBOOT_HW_CONFIG_STRING, PCR_0 },
+	{ NT_FW_CONFIG_ID, MBOOT_NT_FW_CONFIG_STRING, PCR_0 },
+	{ SCP_BL2_IMAGE_ID, MBOOT_SCP_BL2_IMAGE_STRING, PCR_0 },
+	{ SOC_FW_CONFIG_ID, MBOOT_SOC_FW_CONFIG_STRING, PCR_0 },
+	{ TOS_FW_CONFIG_ID, MBOOT_TOS_FW_CONFIG_STRING, PCR_0 },
+	{ RMM_IMAGE_ID, MBOOT_RMM_IMAGE_STRING, PCR_0},
 
 #if defined(SPD_spmd)
-	{ SP_PKG1_ID, EVLOG_SP1_STRING, PCR_0 },
-	{ SP_PKG2_ID, EVLOG_SP2_STRING, PCR_0 },
-	{ SP_PKG3_ID, EVLOG_SP3_STRING, PCR_0 },
-	{ SP_PKG4_ID, EVLOG_SP4_STRING, PCR_0 },
-	{ SP_PKG5_ID, EVLOG_SP5_STRING, PCR_0 },
-	{ SP_PKG6_ID, EVLOG_SP6_STRING, PCR_0 },
-	{ SP_PKG7_ID, EVLOG_SP7_STRING, PCR_0 },
-	{ SP_PKG8_ID, EVLOG_SP8_STRING, PCR_0 },
+	{ SP_PKG1_ID, MBOOT_SP1_STRING, PCR_0 },
+	{ SP_PKG2_ID, MBOOT_SP2_STRING, PCR_0 },
+	{ SP_PKG3_ID, MBOOT_SP3_STRING, PCR_0 },
+	{ SP_PKG4_ID, MBOOT_SP4_STRING, PCR_0 },
+	{ SP_PKG5_ID, MBOOT_SP5_STRING, PCR_0 },
+	{ SP_PKG6_ID, MBOOT_SP6_STRING, PCR_0 },
+	{ SP_PKG7_ID, MBOOT_SP7_STRING, PCR_0 },
+	{ SP_PKG8_ID, MBOOT_SP8_STRING, PCR_0 },
 #endif
 
 	{ CRITICAL_DATA_ID, EVLOG_CRITICAL_DATA_STRING, PCR_1 },
diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c
index e46dbc9..93289b6 100644
--- a/plat/arm/board/fvp/fvp_bl31_setup.c
+++ b/plat/arm/board/fvp/fvp_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -73,8 +73,19 @@
 	fvp_timer_init();
 
 	/* On FVP RevC, initialize SMMUv3 */
-	if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U)
-		smmuv3_init(PLAT_FVP_SMMUV3_BASE);
+	if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) {
+		if (smmuv3_security_init(PLAT_FVP_SMMUV3_BASE) != 0) {
+			/*
+			 * Don't proceed for smmuv3 initialization if the
+			 * security init failed.
+			 */
+			return;
+		}
+		/* SMMUv3 initialization failure is not fatal */
+		if (smmuv3_init(PLAT_FVP_SMMUV3_BASE) != 0) {
+			WARN("Failed initializing SMMU.\n");
+		}
+	}
 }
 
 void __init bl31_plat_arch_setup(void)
diff --git a/plat/arm/board/fvp/fvp_cpu_errata.mk b/plat/arm/board/fvp/fvp_cpu_errata.mk
index b8fa4ea..b26fa80 100644
--- a/plat/arm/board/fvp/fvp_cpu_errata.mk
+++ b/plat/arm/board/fvp/fvp_cpu_errata.mk
@@ -1,63 +1,32 @@
 #
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
-
-#/*
-# * TODO: below lines of code to be removed
-# * after abi and framework are synchronized
-# */
+# Flags to enable the cpu structures in the Errata ABI file
+# file: services/std_svc/errata_abi/errata_abi_main.c. This is specifically
+# for platforms that need to enable errata based on non-arm interconnect IP.
 
 ifeq (${ERRATA_ABI_SUPPORT}, 1)
-# enable the cpu macros for errata abi interface
-ifeq (${ARCH}, aarch64)
-ifeq (${HW_ASSISTED_COHERENCY}, 0)
-CORTEX_A35_H_INC	:= 1
-CORTEX_A53_H_INC	:= 1
-CORTEX_A57_H_INC	:= 1
-CORTEX_A72_H_INC	:= 1
-CORTEX_A73_H_INC	:= 1
-$(eval $(call add_define, CORTEX_A35_H_INC))
-$(eval $(call add_define, CORTEX_A53_H_INC))
-$(eval $(call add_define, CORTEX_A57_H_INC))
-$(eval $(call add_define, CORTEX_A72_H_INC))
-$(eval $(call add_define, CORTEX_A73_H_INC))
-else
+ifeq (${ERRATA_NON_ARM_INTERCONNECT}, 1)
 ifeq (${CTX_INCLUDE_AARCH32_REGS}, 0)
-CORTEX_A76_H_INC	:= 1
-CORTEX_A77_H_INC	:= 1
+CORTEX_A710_H_INC	:= 1
 CORTEX_A78_H_INC	:= 1
-NEOVERSE_N1_H_INC	:= 1
-NEOVERSE_N2_H_INC	:= 1
-NEOVERSE_V1_H_INC	:= 1
 CORTEX_A78_AE_H_INC	:= 1
-CORTEX_A510_H_INC	:= 1
-CORTEX_A710_H_INC	:= 1
-CORTEX_A715_H_INC 	:= 1
 CORTEX_A78C_H_INC	:= 1
-CORTEX_X2_H_INC		:= 1
-$(eval $(call add_define, CORTEX_A76_H_INC))
-$(eval $(call add_define, CORTEX_A77_H_INC))
+CORTEX_X3_H_INC		:= 1
+CORTEX_X4_H_INC		:= 1
+NEOVERSE_N2_H_INC	:= 1
+NEOVERSE_V1_H_INC	:= 1
+$(eval $(call add_define, CORTEX_A710_H_INC))
 $(eval $(call add_define, CORTEX_A78_H_INC))
-$(eval $(call add_define, NEOVERSE_N1_H_INC))
-$(eval $(call add_define, NEOVERSE_N2_H_INC))
-$(eval $(call add_define, NEOVERSE_V1_H_INC))
 $(eval $(call add_define, CORTEX_A78_AE_H_INC))
-$(eval $(call add_define, CORTEX_A510_H_INC))
-$(eval $(call add_define, CORTEX_A710_H_INC))
-$(eval $(call add_define, CORTEX_A715_H_INC))
 $(eval $(call add_define, CORTEX_A78C_H_INC))
-$(eval $(call add_define, CORTEX_X2_H_INC))
-endif
-CORTEX_A55_H_INC	:= 1
-CORTEX_A75_H_INC	:= 1
-$(eval $(call add_define, CORTEX_A55_H_INC))
-$(eval $(call add_define, CORTEX_A75_H_INC))
+$(eval $(call add_define, CORTEX_X3_H_INC))
+$(eval $(call add_define, CORTEX_X4_H_INC))
+$(eval $(call add_define, NEOVERSE_N2_H_INC))
+$(eval $(call add_define, NEOVERSE_V1_H_INC))
 endif
-else
-CORTEX_A32_H_INC	:= 1
-$(eval $(call add_define, CORTEX_A32_H_INC))
 endif
 endif
diff --git a/plat/arm/board/fvp/fvp_el3_spmc.c b/plat/arm/board/fvp/fvp_el3_spmc.c
index 6b44f63..c57a244 100644
--- a/plat/arm/board/fvp/fvp_el3_spmc.c
+++ b/plat/arm/board/fvp/fvp_el3_spmc.c
@@ -7,23 +7,14 @@
 
 #include <platform_def.h>
 
-/*
- * On the FVP platform when using the EL3 SPMC implementation allocate the
- * datastore for tracking shared memory descriptors in the TZC DRAM section
- * to ensure sufficient storage can be allocated.
- * Provide an implementation of the accessor method to allow the datastore
- * details to be retrieved by the SPMC.
- * The SPMC will take care of initializing the memory region.
- */
+IMPORT_SYM(uintptr_t, __PLAT_SPMC_SHMEM_DATASTORE_START__, DATASTORE_BASE);
 
-#define PLAT_SPMC_SHMEM_DATASTORE_SIZE 512 * 1024
-
-__section(".arm_el3_tzc_dram") static uint8_t
+__section(".arm_el3_tzc_dram") __unused static uint8_t
 plat_spmc_shmem_datastore[PLAT_SPMC_SHMEM_DATASTORE_SIZE];
 
 int plat_spmc_shmem_datastore_get(uint8_t **datastore, size_t *size)
 {
-	*datastore = plat_spmc_shmem_datastore;
+	*datastore = (uint8_t *)DATASTORE_BASE;
 	*size = PLAT_SPMC_SHMEM_DATASTORE_SIZE;
 	return 0;
 }
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 4b69d66..bf567a4 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -99,6 +99,17 @@
 					FVP_DTB_DRAM_MAP_SIZE,		\
 					MT_MEMORY | MT_RO | MT_NS)
 
+/*
+ * On the FVP platform when using the EL3 SPMC implementation allocate the
+ * datastore for tracking shared memory descriptors in the TZC DRAM section
+ * to ensure sufficient storage can be allocated.
+ * Provide an implementation of the accessor method to allow the datastore
+ * details to be retrieved by the SPMC.
+ * The SPMC will take care of initializing the memory region.
+ */
+
+#define PLAT_SPMC_SHMEM_DATASTORE_SIZE 512 * 1024
+
 #if SPMC_AT_EL3
 /*
  * Number of Secure Partitions supported.
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 35086e4..569ac3f 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -204,12 +204,14 @@
 					lib/cpus/aarch64/cortex_a78_ae.S	\
 					lib/cpus/aarch64/cortex_a78c.S		\
 					lib/cpus/aarch64/cortex_a710.S		\
+					lib/cpus/aarch64/cortex_a715.S		\
 					lib/cpus/aarch64/neoverse_n_common.S	\
 					lib/cpus/aarch64/neoverse_n1.S		\
 					lib/cpus/aarch64/neoverse_n2.S		\
 					lib/cpus/aarch64/neoverse_v1.S		\
 					lib/cpus/aarch64/neoverse_e1.S		\
 					lib/cpus/aarch64/cortex_x2.S		\
+					lib/cpus/aarch64/cortex_x4.S		\
 					lib/cpus/aarch64/cortex_gelas.S		\
 					lib/cpus/aarch64/nevis.S		\
 					lib/cpus/aarch64/travis.S
diff --git a/plat/arm/css/sgi/aarch64/sgi_helper.S b/plat/arm/board/neoverse_rd/common/arch/aarch64/nrd_helper.S
similarity index 84%
rename from plat/arm/css/sgi/aarch64/sgi_helper.S
rename to plat/arm/board/neoverse_rd/common/arch/aarch64/nrd_helper.S
index ced59e8..8d9c0d7 100644
--- a/plat/arm/css/sgi/aarch64/sgi_helper.S
+++ b/plat/arm/board/neoverse_rd/common/arch/aarch64/nrd_helper.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,15 +21,15 @@
 	 *
 	 * Helper function to calculate the core position.
 	 * (ChipId * PLAT_ARM_CLUSTER_COUNT *
-	 *  CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
-	 * (ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
-	 * (CPUId * CSS_SGI_MAX_PE_PER_CPU) +
+	 *  NRD_MAX_CPUS_PER_CLUSTER * NRD_MAX_PE_PER_CPU) +
+	 * (ClusterId * NRD_MAX_CPUS_PER_CLUSTER * NRD_MAX_PE_PER_CPU) +
+	 * (CPUId * NRD_MAX_PE_PER_CPU) +
 	 * ThreadId
 	 *
 	 * which can be simplified as:
 	 *
 	 * ((((ChipId * PLAT_ARM_CLUSTER_COUNT) + ClusterId) *
-	 *   CSS_SGI_MAX_CPUS_PER_CLUSTER) + CPUId) * CSS_SGI_MAX_PE_PER_CPU +
+	 *   NRD_MAX_CPUS_PER_CLUSTER) + CPUId) * NRD_MAX_PE_PER_CPU +
 	 * ThreadId
 	 * ------------------------------------------------------
 	 */
@@ -38,7 +38,7 @@
 	mov	x4, x0
 
 	/*
-	 * The MT bit in MPIDR is always set for SGI platforms
+	 * The MT bit in MPIDR is always set for Neoverse RD platforms
 	 * and the affinity level 0 corresponds to thread affinity level.
 	 */
 
@@ -51,9 +51,9 @@
 	/* Compute linear position */
 	mov     x4, #PLAT_ARM_CLUSTER_COUNT
 	madd    x2, x3, x4, x2
-	mov     x4, #CSS_SGI_MAX_CPUS_PER_CLUSTER
+	mov     x4, #NRD_MAX_CPUS_PER_CLUSTER
 	madd    x1, x2, x4, x1
-	mov     x4, #CSS_SGI_MAX_PE_PER_CPU
+	mov     x4, #NRD_MAX_PE_PER_CPU
 	madd    x0, x1, x4, x0
 	ret
 endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/board/neoverse_rd/common/include/nrd_base_platform_def.h
similarity index 76%
rename from plat/arm/css/sgi/include/sgi_base_platform_def.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_base_platform_def.h
index 2126a86..89fa924 100644
--- a/plat/arm/css/sgi/include/sgi_base_platform_def.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_base_platform_def.h
@@ -4,8 +4,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_BASE_PLATFORM_DEF_H
-#define SGI_BASE_PLATFORM_DEF_H
+#ifndef NRD_BASE_PLATFORM_DEF_H
+#define NRD_BASE_PLATFORM_DEF_H
 
 #include <lib/utils_def.h>
 #include <lib/xlat_tables/xlat_tables_defs.h>
@@ -14,16 +14,16 @@
 #include <plat/arm/css/common/css_def.h>
 #include <plat/common/common_def.h>
 
-#define PLATFORM_CORE_COUNT		(CSS_SGI_CHIP_COUNT *		\
+#define PLATFORM_CORE_COUNT		(NRD_CHIP_COUNT *		\
 					PLAT_ARM_CLUSTER_COUNT *	\
-					CSS_SGI_MAX_CPUS_PER_CLUSTER *	\
-					CSS_SGI_MAX_PE_PER_CPU)
+					NRD_MAX_CPUS_PER_CLUSTER *	\
+					NRD_MAX_PE_PER_CPU)
 
 #define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00080000	/* 512 KB */
 
 /* Remote chip address offset */
-#define CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n)	\
-		((ULL(1) << CSS_SGI_ADDR_BITS_PER_CHIP) * (n))
+#define NRD_REMOTE_CHIP_MEM_OFFSET(n)	\
+		((ULL(1) << NRD_ADDR_BITS_PER_CHIP) * (n))
 
 /*
  * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
@@ -34,19 +34,19 @@
  */
 #if defined(IMAGE_BL31)
 # if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
-#  define PLAT_ARM_MMAP_ENTRIES		(10  + ((CSS_SGI_CHIP_COUNT - 1) * 3))
-#  define MAX_XLAT_TABLES		(8  + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+#  define PLAT_ARM_MMAP_ENTRIES		(10  + ((NRD_CHIP_COUNT - 1) * 3))
+#  define MAX_XLAT_TABLES		(8  + ((NRD_CHIP_COUNT - 1) * 3))
 #  define PLAT_SP_IMAGE_MMAP_REGIONS	12
 #  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	14
 # else
-#  define PLAT_ARM_MMAP_ENTRIES		(5 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
-#  define MAX_XLAT_TABLES		(6 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+#  define PLAT_ARM_MMAP_ENTRIES		(5 + ((NRD_CHIP_COUNT - 1) * 3))
+#  define MAX_XLAT_TABLES		(6 + ((NRD_CHIP_COUNT - 1) * 3))
 # endif
 #elif defined(IMAGE_BL32)
 # define PLAT_ARM_MMAP_ENTRIES		8
 # define MAX_XLAT_TABLES		5
 #elif defined(IMAGE_BL2)
-# define PLAT_ARM_MMAP_ENTRIES		(11 + (CSS_SGI_CHIP_COUNT - 1))
+# define PLAT_ARM_MMAP_ENTRIES		(11 + (NRD_CHIP_COUNT - 1))
 
 /*
  * MAX_XLAT_TABLES entries need to be doubled because when the address width
@@ -55,7 +55,7 @@
  * > 40 bits
  *
  */
-# define MAX_XLAT_TABLES		(7  + ((CSS_SGI_CHIP_COUNT - 1) * 2))
+# define MAX_XLAT_TABLES		(7  + ((NRD_CHIP_COUNT - 1) * 2))
 #elif !USE_ROMLIB
 # define PLAT_ARM_MMAP_ENTRIES		11
 # define MAX_XLAT_TABLES		7
@@ -90,23 +90,23 @@
  *
  */
 #if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE		(0x20000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+# define PLAT_ARM_MAX_BL2_SIZE		(0x20000 + ((NRD_CHIP_COUNT - 1) * \
 							0x2000))
 #else
-# define PLAT_ARM_MAX_BL2_SIZE		(0x14000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+# define PLAT_ARM_MAX_BL2_SIZE		(0x14000 + ((NRD_CHIP_COUNT - 1) * \
 							0x2000))
 #endif
 
 /*
  * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
  * calculated using the current BL31 PROGBITS debug size plus the sizes of BL2
- * and BL1-RW. CSS_SGI_BL31_SIZE - is tuned with respect to the actual BL31
+ * and BL1-RW. NRD_BL31_SIZE - is tuned with respect to the actual BL31
  * PROGBITS size which is around 64-68KB at the time this change is being made.
  * A buffer of ~35KB is added to account for future expansion of the image,
  * making it a total of 100KB.
  */
-#define CSS_SGI_BL31_SIZE		(116 * 1024)	/* 116 KB */
-#define PLAT_ARM_MAX_BL31_SIZE		(CSS_SGI_BL31_SIZE +		\
+#define NRD_BL31_SIZE			(116 * 1024)	/* 116 KB */
+#define PLAT_ARM_MAX_BL31_SIZE		(NRD_BL31_SIZE +		\
 						PLAT_ARM_MAX_BL2_SIZE +	\
 						PLAT_ARM_MAX_BL1_RW_SIZE)
 
@@ -167,32 +167,32 @@
 #define PLAT_ARM_G1S_IRQ_PROPS(grp)	CSS_G1S_IRQ_PROPS(grp)
 #define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
 
-#define CSS_SGI_DEVICE_BASE	(0x20000000)
-#define CSS_SGI_DEVICE_SIZE	(0x20000000)
-#define CSS_SGI_MAP_DEVICE	MAP_REGION_FLAT(		\
-					CSS_SGI_DEVICE_BASE,	\
-					CSS_SGI_DEVICE_SIZE,	\
+#define NRD_DEVICE_BASE	(0x20000000)
+#define NRD_DEVICE_SIZE	(0x20000000)
+#define NRD_MAP_DEVICE	MAP_REGION_FLAT(		\
+					NRD_DEVICE_BASE,	\
+					NRD_DEVICE_SIZE,	\
 					MT_DEVICE | MT_RW | MT_SECURE)
 
 #define ARM_MAP_SHARED_RAM_REMOTE_CHIP(n)					\
 			MAP_REGION_FLAT(					\
-				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				NRD_REMOTE_CHIP_MEM_OFFSET(n) +		\
 				ARM_SHARED_RAM_BASE,				\
 				ARM_SHARED_RAM_SIZE,				\
 				MT_NON_CACHEABLE | MT_RW | MT_SECURE		\
 			)
 
-#define CSS_SGI_MAP_DEVICE_REMOTE_CHIP(n)					\
+#define NRD_MAP_DEVICE_REMOTE_CHIP(n)					\
 			MAP_REGION_FLAT(					\
-				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
-				CSS_SGI_DEVICE_BASE,				\
-				CSS_SGI_DEVICE_SIZE,				\
+				NRD_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				NRD_DEVICE_BASE,				\
+				NRD_DEVICE_SIZE,				\
 				MT_DEVICE | MT_RW | MT_SECURE			\
 			)
 
 #define SOC_CSS_MAP_DEVICE_REMOTE_CHIP(n)					\
 			MAP_REGION_FLAT(					\
-				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				NRD_REMOTE_CHIP_MEM_OFFSET(n) +		\
 				SOC_CSS_DEVICE_BASE,				\
 				SOC_CSS_DEVICE_SIZE,				\
 				MT_DEVICE | MT_RW | MT_SECURE			\
@@ -215,13 +215,13 @@
  * CPER buffer memory of 128KB is reserved and it is placed adjacent to the
  * memory shared between EL3 and S-EL0.
  */
-#define CSS_SGI_SP_CPER_BUF_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE + \
+#define NRD_SP_CPER_BUF_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE + \
 					 PLAT_SP_IMAGE_NS_BUF_SIZE)
-#define CSS_SGI_SP_CPER_BUF_SIZE	ULL(0x10000)
-#define CSS_SGI_SP_CPER_BUF_MMAP	MAP_REGION2(			       \
-						CSS_SGI_SP_CPER_BUF_BASE,      \
-						CSS_SGI_SP_CPER_BUF_BASE,      \
-						CSS_SGI_SP_CPER_BUF_SIZE,      \
+#define NRD_SP_CPER_BUF_SIZE	ULL(0x10000)
+#define NRD_SP_CPER_BUF_MMAP	MAP_REGION2(			       \
+						NRD_SP_CPER_BUF_BASE,      \
+						NRD_SP_CPER_BUF_BASE,      \
+						NRD_SP_CPER_BUF_SIZE,      \
 						MT_RW_DATA | MT_NS | MT_USER,  \
 						PAGE_SIZE)
 
@@ -231,7 +231,7 @@
  */
 #define PLAT_ARM_SP_IMAGE_STACK_BASE		(PLAT_SP_IMAGE_NS_BUF_BASE +   \
 						 PLAT_SP_IMAGE_NS_BUF_SIZE +   \
-						 CSS_SGI_SP_CPER_BUF_SIZE)
+						 NRD_SP_CPER_BUF_SIZE)
 #elif (SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP))
 /*
  * Secure partition stack follows right after the memory region that is shared
@@ -246,10 +246,10 @@
 #ifndef __ASSEMBLER__
 /* SSC_VERSION related accessors */
 /* Returns the part number of the platform */
-#define GET_SGI_PART_NUM                                       \
+#define GET_NRD_PART_NUM                                       \
 		GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION))
 /* Returns the configuration number of the platform */
-#define GET_SGI_CONFIG_NUM                                     \
+#define GET_NRD_CONFIG_NUM                                     \
 		GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION))
 #endif /* __ASSEMBLER__ */
 
@@ -269,19 +269,19 @@
 #define SBSA_SECURE_WDOG_TIMEOUT	UL(100)
 
 /* Number of SCMI channels on the platform */
-#define PLAT_ARM_SCMI_CHANNEL_COUNT	CSS_SGI_CHIP_COUNT
+#define PLAT_ARM_SCMI_CHANNEL_COUNT	NRD_CHIP_COUNT
 
 /*
- * Mapping definition of the TrustZone Controller for ARM SGI/RD platforms
+ * Mapping definition of the TrustZone Controller for Arm Neoverse RD platforms
  * where both the DRAM regions are marked for non-secure access. This applies
  * to multi-chip platforms.
  */
-#define SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(n)				\
-	{CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_BASE,		\
-		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_END,	\
+#define NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(n)				\
+	{NRD_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_BASE,		\
+		NRD_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_END,	\
 		ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},	\
-	{CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_BASE,		\
-		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_END,	\
+	{NRD_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_BASE,		\
+		NRD_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_END,	\
 		ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}
 
 #if SPM_MM
@@ -303,4 +303,4 @@
 /* SDS ID for unusable CPU MPID list structure */
 #define SDS_ISOLATED_CPU_LIST_ID		U(128)
 
-#endif /* SGI_BASE_PLATFORM_DEF_H */
+#endif /* NRD_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h b/plat/arm/board/neoverse_rd/common/include/nrd_dmc620_tzc_regions.h
similarity index 72%
rename from plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_dmc620_tzc_regions.h
index e939163..c63d750 100644
--- a/plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_dmc620_tzc_regions.h
@@ -1,16 +1,16 @@
 /*
- * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_DMC620_TZC_REGIONS_H
-#define SGI_DMC620_TZC_REGIONS_H
+#ifndef NRD_DMC620_TZC_REGIONS_H
+#define NRD_DMC620_TZC_REGIONS_H
 
 #include <drivers/arm/tzc_dmc620.h>
 
 #if SPM_MM
-#define CSS_SGI_DMC620_TZC_REGIONS_DEF				\
+#define NRD_DMC620_TZC_REGIONS_DEF				\
 	{							\
 		.region_base = ARM_AP_TZC_DRAM1_BASE,		\
 		.region_top = PLAT_SP_IMAGE_NS_BUF_BASE - 1,	\
@@ -25,7 +25,7 @@
 		.sec_attr = TZC_DMC620_REGION_S_RDWR		\
 	}
 #else
-#define CSS_SGI_DMC620_TZC_REGIONS_DEF				\
+#define NRD_DMC620_TZC_REGIONS_DEF				\
 	{							\
 		.region_base = ARM_AP_TZC_DRAM1_BASE,		\
 		.region_top = ARM_AP_TZC_DRAM1_END,		\
@@ -33,4 +33,4 @@
 	}
 #endif /* SPM_MM */
 
-#endif /* SGI_DMC620_TZC_REGIONS_H */
+#endif /* NRD_DMC620_TZC_REGIONS_H */
diff --git a/plat/arm/board/neoverse_rd/common/include/nrd_plat.h b/plat/arm/board/neoverse_rd/common/include/nrd_plat.h
new file mode 100644
index 0000000..775f233
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_plat.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_PLAT_H
+#define NRD_PLAT_H
+
+/* BL31 platform setup common to all Neoverse RD platforms */
+void nrd_bl31_common_platform_setup(void);
+
+#endif /* NRD_PLAT_H */
diff --git a/plat/arm/css/sgi/include/sgi_ras.h b/plat/arm/board/neoverse_rd/common/include/nrd_ras.h
similarity index 66%
rename from plat/arm/css/sgi/include/sgi_ras.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_ras.h
index d311807..768689c 100644
--- a/plat/arm/css/sgi/include/sgi_ras.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_ras.h
@@ -1,22 +1,22 @@
 /*
- * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_RAS_H
-#define SGI_RAS_H
+#ifndef NRD_RAS_H
+#define NRD_RAS_H
 
 #include <lib/extensions/ras.h>
 #include <plat/common/platform.h>
 
 /*
  * Interrupt type supported.
- * - SGI_RAS_INTR_TYPE_SPI: Denotes a SPI interrupt
- * - SGI_RAS_INTR_TYPE_PPI: Denotes a PPI interrupt
+ * - NRD_RAS_INTR_TYPE_SPI: Denotes a SPI interrupt
+ * - NRD_RAS_INTR_TYPE_PPI: Denotes a PPI interrupt
  */
-#define SGI_RAS_INTR_TYPE_SPI 0
-#define SGI_RAS_INTR_TYPE_PPI 1
+#define NRD_RAS_INTR_TYPE_SPI 0
+#define NRD_RAS_INTR_TYPE_PPI 1
 
 /*
  * MM Communicate information structure. Required to generate MM Communicate
@@ -29,15 +29,15 @@
 } mm_communicate_header_t;
 
 /* RAS error info data structure. */
-struct sgi_ras_ev_map {
+struct nrd_ras_ev_map {
 	int sdei_ev_num;	/* SDEI Event number */
 	int intr;		/* Physical intr number */
 	int intr_type;          /* Interrupt Type (SPI or PPI)*/
 };
 
 /* RAS config data structure. Must be defined by each platform. */
-struct plat_sgi_ras_config {
-	struct sgi_ras_ev_map *ev_map;
+struct plat_nrd_ras_config {
+	struct nrd_ras_ev_map *ev_map;
 	int ev_map_size;
 };
 
@@ -45,7 +45,7 @@
  * Find event map for a given interrupt number. On success, returns pointer
  * to the event map. On error, returns NULL.
  */
-struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num);
+struct nrd_ras_ev_map *nrd_find_ras_event_map_by_intr(uint32_t intr_num);
 
 /*
  * Initialization function for the framework.
@@ -53,16 +53,16 @@
  * Registers RAS config provided by the platform and then configures and
  * enables interrupt for each registered error. On success, return 0.
  */
-int sgi_ras_platform_setup(struct plat_sgi_ras_config *config);
+int nrd_ras_platform_setup(struct plat_nrd_ras_config *config);
 
 /* Base element RAM RAS interrupt handler function. */
-int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
+int nrd_ras_sram_intr_handler(const struct err_record_info *err_rec,
 				int probe_data,
 				const struct err_handler_data *const data);
 
 /* CPU RAS interrupt handler */
-int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec,
+int nrd_ras_cpu_intr_handler(const struct err_record_info *err_rec,
 				int probe_data,
 				const struct err_handler_data *const data);
 
-#endif /* SGI_RAS_H */
+#endif /* NRD_RAS_H */
diff --git a/plat/arm/board/neoverse_rd/common/include/nrd_sdei.h b/plat/arm/board/neoverse_rd/common/include/nrd_sdei.h
new file mode 100644
index 0000000..f1b6015
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_sdei.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SDEI_H
+#define NRD_SDEI_H
+
+#if SDEI_SUPPORT
+
+/* ARM SDEI dynamic shared event numbers */
+#define NRD_SDEI_DS_EVENT_0		U(804)
+#define NRD_SDEI_DS_EVENT_1		U(805)
+
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS					      \
+		SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI),			      \
+		SDEI_EXPLICIT_EVENT(NRD_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \
+		SDEI_EXPLICIT_EVENT(NRD_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL),
+
+#define PLAT_ARM_SHARED_SDEI_EVENTS
+
+#endif /* SDEI_SUPPORT */
+
+#endif /* NRD_SDEI_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_css_def.h b/plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def.h
similarity index 86%
rename from plat/arm/css/sgi/include/sgi_soc_css_def.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def.h
index f78b45a..7c1f5ae 100644
--- a/plat/arm/css/sgi/include/sgi_soc_css_def.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_SOC_CSS_DEF_H
-#define SGI_SOC_CSS_DEF_H
+#ifndef NRD_SOC_CSS_DEF_H
+#define NRD_SOC_CSS_DEF_H
 
 #include <lib/utils_def.h>
 #include <plat/arm/board/common/v2m_def.h>
@@ -44,4 +44,4 @@
 #define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
 #define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
-#endif /* SGI_SOC_CSS_DEF_H */
+#endif /* NRD_SOC_CSS_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h b/plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def_v2.h
similarity index 95%
rename from plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def_v2.h
index d659ae5..33f9b4b 100644
--- a/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_soc_css_def_v2.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_SOC_CSS_DEF_V2_H
-#define SGI_SOC_CSS_DEF_V2_H
+#ifndef NRD_SOC_CSS_DEF_V2_H
+#define NRD_SOC_CSS_DEF_V2_H
 
 #include <lib/utils_def.h>
 #include <plat/common/common_def.h>
@@ -92,7 +92,7 @@
 
 #define SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(n)					\
 		MAP_REGION_FLAT(						\
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + SOC_MEMCNTRL_BASE,	\
+			NRD_REMOTE_CHIP_MEM_OFFSET(n) + SOC_MEMCNTRL_BASE,	\
 			SOC_MEMCNTRL_SIZE,					\
 			MT_DEVICE | MT_RW | MT_SECURE)
 
@@ -156,7 +156,7 @@
 						V2M_FLASH0_SIZE,	\
 						MT_RO_DATA | MT_SECURE)
 
-#define SGI_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+#define NRD_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
 						V2M_FLASH0_SIZE,	\
 						MT_DEVICE | MT_RO | MT_SECURE)
 
@@ -204,4 +204,4 @@
 #define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
 #define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
-#endif /* SGI_SOC_CSS_DEF_V2_H */
+#endif /* NRD_SOC_CSS_DEF_V2_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_platform_def.h b/plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def.h
similarity index 78%
rename from plat/arm/css/sgi/include/sgi_soc_platform_def.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def.h
index 3b8d9c6..0024e49 100644
--- a/plat/arm/css/sgi/include/sgi_soc_platform_def.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def.h
@@ -1,16 +1,17 @@
 /*
- * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_SOC_PLATFORM_DEF_H
-#define SGI_SOC_PLATFORM_DEF_H
+#ifndef NRD_SOC_PLATFORM_DEF_H
+#define NRD_SOC_PLATFORM_DEF_H
 
 #include <plat/arm/board/common/v2m_def.h>
 #include <plat/arm/soc/common/soc_css_def.h>
-#include <sgi_base_platform_def.h>
-#include <sgi_soc_css_def.h>
+
+#include <nrd_base_platform_def.h>
+#include <nrd_soc_css_def.h>
 
 /* Map the System registers to access from S-EL0 */
 #define CSS_SYSTEMREG_DEVICE_BASE	(0x1C010000)
@@ -30,4 +31,4 @@
 						(MT_DEVICE | MT_RW |	    \
 						 MT_SECURE | MT_USER))
 
-#endif /* SGI_SOC_PLATFORM_DEF_H */
+#endif /* NRD_SOC_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h b/plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def_v2.h
similarity index 76%
rename from plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def_v2.h
index 20dd682..2e6f354 100644
--- a/plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_soc_platform_def_v2.h
@@ -1,14 +1,14 @@
 /*
- * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_SOC_PLATFORM_DEF_V2_H
-#define SGI_SOC_PLATFORM_DEF_V2_H
+#ifndef NRD_SOC_PLATFORM_DEF_V2_H
+#define NRD_SOC_PLATFORM_DEF_V2_H
 
-#include <sgi_base_platform_def.h>
-#include <sgi_soc_css_def_v2.h>
+#include <nrd_base_platform_def.h>
+#include <nrd_soc_css_def_v2.h>
 
 /* Map the System registers to access from S-EL0 */
 #define CSS_SYSTEMREG_DEVICE_BASE	(0x0C010000)
@@ -28,4 +28,4 @@
 						(MT_DEVICE | MT_RW |	    \
 						 MT_SECURE | MT_USER))
 
-#endif /* SGI_SOC_PLATFORM_DEF_V2_H */
+#endif /* NRD_SOC_PLATFORM_DEF_V2_H */
diff --git a/plat/arm/css/sgi/include/sgi_variant.h b/plat/arm/board/neoverse_rd/common/include/nrd_variant.h
similarity index 69%
rename from plat/arm/css/sgi/include/sgi_variant.h
rename to plat/arm/board/neoverse_rd/common/include/nrd_variant.h
index 8f9529a..94f80c3 100644
--- a/plat/arm/css/sgi/include/sgi_variant.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd_variant.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef SGI_VARIANT_H
-#define SGI_VARIANT_H
+#ifndef NRD_VARIANT_H
+#define NRD_VARIANT_H
 
 /* SSC_VERSION values for SGI575 */
 #define SGI575_SSC_VER_PART_NUM			0x0783
@@ -28,23 +28,23 @@
 #define RD_V2_SID_VER_PART_NUM			0x07F2
 #define RD_V2_CONFIG_ID				0x1
 
-/* Structure containing SGI platform variant information */
-typedef struct sgi_platform_info {
+/* Structure containing Neoverse RD platform variant information */
+typedef struct nrd_platform_info {
 	unsigned int platform_id;	/* Part Number of the platform */
 	unsigned int config_id;		/* Config Id of the platform */
 	unsigned int chip_id;		/* Chip Id or Node number */
 	unsigned int multi_chip_mode;	/* Multi-chip mode availability */
-} sgi_platform_info_t;
+} nrd_platform_info_t;
 
-extern sgi_platform_info_t sgi_plat_info;
+extern nrd_platform_info_t nrd_plat_info;
 
 /* returns the part number of the platform*/
-unsigned int plat_arm_sgi_get_platform_id(void);
+unsigned int plat_arm_nrd_get_platform_id(void);
 
 /* returns the configuration id of the platform */
-unsigned int plat_arm_sgi_get_config_id(void);
+unsigned int plat_arm_nrd_get_config_id(void);
 
 /* returns true if operating in multi-chip configuration */
-unsigned int plat_arm_sgi_get_multi_chip_mode(void);
+unsigned int plat_arm_nrd_get_multi_chip_mode(void);
 
-#endif /* SGI_VARIANT_H */
+#endif /* NRD_VARIANT_H */
diff --git a/plat/arm/css/sgi/include/plat_macros.S b/plat/arm/board/neoverse_rd/common/include/plat_macros.S
similarity index 85%
rename from plat/arm/css/sgi/include/plat_macros.S
rename to plat/arm/board/neoverse_rd/common/include/plat_macros.S
index 521bcc3..df7cfb6 100644
--- a/plat/arm/css/sgi/include/plat_macros.S
+++ b/plat/arm/board/neoverse_rd/common/include/plat_macros.S
@@ -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
  */
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/board/neoverse_rd/common/nrd-common.mk
similarity index 73%
rename from plat/arm/css/sgi/sgi-common.mk
rename to plat/arm/board/neoverse_rd/common/nrd-common.mk
index efa3cc6..96e6f01 100644
--- a/plat/arm/css/sgi/sgi-common.mk
+++ b/plat/arm/board/neoverse_rd/common/nrd-common.mk
@@ -6,7 +6,7 @@
 
 CSS_USE_SCMI_SDS_DRIVER		:=	1
 
-CSS_ENT_BASE			:=	plat/arm/css/sgi
+NRD_COMMON_BASE			:=	plat/arm/board/neoverse_rd/common
 
 ENABLE_FEAT_RAS			:=	1
 
@@ -16,18 +16,18 @@
 
 HANDLE_EA_EL3_FIRST_NS		:=	0
 
-CSS_SGI_CHIP_COUNT		:=	1
+NRD_CHIP_COUNT		:=	1
 
-CSS_SGI_PLATFORM_VARIANT	:=	0
+NRD_PLATFORM_VARIANT	:=	0
 
 # Do not enable SVE
 ENABLE_SVE_FOR_NS		:=	0
 
 CTX_INCLUDE_FPREGS		:=	1
 
-INTERCONNECT_SOURCES	:=	${CSS_ENT_BASE}/sgi_interconnect.c
+INTERCONNECT_SOURCES	:=	${NRD_COMMON_BASE}/nrd_interconnect.c
 
-PLAT_INCLUDES		+=	-I${CSS_ENT_BASE}/include
+PLAT_INCLUDES		+=	-I${NRD_COMMON_BASE}/include
 
 # GIC-600 configuration
 GICV3_SUPPORT_GIC600	:=	1
@@ -39,18 +39,18 @@
 				plat/common/plat_gicv3.c	\
 				plat/arm/common/arm_gicv3.c
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/aarch64/sgi_helper.S
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/arch/aarch64/nrd_helper.S
 
 BL1_SOURCES		+=	${INTERCONNECT_SOURCES}			\
 				drivers/arm/sbsa/sbsa.c
 
-BL2_SOURCES		+=	${CSS_ENT_BASE}/sgi_image_load.c	\
+BL2_SOURCES		+=	${NRD_COMMON_BASE}/nrd_image_load.c	\
 				drivers/arm/css/sds/sds.c
 
 BL31_SOURCES		+=	${INTERCONNECT_SOURCES}			\
 				${ENT_GIC_SOURCES}			\
-				${CSS_ENT_BASE}/sgi_bl31_setup.c	\
-				${CSS_ENT_BASE}/sgi_topology.c          \
+				${NRD_COMMON_BASE}/nrd_bl31_setup.c	\
+				${NRD_COMMON_BASE}/nrd_topology.c	\
 				drivers/delay_timer/generic_delay_timer.c
 
 ifneq (${RESET_TO_BL31},0)
@@ -58,11 +58,9 @@
   Please set RESET_TO_BL31 to 0.")
 endif
 
-$(eval $(call add_define,SGI_PLAT))
-
-$(eval $(call add_define,CSS_SGI_CHIP_COUNT))
+$(eval $(call add_define,NRD_CHIP_COUNT))
 
-$(eval $(call add_define,CSS_SGI_PLATFORM_VARIANT))
+$(eval $(call add_define,NRD_PLATFORM_VARIANT))
 
 override CSS_LOAD_SCP_IMAGES	:=	0
 override NEED_BL2U		:=	no
diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
similarity index 67%
rename from plat/arm/css/sgi/sgi_bl31_setup.c
rename to plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
index ac1ea48..a22c799 100644
--- a/plat/arm/css/sgi/sgi_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
@@ -14,15 +14,13 @@
 #include <drivers/arm/css/scmi.h>
 #include <drivers/generic_delay_timer.h>
 #include <plat/arm/common/plat_arm.h>
-
-#include <plat/common/platform.h>
-
 #include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
 
-#include <sgi_ras.h>
-#include <sgi_variant.h>
+#include <nrd_ras.h>
+#include <nrd_variant.h>
 
-sgi_platform_info_t sgi_plat_info;
+nrd_platform_info_t nrd_plat_info;
 
 static scmi_channel_plat_info_t sgi575_scmi_plat_info = {
 		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
@@ -40,34 +38,34 @@
 		.db_modify_mask = 0x1,
 		.ring_doorbell = &mhuv2_ring_doorbell,
 	},
-	#if (CSS_SGI_CHIP_COUNT > 1)
+	#if (NRD_CHIP_COUNT > 1)
 	{
 		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+			NRD_REMOTE_CHIP_MEM_OFFSET(1),
 		.db_reg_addr = PLAT_CSS_MHU_BASE
-			+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1) + SENDER_REG_SET(0),
+			+ NRD_REMOTE_CHIP_MEM_OFFSET(1) + SENDER_REG_SET(0),
 		.db_preserve_mask = 0xfffffffe,
 		.db_modify_mask = 0x1,
 		.ring_doorbell = &mhuv2_ring_doorbell,
 	},
 	#endif
-	#if (CSS_SGI_CHIP_COUNT > 2)
+	#if (NRD_CHIP_COUNT > 2)
 	{
 		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+			NRD_REMOTE_CHIP_MEM_OFFSET(2),
 		.db_reg_addr = PLAT_CSS_MHU_BASE +
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2) + SENDER_REG_SET(0),
+			NRD_REMOTE_CHIP_MEM_OFFSET(2) + SENDER_REG_SET(0),
 		.db_preserve_mask = 0xfffffffe,
 		.db_modify_mask = 0x1,
 		.ring_doorbell = &mhuv2_ring_doorbell,
 	},
 	#endif
-	#if (CSS_SGI_CHIP_COUNT > 3)
+	#if (NRD_CHIP_COUNT > 3)
 	{
 		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+			NRD_REMOTE_CHIP_MEM_OFFSET(3),
 		.db_reg_addr = PLAT_CSS_MHU_BASE +
-			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3) + SENDER_REG_SET(0),
+			NRD_REMOTE_CHIP_MEM_OFFSET(3) + SENDER_REG_SET(0),
 		.db_preserve_mask = 0xfffffffe,
 		.db_modify_mask = 0x1,
 		.ring_doorbell = &mhuv2_ring_doorbell,
@@ -77,33 +75,34 @@
 
 scmi_channel_plat_info_t *plat_css_get_scmi_info(unsigned int channel_id)
 {
-	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM ||
-		sgi_plat_info.platform_id == RD_V1_SID_VER_PART_NUM ||
-		sgi_plat_info.platform_id == RD_N2_SID_VER_PART_NUM ||
-		sgi_plat_info.platform_id == RD_V2_SID_VER_PART_NUM ||
-		sgi_plat_info.platform_id == RD_N2_CFG1_SID_VER_PART_NUM ||
-		sgi_plat_info.platform_id == RD_N2_CFG3_SID_VER_PART_NUM) {
-		if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info))
+	if (nrd_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM ||
+		nrd_plat_info.platform_id == RD_V1_SID_VER_PART_NUM ||
+		nrd_plat_info.platform_id == RD_N2_SID_VER_PART_NUM ||
+		nrd_plat_info.platform_id == RD_V2_SID_VER_PART_NUM ||
+		nrd_plat_info.platform_id == RD_N2_CFG1_SID_VER_PART_NUM ||
+		nrd_plat_info.platform_id == RD_N2_CFG3_SID_VER_PART_NUM) {
+		if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info)) {
 			panic();
+		}
 		return &plat_rd_scmi_info[channel_id];
-	}
-	else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM)
+	} else if (nrd_plat_info.platform_id == SGI575_SSC_VER_PART_NUM) {
 		return &sgi575_scmi_plat_info;
-	else
+	} else {
 		panic();
+	}
 }
 
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 				u_register_t arg2, u_register_t arg3)
 {
-	sgi_plat_info.platform_id = plat_arm_sgi_get_platform_id();
-	sgi_plat_info.config_id = plat_arm_sgi_get_config_id();
-	sgi_plat_info.multi_chip_mode = plat_arm_sgi_get_multi_chip_mode();
+	nrd_plat_info.platform_id = plat_arm_nrd_get_platform_id();
+	nrd_plat_info.config_id = plat_arm_nrd_get_config_id();
+	nrd_plat_info.multi_chip_mode = plat_arm_nrd_get_multi_chip_mode();
 
 	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
 }
 
-void sgi_bl31_common_platform_setup(void)
+void nrd_bl31_common_platform_setup(void)
 {
 	generic_delay_timer_init();
 
@@ -125,8 +124,8 @@
 	 * For RD-E1-Edge, only CPU power ON/OFF, PSCI platform callbacks are
 	 * supported.
 	 */
-	if (((sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) &&
-	    (sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID))) {
+	if (((nrd_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) &&
+	    (nrd_plat_info.config_id == RD_E1_EDGE_CONFIG_ID))) {
 		ops->cpu_standby = NULL;
 		ops->system_off = NULL;
 		ops->system_reset = NULL;
diff --git a/plat/arm/css/sgi/sgi_image_load.c b/plat/arm/board/neoverse_rd/common/nrd_image_load.c
similarity index 90%
rename from plat/arm/css/sgi/sgi_image_load.c
rename to plat/arm/board/neoverse_rd/common/nrd_image_load.c
index 0a9bba9..39de0ab 100644
--- a/plat/arm/css/sgi/sgi_image_load.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_image_load.c
@@ -12,10 +12,10 @@
 #include <drivers/arm/css/sds.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
-
 #include <platform_def.h>
-#include <sgi_base_platform_def.h>
-#include <sgi_variant.h>
+
+#include <nrd_base_platform_def.h>
+#include <nrd_variant.h>
 
 /*
  * Information about the isolated CPUs obtained from SDS.
@@ -26,7 +26,7 @@
 };
 
 /* Function to read isolated CPU MPID list from SDS. */
-void plat_arm_sgi_get_isolated_cpu_list(struct isolated_cpu_mpid_list *list)
+void plat_arm_nrd_get_isolated_cpu_list(struct isolated_cpu_mpid_list *list)
 {
 	int ret;
 
@@ -75,7 +75,7 @@
  *    isolated-cpu-list = <0>
  * }
  ******************************************************************************/
-static int plat_sgi_append_config_node(void)
+static int plat_nrd_append_config_node(void)
 {
 	bl_mem_params_node_t *mem_params;
 	void *fdt;
@@ -103,28 +103,28 @@
 		return -1;
 	}
 
-	platid = plat_arm_sgi_get_platform_id();
+	platid = plat_arm_nrd_get_platform_id();
 	err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid);
 	if (err < 0) {
 		ERROR("Failed to set platform-id\n");
 		return -1;
 	}
 
-	platcfg = plat_arm_sgi_get_config_id();
+	platcfg = plat_arm_nrd_get_config_id();
 	err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg);
 	if (err < 0) {
 		ERROR("Failed to set config-id\n");
 		return -1;
 	}
 
-	platcfg = plat_arm_sgi_get_multi_chip_mode();
+	platcfg = plat_arm_nrd_get_multi_chip_mode();
 	err = fdt_setprop_u32(fdt, nodeoffset, "multi-chip-mode", platcfg);
 	if (err < 0) {
 		ERROR("Failed to set multi-chip-mode\n");
 		return -1;
 	}
 
-	plat_arm_sgi_get_isolated_cpu_list(&cpu_mpid_list);
+	plat_arm_nrd_get_isolated_cpu_list(&cpu_mpid_list);
 	if (cpu_mpid_list.num_entries > 0) {
 		err = fdt_setprop(fdt, nodeoffset, "isolated-cpu-list",
 				&cpu_mpid_list,
@@ -148,7 +148,7 @@
 {
 	int ret;
 
-	ret = plat_sgi_append_config_node();
+	ret = plat_nrd_append_config_node();
 	if (ret != 0)
 		panic();
 
diff --git a/plat/arm/css/sgi/sgi_interconnect.c b/plat/arm/board/neoverse_rd/common/nrd_interconnect.c
similarity index 94%
rename from plat/arm/css/sgi/sgi_interconnect.c
rename to plat/arm/board/neoverse_rd/common/nrd_interconnect.c
index e9cd812..4f9cc85 100644
--- a/plat/arm/css/sgi/sgi_interconnect.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_interconnect.c
@@ -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
  */
diff --git a/plat/arm/css/sgi/sgi_plat.c b/plat/arm/board/neoverse_rd/common/nrd_plat.c
similarity index 88%
rename from plat/arm/css/sgi/sgi_plat.c
rename to plat/arm/board/neoverse_rd/common/nrd_plat.c
index fe64d34..0c59271 100644
--- a/plat/arm/css/sgi/sgi_plat.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_plat.c
@@ -16,13 +16,14 @@
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
 #include <drivers/arm/sbsa.h>
-#include <sgi_base_platform_def.h>
+
+#include <nrd_base_platform_def.h>
 
 #if SPM_MM
 #include <services/spm_mm_partition.h>
 #endif
 
-#define SGI_MAP_FLASH0_RO	MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+#define NRD_MAP_FLASH0_RO	MAP_REGION_FLAT(V2M_FLASH0_BASE,\
 						V2M_FLASH0_SIZE,	\
 						MT_DEVICE | MT_RO | MT_SECURE)
 /*
@@ -35,8 +36,8 @@
 #if IMAGE_BL1
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
-	SGI_MAP_FLASH0_RO,
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_FLASH0_RO,
+	NRD_MAP_DEVICE,
 	SOC_CSS_MAP_DEVICE,
 	{0}
 };
@@ -44,21 +45,21 @@
 #if IMAGE_BL2
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
-	SGI_MAP_FLASH0_RO,
+	NRD_MAP_FLASH0_RO,
 #ifdef PLAT_ARM_MEM_PROT_ADDR
 	ARM_V2M_MAP_MEM_PROTECT,
 #endif
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_DEVICE,
 	SOC_CSS_MAP_DEVICE,
 	ARM_MAP_NS_DRAM1,
-#if CSS_SGI_CHIP_COUNT > 1
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+#if NRD_CHIP_COUNT > 1
+	NRD_MAP_DEVICE_REMOTE_CHIP(1),
 #endif
-#if CSS_SGI_CHIP_COUNT > 2
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+#if NRD_CHIP_COUNT > 2
+	NRD_MAP_DEVICE_REMOTE_CHIP(2),
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+#if NRD_CHIP_COUNT > 3
+	NRD_MAP_DEVICE_REMOTE_CHIP(3),
 #endif
 #if ARM_BL31_IN_DRAM
 	ARM_MAP_BL31_SEC_DRAM,
@@ -76,7 +77,7 @@
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_IOFPGA,
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_DEVICE,
 #ifdef PLAT_ARM_MEM_PROT_ADDR
 	ARM_V2M_MAP_MEM_PROTECT,
 #endif
@@ -96,7 +97,7 @@
 	ARM_SP_IMAGE_MMAP,
 	ARM_SP_IMAGE_NS_BUF_MMAP,
 #if ENABLE_FEAT_RAS && FFH_SUPPORT
-	CSS_SGI_SP_CPER_BUF_MMAP,
+	NRD_SP_CPER_BUF_MMAP,
 #endif
 	ARM_SP_IMAGE_RW_MMAP,
 	ARM_SPM_BUF_EL0_MMAP,
@@ -177,13 +178,13 @@
 	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
 }
 
-static sds_region_desc_t sgi_sds_regions[] = {
+static sds_region_desc_t nrd_sds_regions[] = {
 	{ .base = PLAT_ARM_SDS_MEM_BASE },
 };
 
 sds_region_desc_t *plat_sds_get_regions(unsigned int *region_count)
 {
-	*region_count = ARRAY_SIZE(sgi_sds_regions);
+	*region_count = ARRAY_SIZE(nrd_sds_regions);
 
-	return sgi_sds_regions;
+	return nrd_sds_regions;
 }
diff --git a/plat/arm/css/sgi/sgi_plat_v2.c b/plat/arm/board/neoverse_rd/common/nrd_plat_v2.c
similarity index 92%
rename from plat/arm/css/sgi/sgi_plat_v2.c
rename to plat/arm/board/neoverse_rd/common/nrd_plat_v2.c
index d241f70..67f486e 100644
--- a/plat/arm/css/sgi/sgi_plat_v2.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_plat_v2.c
@@ -24,8 +24,8 @@
 #if IMAGE_BL1
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
-	SGI_MAP_FLASH0_RO,
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_FLASH0_RO,
+	NRD_MAP_DEVICE,
 	SOC_PLATFORM_PERIPH_MAP_DEVICE,
 	SOC_SYSTEM_PERIPH_MAP_DEVICE,
 	{0}
@@ -35,22 +35,22 @@
 #if IMAGE_BL2
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
-	SGI_MAP_FLASH0_RO,
+	NRD_MAP_FLASH0_RO,
 #ifdef PLAT_ARM_MEM_PROT_ADDR
 	ARM_V2M_MAP_MEM_PROTECT,
 #endif
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_DEVICE,
 	SOC_MEMCNTRL_MAP_DEVICE,
 	SOC_PLATFORM_PERIPH_MAP_DEVICE,
 	SOC_SYSTEM_PERIPH_MAP_DEVICE,
 	ARM_MAP_NS_DRAM1,
-#if CSS_SGI_CHIP_COUNT > 1
+#if NRD_CHIP_COUNT > 1
 	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(1),
 #endif
-#if CSS_SGI_CHIP_COUNT > 2
+#if NRD_CHIP_COUNT > 2
 	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(2),
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
+#if NRD_CHIP_COUNT > 3
 	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(3),
 #endif
 #if ARM_BL31_IN_DRAM
@@ -72,7 +72,7 @@
 #ifdef PLAT_ARM_MEM_PROT_ADDR
 	ARM_V2M_MAP_MEM_PROTECT,
 #endif
-	CSS_SGI_MAP_DEVICE,
+	NRD_MAP_DEVICE,
 	SOC_PLATFORM_PERIPH_MAP_DEVICE,
 	SOC_SYSTEM_PERIPH_MAP_DEVICE,
 #if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
@@ -90,7 +90,7 @@
 	ARM_SP_IMAGE_MMAP,
 	ARM_SP_IMAGE_NS_BUF_MMAP,
 #if ENABLE_FEAT_RAS && FFH_SUPPORT
-	CSS_SGI_SP_CPER_BUF_MMAP,
+	NRD_SP_CPER_BUF_MMAP,
 #endif
 	ARM_SP_IMAGE_RW_MMAP,
 	ARM_SPM_BUF_EL0_MMAP,
@@ -179,13 +179,13 @@
 	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
 }
 
-static sds_region_desc_t sgi_sds_regions[] = {
+static sds_region_desc_t nrd_sds_regions[] = {
 	{ .base = PLAT_ARM_SDS_MEM_BASE },
 };
 
 sds_region_desc_t *plat_sds_get_regions(unsigned int *region_count)
 {
-	*region_count = ARRAY_SIZE(sgi_sds_regions);
+	*region_count = ARRAY_SIZE(nrd_sds_regions);
 
-	return sgi_sds_regions;
+	return nrd_sds_regions;
 }
diff --git a/plat/arm/css/sgi/sgi_topology.c b/plat/arm/board/neoverse_rd/common/nrd_topology.c
similarity index 78%
rename from plat/arm/css/sgi/sgi_topology.c
rename to plat/arm/board/neoverse_rd/common/nrd_topology.c
index 1c3b5bf..ff04b2b 100644
--- a/plat/arm/css/sgi/sgi_topology.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,7 +7,7 @@
 #include <plat/arm/common/plat_arm.h>
 
 /*
- * Common topology related methods for SGI and RD based platforms
+ * Common topology related methods for Neoverse RD platforms
  */
 /*******************************************************************************
  * This function returns the core count within the cluster corresponding to
@@ -15,7 +15,7 @@
  ******************************************************************************/
 unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
 {
-	return CSS_SGI_MAX_CPUS_PER_CLUSTER;
+	return NRD_MAX_CPUS_PER_CLUSTER;
 }
 
 #if ARM_PLAT_MT
@@ -24,6 +24,6 @@
  *****************************************************************************/
 unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
 {
-	return CSS_SGI_MAX_PE_PER_CPU;
+	return NRD_MAX_PE_PER_CPU;
 }
 #endif
diff --git a/plat/arm/css/sgi/ras/sgi_ras_common.c b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_common.c
similarity index 65%
rename from plat/arm/css/sgi/ras/sgi_ras_common.c
rename to plat/arm/board/neoverse_rd/common/ras/nrd_ras_common.c
index 9789670..24f4506 100644
--- a/plat/arm/css/sgi/ras/sgi_ras_common.c
+++ b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2023, 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,27 +11,27 @@
 #include <plat/common/platform.h>
 #include <platform_def.h>
 
-#include <sgi_ras.h>
+#include <nrd_ras.h>
 
-static struct plat_sgi_ras_config *sgi_ras_config;
+static struct plat_nrd_ras_config *nrd_ras_config;
 
 /*
  * Find event map for a given interrupt number. On success, returns pointer to
  * the event map. On error, returns NULL.
  */
-struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num)
+struct nrd_ras_ev_map *nrd_find_ras_event_map_by_intr(uint32_t intr_num)
 {
-	struct sgi_ras_ev_map *map;
+	struct nrd_ras_ev_map *map;
 	int size;
 	int i;
 
-	if (sgi_ras_config == NULL) {
+	if (nrd_ras_config == NULL) {
 		ERROR("RAS config is NULL\n");
 		return NULL;
 	}
 
-	map = sgi_ras_config->ev_map;
-	size = sgi_ras_config->ev_map_size;
+	map = nrd_ras_config->ev_map;
+	size = nrd_ras_config->ev_map_size;
 
 	for (i = 0; i < size; i++) {
 		if (map->intr == intr_num)
@@ -47,14 +47,14 @@
  * Programs GIC registers and configures interrupt ID's as Group0 EL3
  * interrupts. Current support is to register PPI and SPI interrupts.
  */
-static void sgi_ras_intr_configure(int intr, int intr_type)
+static void nrd_ras_intr_configure(int intr, int intr_type)
 {
 	plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3);
 	plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI);
 	plat_ic_clear_interrupt_pending(intr);
 
 	/* Routing mode option available only for SPI interrupts */
-	if (intr_type == SGI_RAS_INTR_TYPE_SPI) {
+	if (intr_type == NRD_RAS_INTR_TYPE_SPI) {
 		plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY,
 					(u_register_t)read_mpidr_el1());
 	}
@@ -67,15 +67,15 @@
  * Registers RAS config provided by the platform and then configures and
  * enables interrupt for each registered error. On success, return 0.
  */
-int sgi_ras_platform_setup(struct plat_sgi_ras_config *config)
+int nrd_ras_platform_setup(struct plat_nrd_ras_config *config)
 {
-	struct sgi_ras_ev_map *map;
+	struct nrd_ras_ev_map *map;
 	int size;
 	int i;
 
 	/* Check if parameter is valid. */
 	if (config == NULL) {
-		ERROR("SGI: Failed to register RAS config\n");
+		ERROR("NRD: Failed to register RAS config\n");
 		return -1;
 	}
 
@@ -83,17 +83,17 @@
 	 * Maintain a reference to the platform RAS config data for later
 	 * use.
 	 */
-	sgi_ras_config = config;
+	nrd_ras_config = config;
 
-	map = sgi_ras_config->ev_map;
-	size = sgi_ras_config->ev_map_size;
+	map = nrd_ras_config->ev_map;
+	size = nrd_ras_config->ev_map_size;
 
 	for (i = 0; i < size; i++) {
-		sgi_ras_intr_configure(map->intr, map->intr_type);
+		nrd_ras_intr_configure(map->intr, map->intr_type);
 		map++;
 	}
 
-	INFO("SGI: Platform RAS setup successful\n");
+	INFO("NRD: Platform RAS setup successful\n");
 
 	return 0;
 }
diff --git a/plat/arm/css/sgi/ras/sgi_ras_cpu.c b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
similarity index 74%
rename from plat/arm/css/sgi/ras/sgi_ras_cpu.c
rename to plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
index 5e77dbb..371bde6 100644
--- a/plat/arm/css/sgi/ras/sgi_ras_cpu.c
+++ b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,7 +14,7 @@
 #include <services/sdei.h>
 #include <services/spm_mm_svc.h>
 
-#include <sgi_ras.h>
+#include <nrd_ras.h>
 
 #define CPU_CONTEXT_REG_GPR_ARR_SIZE 32
 #define CPU_CONTEXT_REG_EL1_ARR_SIZE 17
@@ -95,39 +95,39 @@
 						  CTX_TTBR1_EL1);
 
 #if CTX_INCLUDE_EL2_REGS
-	cpu_info->ErrCtxEl2Reg[0]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_ELR_EL2);
-	cpu_info->ErrCtxEl2Reg[1]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_ESR_EL2);
-	cpu_info->ErrCtxEl2Reg[2]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_FAR_EL2);
-	cpu_info->ErrCtxEl2Reg[3]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_HACR_EL2);
-	cpu_info->ErrCtxEl2Reg[4]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_HCR_EL2);
-	cpu_info->ErrCtxEl2Reg[5]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_HPFAR_EL2);
-	cpu_info->ErrCtxEl2Reg[6]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_MAIR_EL2);
-	cpu_info->ErrCtxEl2Reg[7]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_SCTLR_EL2);
-	cpu_info->ErrCtxEl2Reg[8]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_SP_EL2);
-	cpu_info->ErrCtxEl2Reg[9]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_SPSR_EL2);
-	cpu_info->ErrCtxEl2Reg[10]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_TCR_EL2);
-	cpu_info->ErrCtxEl2Reg[11]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_TPIDR_EL2);
-	cpu_info->ErrCtxEl2Reg[12]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_TTBR0_EL2);
-	cpu_info->ErrCtxEl2Reg[13]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_VTCR_EL2);
-	cpu_info->ErrCtxEl2Reg[14]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_VTTBR_EL2);
-	cpu_info->ErrCtxEl2Reg[15]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
-						   CTX_ESR_EL2);
-#endif
+	cpu_info->ErrCtxEl2Reg[0]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						elr_el2);
+	cpu_info->ErrCtxEl2Reg[1]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						esr_el2);
+	cpu_info->ErrCtxEl2Reg[2]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						far_el2);
+	cpu_info->ErrCtxEl2Reg[3]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						hacr_el2);
+	cpu_info->ErrCtxEl2Reg[4]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						hcr_el2);
+	cpu_info->ErrCtxEl2Reg[5]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						hpfar_el2);
+	cpu_info->ErrCtxEl2Reg[6]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						mair_el2);
+	cpu_info->ErrCtxEl2Reg[7]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						sctlr_el2);
+	cpu_info->ErrCtxEl2Reg[8]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						sp_el2);
+	cpu_info->ErrCtxEl2Reg[9]   = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						spsr_el2);
+	cpu_info->ErrCtxEl2Reg[10]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						tcr_el2);
+	cpu_info->ErrCtxEl2Reg[11]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						tpidr_el2);
+	cpu_info->ErrCtxEl2Reg[12]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						ttbr0_el2);
+	cpu_info->ErrCtxEl2Reg[13]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						vtcr_el2);
+	cpu_info->ErrCtxEl2Reg[14]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						vttbr_el2);
+	cpu_info->ErrCtxEl2Reg[15]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
+						esr_el2);
+#endif /* CTX_INCLUDE_EL2_REGS */
 
 	cpu_info->ErrCtxEl3Reg[0]   = read_ctx_reg(get_el3state_ctx(ctx),
 						   CTX_ELR_EL3);
@@ -143,11 +143,11 @@
 }
 
 /* CPU RAS interrupt handler */
-int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec,
+int nrd_ras_cpu_intr_handler(const struct err_record_info *err_rec,
 				int probe_data,
 				const struct err_handler_data *const data)
 {
-	struct sgi_ras_ev_map *ras_map;
+	struct nrd_ras_ev_map *ras_map;
 	mm_communicate_header_t *header;
 	cpu_err_info cpu_info = {0};
 	uint64_t clear_status;
@@ -186,9 +186,9 @@
 	 * Find if this is a RAS interrupt. There must be an event against
 	 * this interrupt
 	 */
-	ras_map = sgi_find_ras_event_map_by_intr(intr);
+	ras_map = nrd_find_ras_event_map_by_intr(intr);
 	if (ras_map == NULL) {
-		ERROR("SGI: RAS error info for interrupt id: %d not found\n",
+		ERROR("NRD: RAS error info for interrupt id: %d not found\n",
 			intr);
 		return -1;
 	}
diff --git a/plat/arm/css/sgi/ras/sgi_ras_sram.c b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_sram.c
similarity index 85%
rename from plat/arm/css/sgi/ras/sgi_ras_sram.c
rename to plat/arm/board/neoverse_rd/common/ras/nrd_ras_sram.c
index b100700..521efdf 100644
--- a/plat/arm/css/sgi/ras/sgi_ras_sram.c
+++ b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_sram.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,7 +11,7 @@
 #include <services/spm_mm_svc.h>
 
 #include <platform_def.h>
-#include <sgi_ras.h>
+#include <nrd_ras.h>
 
 /* Base Element RAM Error Record offsets. */
 #define ERRSTATUS	U(0)
@@ -22,11 +22,11 @@
  * Base Element RAM error information data structure communicated as part of MM
  * Communication data payload.
  */
-typedef struct sgi_sram_err_info {
+typedef struct nrd_sram_err_info {
 	uint32_t err_status;
 	uint32_t err_code;
 	uint32_t err_addr;
-} sgi_sram_err_info_t;
+} nrd_sram_err_info_t;
 
 /*
  * MM Communicate message header GUID to indicate the payload is intended for
@@ -38,13 +38,13 @@
 };
 
 /* Base element RAM RAS error interrupt handler */
-int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
+int nrd_ras_sram_intr_handler(const struct err_record_info *err_rec,
 				int probe_data,
 				const struct err_handler_data *const data)
 {
-	struct sgi_ras_ev_map *ras_map;
+	struct nrd_ras_ev_map *ras_map;
 	mm_communicate_header_t *header;
-	sgi_sram_err_info_t sram_info;
+	nrd_sram_err_info_t sram_info;
 	uintptr_t base_addr;
 	uint32_t clear_status, intr;
 	int ret;
@@ -52,7 +52,7 @@
 	cm_el1_sysregs_context_save(NON_SECURE);
 	intr = data->interrupt;
 
-	INFO("SGI: Base element RAM interrupt [%d] handler\n", intr);
+	INFO("NRD: Base element RAM interrupt [%d] handler\n", intr);
 
 	/* Determine error record base address to read. */
 	base_addr = 0;
@@ -87,9 +87,9 @@
 	 * Find if this is a RAS interrupt. There must be an event against
 	 * this interrupt
 	 */
-	ras_map = sgi_find_ras_event_map_by_intr(intr);
+	ras_map = nrd_find_ras_event_map_by_intr(intr);
 	if (ras_map == NULL) {
-		ERROR("SGI: RAS error info for interrupt id: %d not found\n",
+		ERROR("NRD: RAS error info for interrupt id: %d not found\n",
 			intr);
 		return -1;
 	}
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_fw_config.dts
similarity index 86%
copy from plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
copy to plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_fw_config.dts
index d3b7fba..085a42a 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
similarity index 86%
rename from plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
index 68366c5..3cef0d1 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
similarity index 89%
rename from plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
index 257ef4a..78cd5a8 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/rdn1edge/include/platform_def.h
similarity index 68%
rename from plat/arm/board/rdn1edge/include/platform_def.h
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/include/platform_def.h
index de01902..83590eb 100644
--- a/plat/arm/board/rdn1edge/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,12 +9,12 @@
 
 #include <lib/utils_def.h>
 
-#include <sgi_sdei.h>
-#include <sgi_soc_platform_def.h>
+#include <nrd_sdei.h>
+#include <nrd_soc_platform_def.h>
 
 #define PLAT_ARM_CLUSTER_COUNT		U(2)
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(4)
-#define CSS_SGI_MAX_PE_PER_CPU		U(1)
+#define NRD_MAX_CPUS_PER_CLUSTER	U(4)
+#define NRD_MAX_PE_PER_CPU		U(1)
 
 #define PLAT_CSS_MHU_BASE		UL(0x45400000)
 
@@ -31,16 +31,16 @@
 #define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
 
 /* Maximum number of address bits used per chip */
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(42)
+#define NRD_ADDR_BITS_PER_CHIP	U(42)
 
 /*
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
+#define PLAT_PHY_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
@@ -51,4 +51,7 @@
 #define PLAT_ARM_GICC_BASE		UL(0x2C000000)
 #define PLAT_ARM_GICR_BASE		UL(0x300C0000)
 
+#define RDN1E1_CHIP0_SPI_START		U(32)
+#define RDN1E1_CHIP0_SPI_END		U(991)
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdn1edge/platform.mk b/plat/arm/board/neoverse_rd/platform/rdn1edge/platform.mk
similarity index 77%
rename from plat/arm/board/rdn1edge/platform.mk
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/platform.mk
index d8d1293..8f21314 100644
--- a/plat/arm/board/rdn1edge/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,17 +9,17 @@
 # GIC-600 configuration
 GICV3_IMPL_GIC600_MULTICHIP	:=	1
 
-include plat/arm/css/sgi/sgi-common.mk
+include plat/arm/board/neoverse_rd/common/nrd-common.mk
 
-RDN1EDGE_BASE		=	plat/arm/board/rdn1edge
+RDN1EDGE_BASE		=	plat/arm/board/neoverse_rd/platform/rdn1edge
 
 PLAT_INCLUDES		+=	-I${RDN1EDGE_BASE}/include/
 
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_n1.S
+NRD_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_n1.S
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/nrd_plat.c
 
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL1_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDN1EDGE_BASE}/rdn1edge_err.c
 
 BL2_SOURCES		+=	${RDN1EDGE_BASE}/rdn1edge_plat.c	\
@@ -29,7 +29,7 @@
 				lib/utils/mem_region.c			\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL31_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDN1EDGE_BASE}/rdn1edge_plat.c	\
 				${RDN1EDGE_BASE}/rdn1edge_topology.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
@@ -62,14 +62,14 @@
 $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config,${NT_FW_CONFIG}))
 
 $(eval $(call CREATE_SEQ,SEQ,2))
-ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ifneq ($(NRD_CHIP_COUNT),$(filter $(NRD_CHIP_COUNT),$(SEQ)))
  $(error  "Chip count for RDN1Edge platform should be one of $(SEQ), currently \
-   set to ${CSS_SGI_CHIP_COUNT}.")
+   set to ${NRD_CHIP_COUNT}.")
 endif
 
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-N1-Edge should always be 0, \
-     currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+ifneq ($(NRD_PLATFORM_VARIANT),0)
+ $(error "NRD_PLATFORM_VARIANT for RD-N1-Edge should always be 0, \
+     currently set to ${NRD_PLATFORM_VARIANT}.")
 endif
 
 override CTX_INCLUDE_AARCH32_REGS	:= 0
diff --git a/plat/arm/board/rdn1edge/rdn1edge_err.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_err.c
similarity index 71%
rename from plat/arm/board/rdn1edge/rdn1edge_err.c
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_err.c
index 46d318c..273e1f4 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_err.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_err.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/rdn1edge_plat.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
similarity index 72%
rename from plat/arm/board/rdn1edge/rdn1edge_plat.c
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
index 6da8bcd..0c6756c 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,26 +8,28 @@
 #include <drivers/arm/gic600_multichip.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
-#include <sgi_soc_platform_def.h>
-#include <sgi_plat.h>
+
+#include <nrd_plat.h>
+#include <nrd_soc_platform_def.h>
 
 #if defined(IMAGE_BL31)
 static const mmap_region_t rdn1edge_dynamic_mmap[] = {
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+	NRD_MAP_DEVICE_REMOTE_CHIP(1),
 	SOC_CSS_MAP_DEVICE_REMOTE_CHIP(1)
 };
 
 static struct gic600_multichip_data rdn1e1_multichip_data __init = {
 	.rt_owner_base = PLAT_ARM_GICD_BASE,
 	.rt_owner = 0,
-	.chip_count = CSS_SGI_CHIP_COUNT,
+	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
 		PLAT_ARM_GICD_BASE >> 16,
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
 	},
 	.spi_ids = {
-		{PLAT_ARM_GICD_BASE, 32, 255},
+		{PLAT_ARM_GICD_BASE, RDN1E1_CHIP0_SPI_START,
+			RDN1E1_CHIP0_SPI_END},
 		{0, 0, 0}
 	}
 };
@@ -35,23 +37,23 @@
 static uintptr_t rdn1e1_multichip_gicr_frames[] = {
 	PLAT_ARM_GICR_BASE,				/* Chip 0's GICR Base */
 	PLAT_ARM_GICR_BASE +
-		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),	/* Chip 1's GICR BASE */
+		NRD_REMOTE_CHIP_MEM_OFFSET(1),		/* Chip 1's GICR BASE */
 	UL(0)						/* Zero Termination */
 };
 #endif /* IMAGE_BL31 */
 
-unsigned int plat_arm_sgi_get_platform_id(void)
+unsigned int plat_arm_nrd_get_platform_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
 				& SID_SYSTEM_ID_PART_NUM_MASK;
 }
 
-unsigned int plat_arm_sgi_get_config_id(void)
+unsigned int plat_arm_nrd_get_config_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
 }
 
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+unsigned int plat_arm_nrd_get_multi_chip_mode(void)
 {
 	return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
 			SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
@@ -68,12 +70,12 @@
 	unsigned int i;
 	int ret;
 
-	if (plat_arm_sgi_get_multi_chip_mode() == 0 && CSS_SGI_CHIP_COUNT > 1) {
+	if (plat_arm_nrd_get_multi_chip_mode() == 0 && NRD_CHIP_COUNT > 1) {
 		ERROR("Chip Count is set to %d but multi-chip mode not enabled\n",
-				CSS_SGI_CHIP_COUNT);
+				NRD_CHIP_COUNT);
 		panic();
-	} else if (plat_arm_sgi_get_multi_chip_mode() == 1 &&
-			CSS_SGI_CHIP_COUNT > 1) {
+	} else if (plat_arm_nrd_get_multi_chip_mode() == 1 &&
+			NRD_CHIP_COUNT > 1) {
 		INFO("Enabling support for multi-chip in RD-N1-Edge\n");
 
 		for (i = 0; i < ARRAY_SIZE(rdn1edge_dynamic_mmap); i++) {
@@ -93,6 +95,6 @@
 		gic600_multichip_init(&rdn1e1_multichip_data);
 	}
 
-	sgi_bl31_common_platform_setup();
+	nrd_bl31_common_platform_setup();
 }
 #endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn1edge/rdn1edge_security.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_security.c
similarity index 85%
rename from plat/arm/board/rdn1edge/rdn1edge_security.c
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_security.c
index 4943532..f3f6238 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_security.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_security.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,7 +7,7 @@
 #include <platform_def.h>
 
 #include <common/debug.h>
-#include <sgi_dmc620_tzc_regions.h>
+#include <nrd_dmc620_tzc_regions.h>
 
 uintptr_t rdn1edge_dmc_base[] = {
 	RDN1EDGE_DMC620_BASE0,
@@ -20,7 +20,7 @@
 };
 
 static const tzc_dmc620_acc_addr_data_t rdn1edge_acc_addr_data[] = {
-	CSS_SGI_DMC620_TZC_REGIONS_DEF
+	NRD_DMC620_TZC_REGIONS_DEF
 };
 
 static const tzc_dmc620_config_data_t rdn1edge_plat_config_data = {
diff --git a/plat/arm/board/rdn1edge/rdn1edge_topology.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_topology.c
similarity index 86%
rename from plat/arm/board/rdn1edge/rdn1edge_topology.c
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_topology.c
index 5bbea69..133eb16 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_topology.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_topology.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.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,12 +11,12 @@
  * The power domain tree descriptor.
  ******************************************************************************/
 static const unsigned char rdn1edge_pd_tree_desc[] = {
-	(PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-#if (CSS_SGI_CHIP_COUNT > 1)
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER
+	(PLAT_ARM_CLUSTER_COUNT) * (NRD_CHIP_COUNT),
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+#if (NRD_CHIP_COUNT > 1)
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER
 #endif
 };
 
@@ -41,7 +41,7 @@
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
-#if (CSS_SGI_CHIP_COUNT > 1)
+#if (NRD_CHIP_COUNT > 1)
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_trusted_boot.c
similarity index 88%
rename from plat/arm/board/rde1edge/rde1edge_trusted_boot.c
rename to plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_trusted_boot.c
index 4592b8f..84622d0 100644
--- a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_fw_config.dts
similarity index 85%
rename from plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_fw_config.dts
index d992eac..f857f72 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,12 +18,14 @@
 			id = <TB_FW_CONFIG_ID>;
 		};
 
+#if SPMC_AT_EL3
 		tos_fw-config {
 			load-address = <0x0 0x04001500>;
 			max-size = <0x1000>;
 			id = <TOS_FW_CONFIG_ID>;
 		};
 
+#endif
 		nt_fw-config {
 			load-address = <0x0 0xFEF00000>;
 			max-size = <0x0100000>;
diff --git a/plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_nt_fw_config.dts
similarity index 90%
rename from plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_nt_fw_config.dts
index dd70141..8e58565 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_nt_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 - 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
similarity index 97%
rename from plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
rename to plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
index 6119706..dbdc7e5 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_tb_fw_config.dts
similarity index 89%
rename from plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_tb_fw_config.dts
index 49eda27..c370623 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/fdts/rdn2_tb_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/rdn2/include/platform_def.h
similarity index 78%
rename from plat/arm/board/rdn2/include/platform_def.h
rename to plat/arm/board/neoverse_rd/platform/rdn2/include/platform_def.h
index 2391b72..840ea4a 100644
--- a/plat/arm/board/rdn2/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,19 +8,19 @@
 #define PLATFORM_DEF_H
 
 #include <lib/utils_def.h>
-#include <sgi_sdei.h>
-#include <sgi_soc_platform_def_v2.h>
+#include <nrd_sdei.h>
+#include <nrd_soc_platform_def_v2.h>
 
-#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#if (NRD_PLATFORM_VARIANT == 1)
 #define PLAT_ARM_CLUSTER_COUNT		U(8)
-#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#elif (NRD_PLATFORM_VARIANT == 2)
 #define PLAT_ARM_CLUSTER_COUNT		U(4)
 #else
 #define PLAT_ARM_CLUSTER_COUNT		U(16)
 #endif
 
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(1)
-#define CSS_SGI_MAX_PE_PER_CPU		U(1)
+#define NRD_MAX_CPUS_PER_CLUSTER	U(1)
+#define NRD_MAX_PE_PER_CPU		U(1)
 
 #define PLAT_CSS_MHU_BASE		UL(0x2A920000)
 #define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
@@ -34,9 +34,9 @@
 
 #define TZC400_OFFSET			UL(0x1000000)
 
-#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#if (NRD_PLATFORM_VARIANT == 1)
 #define TZC400_COUNT			U(2)
-#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#elif (NRD_PLATFORM_VARIANT == 2)
 #define TZC400_COUNT			U(4)
 #else
 #define TZC400_COUNT			U(8)
@@ -68,16 +68,16 @@
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(46)	/* 64TB */
+#if (NRD_PLATFORM_VARIANT == 2)
+#define NRD_ADDR_BITS_PER_CHIP	U(46)	/* 64TB */
 #else
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(42)	/* 4TB */
+#define NRD_ADDR_BITS_PER_CHIP	U(42)	/* 4TB */
 #endif
 
-#define PLAT_PHY_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
+#define PLAT_PHY_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
@@ -90,9 +90,9 @@
 /* Virtual address used by dynamic mem_protect for chunk_base */
 #define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xC0000000)
 
-#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#if (NRD_PLATFORM_VARIANT == 1)
 #define PLAT_ARM_GICR_BASE		UL(0x30100000)
-#elif (CSS_SGI_PLATFORM_VARIANT == 3)
+#elif (NRD_PLATFORM_VARIANT == 3)
 #define PLAT_ARM_GICR_BASE		UL(0x30300000)
 #else
 #define PLAT_ARM_GICR_BASE		UL(0x301C0000)
diff --git a/plat/arm/board/neoverse_rd/platform/rdn2/include/rdn2_ras.h b/plat/arm/board/neoverse_rd/platform/rdn2/include/rdn2_ras.h
new file mode 100644
index 0000000..c8a6f2d
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/include/rdn2_ras.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RDN2_RAS_H
+#define RDN2_RAS_H
+
+#include <nrd_ras.h>
+
+extern struct plat_nrd_ras_config ras_config;
+
+#endif /* RDN2_RAS_H */
diff --git a/plat/arm/board/rdn2/platform.mk b/plat/arm/board/neoverse_rd/platform/rdn2/platform.mk
similarity index 77%
rename from plat/arm/board/rdn2/platform.mk
rename to plat/arm/board/neoverse_rd/platform/rdn2/platform.mk
index 28ec5dc..12e7db4 100644
--- a/plat/arm/board/rdn2/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/platform.mk
@@ -1,19 +1,19 @@
-# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 RD_N2_VARIANTS	:= 0 1 2 3
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),\
-	$(filter $(CSS_SGI_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-N2 should be 0, 1, 2 or 3, currently \
-	set to ${CSS_SGI_PLATFORM_VARIANT}.")
+ifneq ($(NRD_PLATFORM_VARIANT),\
+	$(filter $(NRD_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
+ $(error "NRD_PLATFORM_VARIANT for RD-N2 should be 0, 1, 2 or 3, currently \
+	set to ${NRD_PLATFORM_VARIANT}.")
 endif
 
 $(eval $(call CREATE_SEQ,SEQ,4))
-ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ifneq ($(NRD_CHIP_COUNT),$(filter $(NRD_CHIP_COUNT),$(SEQ)))
  $(error  "Chip count for RD-N2-MC should be either $(SEQ) \
- currently it is set to ${CSS_SGI_CHIP_COUNT}.")
+ currently it is set to ${NRD_CHIP_COUNT}.")
 endif
 
 # RD-N2 platform uses GIC-700 which is based on GICv4.1
@@ -21,25 +21,25 @@
 GIC_EXT_INTID		:=	1
 
 #Enable GIC Multichip Extension only for Multichip Platforms
-ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+ifeq (${NRD_PLATFORM_VARIANT}, 2)
 GICV3_IMPL_GIC600_MULTICHIP	:=	1
 endif
 
 override CSS_SYSTEM_GRACEFUL_RESET	:= 1
 override EL3_EXCEPTION_HANDLING		:= 1
 
-include plat/arm/css/sgi/sgi-common.mk
+include plat/arm/board/neoverse_rd/common/nrd-common.mk
 
-RDN2_BASE		=	plat/arm/board/rdn2
+RDN2_BASE		=	plat/arm/board/neoverse_rd/platform/rdn2
 
 PLAT_INCLUDES		+=	-I${RDN2_BASE}/include/
 
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_n2.S \
+NRD_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_n2.S \
 				lib/cpus/aarch64/neoverse_v2.S
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat_v2.c
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/nrd_plat_v2.c
 
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL1_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDN2_BASE}/rdn2_err.c
 
 BL2_SOURCES		+=	${RDN2_BASE}/rdn2_plat.c		\
@@ -50,7 +50,7 @@
 				plat/arm/common/arm_tzc400.c		\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL31_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDN2_BASE}/rdn2_plat.c		\
 				${RDN2_BASE}/rdn2_topology.c		\
 				drivers/cfi/v2m/v2m_flash.c		\
@@ -62,7 +62,7 @@
 BL2_SOURCES		+=	${RDN2_BASE}/rdn2_trusted_boot.c
 endif
 
-ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+ifeq (${NRD_PLATFORM_VARIANT}, 2)
 BL31_SOURCES	+=	drivers/arm/gic/v3/gic600_multichip.c
 
 # Enable dynamic addition of MMAP regions in BL31
@@ -71,9 +71,9 @@
 
 ifeq (${ENABLE_FEAT_RAS}-${HANDLE_EA_EL3_FIRST_NS},1-1)
 BL31_SOURCES		+=	${RDN2_BASE}/rdn2_ras.c			\
-				${CSS_ENT_BASE}/ras/sgi_ras_common.c	\
-				${CSS_ENT_BASE}/ras/sgi_ras_sram.c	\
-				${CSS_ENT_BASE}/ras/sgi_ras_cpu.c
+				${NRD_COMMON_BASE}/ras/nrd_ras_common.c	\
+				${NRD_COMMON_BASE}/ras/nrd_ras_sram.c	\
+				${NRD_COMMON_BASE}/ras/nrd_ras_cpu.c
 endif
 
 # Add the FDT_SOURCES and options for Dynamic Config
@@ -93,12 +93,14 @@
 # Add the NT_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
 
+ifeq (${SPMC_AT_EL3}, 1)
 STMM_CONFIG_DTS		:=	${RDN2_BASE}/fdts/${PLAT}_stmm_sel0_manifest.dts
 FDT_SOURCES		+=	${STMM_CONFIG_DTS}
 TOS_FW_CONFIG		:=	${BUILD_PLAT}/fdts/$(notdir $(basename ${STMM_CONFIG_DTS})).dtb
 
 # Add the TOS_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${TOS_FW_CONFIG},--tos-fw-config,${TOS_FW_CONFIG}))
+endif
 
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 override ENABLE_FEAT_AMU		:= 1
diff --git a/plat/arm/board/rdn2/rdn2_err.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_err.c
similarity index 70%
rename from plat/arm/board/rdn2/rdn2_err.c
rename to plat/arm/board/neoverse_rd/platform/rdn2/rdn2_err.c
index 802ac21..d712645 100644
--- a/plat/arm/board/rdn2/rdn2_err.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_err.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/rdn2_plat.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
similarity index 66%
rename from plat/arm/board/rdn2/rdn2_plat.c
rename to plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
index 2a6c658..0051049 100644
--- a/plat/arm/board/rdn2/rdn2_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,93 +9,94 @@
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
 #include <services/el3_spmc_ffa_memory.h>
+
+#include <nrd_plat.h>
+#include <nrd_soc_platform_def_v2.h>
 #include <rdn2_ras.h>
-#include <sgi_soc_platform_def_v2.h>
-#include <sgi_plat.h>
 
 #if defined(IMAGE_BL31)
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#if (NRD_PLATFORM_VARIANT == 2)
 static const mmap_region_t rdn2mc_dynamic_mmap[] = {
-#if CSS_SGI_CHIP_COUNT > 1
+#if NRD_CHIP_COUNT > 1
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+	NRD_MAP_DEVICE_REMOTE_CHIP(1),
 #endif
-#if CSS_SGI_CHIP_COUNT > 2
+#if NRD_CHIP_COUNT > 2
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(2),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+	NRD_MAP_DEVICE_REMOTE_CHIP(2),
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
+#if NRD_CHIP_COUNT > 3
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(3),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+	NRD_MAP_DEVICE_REMOTE_CHIP(3),
 #endif
 };
 #endif
 
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#if (NRD_PLATFORM_VARIANT == 2)
 static struct gic600_multichip_data rdn2mc_multichip_data __init = {
 	.rt_owner_base = PLAT_ARM_GICD_BASE,
 	.rt_owner = 0,
-	.chip_count = CSS_SGI_CHIP_COUNT,
+	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
 		PLAT_ARM_GICD_BASE >> 16,
-#if CSS_SGI_CHIP_COUNT > 1
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+#if NRD_CHIP_COUNT > 1
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
 #endif
-#if CSS_SGI_CHIP_COUNT > 2
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+#if NRD_CHIP_COUNT > 2
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+#if NRD_CHIP_COUNT > 3
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
 #endif
 	},
 	.spi_ids = {
 		{PLAT_ARM_GICD_BASE, 32, 511},
-	#if CSS_SGI_CHIP_COUNT > 1
+	#if NRD_CHIP_COUNT > 1
 		{PLAT_ARM_GICD_BASE, 512, 991},
 	#endif
-	#if CSS_SGI_CHIP_COUNT > 2
+	#if NRD_CHIP_COUNT > 2
 		{PLAT_ARM_GICD_BASE, 4096, 4575},
 	#endif
-	#if CSS_SGI_CHIP_COUNT > 3
+	#if NRD_CHIP_COUNT > 3
 		{PLAT_ARM_GICD_BASE, 4576, 5055},
 	#endif
 	}
 };
 #endif
 
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#if (NRD_PLATFORM_VARIANT == 2)
 static uintptr_t rdn2mc_multichip_gicr_frames[] = {
 	/* Chip 0's GICR Base */
 	PLAT_ARM_GICR_BASE,
-#if CSS_SGI_CHIP_COUNT > 1
+#if NRD_CHIP_COUNT > 1
 	/* Chip 1's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
 #endif
-#if CSS_SGI_CHIP_COUNT > 2
+#if NRD_CHIP_COUNT > 2
 	/* Chip 2's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
+#if NRD_CHIP_COUNT > 3
 	/* Chip 3's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
 #endif
 	UL(0)	/* Zero Termination */
 };
 #endif
 #endif /* IMAGE_BL31 */
 
-unsigned int plat_arm_sgi_get_platform_id(void)
+unsigned int plat_arm_nrd_get_platform_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
 			    & SID_SYSTEM_ID_PART_NUM_MASK;
 }
 
-unsigned int plat_arm_sgi_get_config_id(void)
+unsigned int plat_arm_nrd_get_config_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
 }
 
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+unsigned int plat_arm_nrd_get_multi_chip_mode(void)
 {
 	return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
 			     SID_MULTI_CHIP_MODE_MASK) >>
@@ -105,13 +106,13 @@
 #if defined(IMAGE_BL31)
 void bl31_platform_setup(void)
 {
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#if (NRD_PLATFORM_VARIANT == 2)
 	int ret;
 	unsigned int i;
 
-	if (plat_arm_sgi_get_multi_chip_mode() == 0) {
-		ERROR("Chip Count is set to %u but multi-chip mode is not "
-			"enabled\n", CSS_SGI_CHIP_COUNT);
+	if (plat_arm_nrd_get_multi_chip_mode() == 0) {
+		ERROR("Chip Count is %u but multi-chip mode is not enabled\n",
+			NRD_CHIP_COUNT);
 		panic();
 	} else {
 		INFO("Enabling multi-chip support for RD-N2 variant\n");
@@ -135,10 +136,10 @@
 	}
 #endif
 
-	sgi_bl31_common_platform_setup();
+	nrd_bl31_common_platform_setup();
 
 #if ENABLE_FEAT_RAS && FFH_SUPPORT
-	sgi_ras_platform_setup(&ras_config);
+	nrd_ras_platform_setup(&ras_config);
 #endif
 }
 #endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn2/rdn2_ras.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_ras.c
similarity index 69%
rename from plat/arm/board/rdn2/rdn2_ras.c
rename to plat/arm/board/neoverse_rd/platform/rdn2/rdn2_ras.c
index 3aed58e..d046a1f 100644
--- a/plat/arm/board/rdn2/rdn2_ras.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_ras.c
@@ -1,30 +1,31 @@
 /*
- * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <platform_def.h>
-#include <sgi_ras.h>
-#include <sgi_sdei.h>
 
-struct sgi_ras_ev_map plat_ras_map[] = {
+#include <nrd_ras.h>
+#include <nrd_sdei.h>
+
+struct nrd_ras_ev_map plat_ras_map[] = {
 	/* Non Secure base RAM ECC CE interrupt */
-	{SGI_SDEI_DS_EVENT_0, NS_RAM_ECC_CE_INT, SGI_RAS_INTR_TYPE_SPI},
+	{NRD_SDEI_DS_EVENT_0, NS_RAM_ECC_CE_INT, NRD_RAS_INTR_TYPE_SPI},
 
 	/* Non Secure base RAM ECC UE interrupt */
-	{SGI_SDEI_DS_EVENT_0, NS_RAM_ECC_UE_INT, SGI_RAS_INTR_TYPE_SPI},
+	{NRD_SDEI_DS_EVENT_0, NS_RAM_ECC_UE_INT, NRD_RAS_INTR_TYPE_SPI},
 
 	/* CPU 1-bit ECC CE error interrupt */
-	{SGI_SDEI_DS_EVENT_1, PLAT_CORE_FAULT_IRQ, SGI_RAS_INTR_TYPE_PPI}
+	{NRD_SDEI_DS_EVENT_1, PLAT_CORE_FAULT_IRQ, NRD_RAS_INTR_TYPE_PPI}
 };
 
 /* RAS error record list definition, used by the common RAS framework. */
 struct err_record_info plat_err_records[] = {
 	/* Base element RAM Non-secure error record. */
 	ERR_RECORD_MEMMAP_V1(SOC_NS_RAM_ERR_REC_BASE, 4, NULL,
-				&sgi_ras_sram_intr_handler, 0),
-	ERR_RECORD_SYSREG_V1(0, 1, NULL, &sgi_ras_cpu_intr_handler, 0),
+				&nrd_ras_sram_intr_handler, 0),
+	ERR_RECORD_SYSREG_V1(0, 1, NULL, &nrd_ras_cpu_intr_handler, 0),
 };
 
 /* RAS error interrupt list definition, used by the common RAS framework. */
@@ -47,7 +48,7 @@
 REGISTER_RAS_INTERRUPTS(plat_ras_interrupts);
 
 /* Platform RAS handling config data definition */
-struct plat_sgi_ras_config ras_config = {
+struct plat_nrd_ras_config ras_config = {
 	plat_ras_map,
 	ARRAY_SIZE(plat_ras_map)
 };
diff --git a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_security.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_security.c
new file mode 100644
index 0000000..41172ea
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_security.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+#define RDN2_TZC_CPER_REGION				\
+	{NRD_SP_CPER_BUF_BASE, (NRD_SP_CPER_BUF_BASE +	\
+	NRD_SP_CPER_BUF_SIZE) - 1, TZC_REGION_S_NONE,	\
+	PLAT_ARM_TZC_NS_DEV_ACCESS}
+
+static const arm_tzc_regions_info_t tzc_regions[] = {
+	ARM_TZC_REGIONS_DEF,
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
+	RDN2_TZC_CPER_REGION,
+#endif
+	{}
+};
+
+#if (NRD_PLATFORM_VARIANT == 2 && NRD_CHIP_COUNT > 1)
+static const arm_tzc_regions_info_t tzc_regions_mc[][NRD_CHIP_COUNT - 1] = {
+	{
+		/* TZC memory regions for second chip */
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
+		{}
+	},
+#if NRD_CHIP_COUNT > 2
+	{
+		/* TZC memory regions for third chip */
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
+		{}
+	},
+#endif
+#if NRD_CHIP_COUNT > 3
+	{
+		/* TZC memory regions for fourth chip */
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
+		{}
+	},
+#endif
+};
+#endif /* NRD_PLATFORM_VARIANT && NRD_CHIP_COUNT */
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+	unsigned int i;
+
+	INFO("Configuring TrustZone Controller for Chip 0\n");
+
+	for (i = 0; i < TZC400_COUNT; i++) {
+		arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+	}
+
+#if (NRD_PLATFORM_VARIANT == 2 && NRD_CHIP_COUNT > 1)
+	unsigned int j;
+
+	for (i = 1; i < NRD_CHIP_COUNT; i++) {
+		INFO("Configuring TrustZone Controller for Chip %u\n", i);
+
+		for (j = 0; j < TZC400_COUNT; j++) {
+			arm_tzc400_setup(NRD_REMOTE_CHIP_MEM_OFFSET(i)
+				+ TZC400_BASE(j), tzc_regions_mc[i-1]);
+		}
+	}
+#endif
+}
diff --git a/plat/arm/board/rdn2/rdn2_topology.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_topology.c
similarity index 76%
rename from plat/arm/board/rdn2/rdn2_topology.c
rename to plat/arm/board/neoverse_rd/platform/rdn2/rdn2_topology.c
index 24acc4d..b8b6b7a 100644
--- a/plat/arm/board/rdn2/rdn2_topology.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,31 +11,31 @@
  * The power domain tree descriptor.
  ******************************************************************************/
 const unsigned char rd_n2_pd_tree_desc[] = {
-	(PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	(PLAT_ARM_CLUSTER_COUNT) * (NRD_CHIP_COUNT),
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #if (PLAT_ARM_CLUSTER_COUNT > 4 || \
-	(CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1))
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	(NRD_PLATFORM_VARIANT == 2 && NRD_CHIP_COUNT > 1))
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #endif
 #if (PLAT_ARM_CLUSTER_COUNT > 8 || \
-	(CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 2))
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	(NRD_PLATFORM_VARIANT == 2 && NRD_CHIP_COUNT > 2))
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #endif
 #if (PLAT_ARM_CLUSTER_COUNT > 8 || \
-	(CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 3))
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	(NRD_PLATFORM_VARIANT == 2 && NRD_CHIP_COUNT > 3))
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #endif
 };
 
@@ -51,25 +51,25 @@
  * The array mapping platform core position (implemented by plat_my_core_pos())
  * to the SCMI power domain ID implemented by SCP.
  ******************************************************************************/
-#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#if (NRD_PLATFORM_VARIANT == 2)
 const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
-#if (CSS_SGI_CHIP_COUNT > 1)
+#if (NRD_CHIP_COUNT > 1)
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 2)
+#if (NRD_CHIP_COUNT > 2)
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x3)),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
+#if (NRD_CHIP_COUNT > 3)
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x2)),
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_trusted_boot.c
similarity index 88%
copy from plat/arm/board/rde1edge/rde1edge_trusted_boot.c
copy to plat/arm/board/neoverse_rd/platform/rdn2/rdn2_trusted_boot.c
index 4592b8f..84622d0 100644
--- a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_fw_config.dts
similarity index 86%
copy from plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
copy to plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_fw_config.dts
index d3b7fba..d443443 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <common/tbbr/tbbr_img_def.h>
 
 /dts-v1/;
+
 / {
 	dtb-registry {
 		compatible = "fconf,dyn_cfg-dtb_registry";
@@ -24,4 +25,3 @@
 		};
 	};
 };
-
diff --git a/plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_nt_fw_config.dts
similarity index 82%
rename from plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_nt_fw_config.dts
index 62ba2c3..fb08885 100644
--- a/plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_nt_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_tb_fw_config.dts
similarity index 89%
copy from plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
copy to plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_tb_fw_config.dts
index 49eda27..c370623 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/fdts/rdv1_tb_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdv1/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/rdv1/include/platform_def.h
similarity index 81%
rename from plat/arm/board/rdv1/include/platform_def.h
rename to plat/arm/board/neoverse_rd/platform/rdv1/include/platform_def.h
index 620fa3e..f889561 100644
--- a/plat/arm/board/rdv1/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,11 +9,11 @@
 
 #include <lib/utils_def.h>
 
-#include <sgi_soc_platform_def.h>
+#include <nrd_soc_platform_def.h>
 
 #define PLAT_ARM_CLUSTER_COUNT		U(16)
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(1)
-#define CSS_SGI_MAX_PE_PER_CPU		U(1)
+#define NRD_MAX_CPUS_PER_CLUSTER	U(1)
+#define NRD_MAX_PE_PER_CPU		U(1)
 
 #define PLAT_CSS_MHU_BASE		UL(0x45400000)
 #define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
@@ -47,14 +47,14 @@
 		(TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIRTIO))
 
 /* Maximum number of address bits used per chip */
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(42)
+#define NRD_ADDR_BITS_PER_CHIP	U(42)
 
 /*
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << NRD_ADDR_BITS_PER_CHIP)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << NRD_ADDR_BITS_PER_CHIP)
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
diff --git a/plat/arm/board/rdv1/platform.mk b/plat/arm/board/neoverse_rd/platform/rdv1/platform.mk
similarity index 77%
rename from plat/arm/board/rdv1/platform.mk
rename to plat/arm/board/neoverse_rd/platform/rdv1/platform.mk
index 0b059b5..0950df2 100644
--- a/plat/arm/board/rdv1/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/platform.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -6,17 +6,17 @@
 # RD-V1 platform uses GIC-700 which is based on GICv4.1
 GIC_ENABLE_V4_EXTN	:=	1
 
-include plat/arm/css/sgi/sgi-common.mk
+include plat/arm/board/neoverse_rd/common/nrd-common.mk
 
-RDV1_BASE		=	plat/arm/board/rdv1
+RDV1_BASE		=	plat/arm/board/neoverse_rd/platform/rdv1
 
 PLAT_INCLUDES		+=	-I${RDV1_BASE}/include/
 
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_v1.S
+NRD_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_v1.S
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/nrd_plat.c
 
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL1_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDV1_BASE}/rdv1_err.c
 
 BL2_SOURCES		+=	${RDV1_BASE}/rdv1_plat.c	\
@@ -27,7 +27,7 @@
 				plat/arm/common/arm_tzc400.c		\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL31_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDV1_BASE}/rdv1_plat.c	\
 				${RDV1_BASE}/rdv1_topology.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
@@ -59,9 +59,9 @@
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 override ENABLE_FEAT_AMU		:= 1
 
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1 should always be 0, \
-     currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+ifneq ($(NRD_PLATFORM_VARIANT),0)
+ $(error "NRD_PLATFORM_VARIANT for RD-V1 should always be 0, \
+     currently set to ${NRD_PLATFORM_VARIANT}.")
 endif
 
 # Enable the flag since RD-V1 has a system level cache
diff --git a/plat/arm/board/rdv1/rdv1_err.c b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_err.c
similarity index 70%
rename from plat/arm/board/rdv1/rdv1_err.c
rename to plat/arm/board/neoverse_rd/platform/rdv1/rdv1_err.c
index 68f9a3e..d75f525 100644
--- a/plat/arm/board/rdv1/rdv1_err.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_err.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_plat.c b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_plat.c
new file mode 100644
index 0000000..7cdc19a
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_plat.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <nrd_plat.h>
+
+unsigned int plat_arm_nrd_get_platform_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
+				& SID_SYSTEM_ID_PART_NUM_MASK;
+}
+
+unsigned int plat_arm_nrd_get_config_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
+}
+
+unsigned int plat_arm_nrd_get_multi_chip_mode(void)
+{
+	return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
+			SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
+}
+
+void bl31_platform_setup(void)
+{
+	nrd_bl31_common_platform_setup();
+}
diff --git a/plat/arm/board/rdv1/rdv1_security.c b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_security.c
similarity index 82%
rename from plat/arm/board/rdv1/rdv1_security.c
rename to plat/arm/board/neoverse_rd/platform/rdv1/rdv1_security.c
index 1247db8..a936a71 100644
--- a/plat/arm/board/rdv1/rdv1_security.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_security.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdv1/rdv1_topology.c b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_topology.c
similarity index 77%
rename from plat/arm/board/rdv1/rdv1_topology.c
rename to plat/arm/board/neoverse_rd/platform/rdv1/rdv1_topology.c
index ab64fd8..20e4266 100644
--- a/plat/arm/board/rdv1/rdv1_topology.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,22 +12,22 @@
  ******************************************************************************/
 const unsigned char rd_v1_pd_tree_desc[] = {
 	PLAT_ARM_CLUSTER_COUNT,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER
 };
 
 /*******************************************************************************
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_trusted_boot.c
similarity index 88%
copy from plat/arm/board/rde1edge/rde1edge_trusted_boot.c
copy to plat/arm/board/neoverse_rd/platform/rdv1/rdv1_trusted_boot.c
index 4592b8f..84622d0 100644
--- a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1/rdv1_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_fw_config.dts
similarity index 86%
copy from plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
copy to plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_fw_config.dts
index d3b7fba..d443443 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <common/tbbr/tbbr_img_def.h>
 
 /dts-v1/;
+
 / {
 	dtb-registry {
 		compatible = "fconf,dyn_cfg-dtb_registry";
@@ -24,4 +25,3 @@
 		};
 	};
 };
-
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
similarity index 82%
rename from plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
index 71c7db3..78fa31e 100644
--- a/plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
similarity index 89%
rename from plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
index 49eda27..c370623 100644
--- a/plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdv1mc/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/rdv1mc/include/platform_def.h
similarity index 77%
rename from plat/arm/board/rdv1mc/include/platform_def.h
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/include/platform_def.h
index 3670904..3e7c9b5 100644
--- a/plat/arm/board/rdv1mc/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,11 +8,11 @@
 #define PLATFORM_DEF_H
 
 #include <lib/utils_def.h>
-#include <sgi_soc_platform_def.h>
+#include <nrd_soc_platform_def.h>
 
 #define PLAT_ARM_CLUSTER_COUNT		U(4)
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(1)
-#define CSS_SGI_MAX_PE_PER_CPU		U(1)
+#define NRD_MAX_CPUS_PER_CLUSTER	U(1)
+#define NRD_MAX_PE_PER_CPU		U(1)
 
 #define PLAT_CSS_MHU_BASE		UL(0x45400000)
 #define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
@@ -47,17 +47,20 @@
 #define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xC0000000)
 
 /* Remote chip address offset (4TB per chip) */
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(42)
+#define NRD_ADDR_BITS_PER_CHIP	U(42)
 
 /* Physical and virtual address space limits for MMU in AARCH64 mode */
-#define PLAT_PHY_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
-						CSS_SGI_CHIP_COUNT)
+#define PLAT_PHY_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	NRD_REMOTE_CHIP_MEM_OFFSET( \
+						NRD_CHIP_COUNT)
 
 /* GIC related constants */
 #define PLAT_ARM_GICD_BASE		UL(0x30000000)
 #define PLAT_ARM_GICC_BASE		UL(0x2C000000)
 #define PLAT_ARM_GICR_BASE		UL(0x30140000)
 
+#define RDV1MC_CHIP0_SPI_START		U(32)
+#define RDV1MC_CHIP0_SPI_END		U(991)
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdv1mc/platform.mk b/plat/arm/board/neoverse_rd/platform/rdv1mc/platform.mk
similarity index 76%
rename from plat/arm/board/rdv1mc/platform.mk
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/platform.mk
index 176e0ef..9d878c3 100644
--- a/plat/arm/board/rdv1mc/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/platform.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -7,17 +7,17 @@
 GIC_ENABLE_V4_EXTN		:=	1
 GICV3_IMPL_GIC600_MULTICHIP	:=	1
 
-include plat/arm/css/sgi/sgi-common.mk
+include plat/arm/board/neoverse_rd/common/nrd-common.mk
 
-RDV1MC_BASE	=	plat/arm/board/rdv1mc
+RDV1MC_BASE	=	plat/arm/board/neoverse_rd/platform/rdv1mc
 
 PLAT_INCLUDES		+=	-I${RDV1MC_BASE}/include/
 
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_v1.S
+NRD_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_v1.S
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/nrd_plat.c
 
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL1_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDV1MC_BASE}/rdv1mc_err.c
 
 BL2_SOURCES		+=	${RDV1MC_BASE}/rdv1mc_plat.c	\
@@ -28,7 +28,7 @@
 				lib/utils/mem_region.c			\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL31_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${RDV1MC_BASE}/rdv1mc_plat.c	\
 				${RDV1MC_BASE}/rdv1mc_topology.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
@@ -56,9 +56,9 @@
 $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
 
 $(eval $(call CREATE_SEQ,SEQ,4))
-ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ifneq ($(NRD_CHIP_COUNT),$(filter $(NRD_CHIP_COUNT),$(SEQ)))
  $(error  "Chip count for RD-V1-MC should be either $(SEQ) \
- currently it is set to ${CSS_SGI_CHIP_COUNT}.")
+ currently it is set to ${NRD_CHIP_COUNT}.")
 endif
 
 FDT_SOURCES		+=	${RDV1MC_BASE}/fdts/${PLAT}_nt_fw_config.dts
@@ -70,9 +70,9 @@
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 override ENABLE_FEAT_AMU		:= 1
 
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1-MC should always be 0, \
-     currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+ifneq ($(NRD_PLATFORM_VARIANT),0)
+ $(error "NRD_PLATFORM_VARIANT for RD-V1-MC should always be 0, \
+     currently set to ${NRD_PLATFORM_VARIANT}.")
 endif
 
 # Enable the flag since RD-V1-MC has a system level cache
diff --git a/plat/arm/board/rdv1mc/rdv1mc_err.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_err.c
similarity index 71%
rename from plat/arm/board/rdv1mc/rdv1mc_err.c
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_err.c
index 755a503..b855edd 100644
--- a/plat/arm/board/rdv1mc/rdv1mc_err.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_err.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdv1mc/rdv1mc_plat.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
similarity index 60%
rename from plat/arm/board/rdv1mc/rdv1mc_plat.c
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
index e4469dc..4455ec4 100644
--- a/plat/arm/board/rdv1mc/rdv1mc_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,22 +8,23 @@
 #include <drivers/arm/gic600_multichip.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
-#include <sgi_soc_platform_def.h>
-#include <sgi_plat.h>
+
+#include <nrd_plat.h>
+#include <nrd_soc_platform_def.h>
 
 #if defined(IMAGE_BL31)
 static const mmap_region_t rdv1mc_dynamic_mmap[] = {
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+	NRD_MAP_DEVICE_REMOTE_CHIP(1),
 	SOC_CSS_MAP_DEVICE_REMOTE_CHIP(1),
-#if (CSS_SGI_CHIP_COUNT > 2)
+#if (NRD_CHIP_COUNT > 2)
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(2),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+	NRD_MAP_DEVICE_REMOTE_CHIP(2),
 	SOC_CSS_MAP_DEVICE_REMOTE_CHIP(2),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
+#if (NRD_CHIP_COUNT > 3)
 	ARM_MAP_SHARED_RAM_REMOTE_CHIP(3),
-	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+	NRD_MAP_DEVICE_REMOTE_CHIP(3),
 	SOC_CSS_MAP_DEVICE_REMOTE_CHIP(3)
 #endif
 };
@@ -31,24 +32,25 @@
 static struct gic600_multichip_data rdv1mc_multichip_data __init = {
 	.rt_owner_base = PLAT_ARM_GICD_BASE,
 	.rt_owner = 0,
-	.chip_count = CSS_SGI_CHIP_COUNT,
+	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
 		PLAT_ARM_GICD_BASE >> 16,
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
-#if (CSS_SGI_CHIP_COUNT > 2)
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+#if (NRD_CHIP_COUNT > 2)
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
-		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+#if (NRD_CHIP_COUNT > 3)
+		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
 #endif
 	},
 	.spi_ids = {
-		{PLAT_ARM_GICD_BASE, 32, 255},
+		{PLAT_ARM_GICD_BASE, RDV1MC_CHIP0_SPI_START,
+			RDV1MC_CHIP0_SPI_END},
 		{0, 0, 0},
-#if (CSS_SGI_CHIP_COUNT > 2)
+#if (NRD_CHIP_COUNT > 2)
 		{0, 0, 0},
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
+#if (NRD_CHIP_COUNT > 3)
 		{0, 0, 0},
 #endif
 	}
@@ -58,31 +60,31 @@
 	/* Chip 0's GICR Base */
 	PLAT_ARM_GICR_BASE,
 	/* Chip 1's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
-#if (CSS_SGI_CHIP_COUNT > 2)
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
+#if (NRD_CHIP_COUNT > 2)
 	/* Chip 2's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
+#if (NRD_CHIP_COUNT > 3)
 	/* Chip 3's GICR BASE */
-	PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+	PLAT_ARM_GICR_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
 #endif
 	UL(0)	/* Zero Termination */
 };
 #endif /* IMAGE_BL31 */
 
-unsigned int plat_arm_sgi_get_platform_id(void)
+unsigned int plat_arm_nrd_get_platform_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
 				& SID_SYSTEM_ID_PART_NUM_MASK;
 }
 
-unsigned int plat_arm_sgi_get_config_id(void)
+unsigned int plat_arm_nrd_get_config_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
 }
 
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+unsigned int plat_arm_nrd_get_multi_chip_mode(void)
 {
 	return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
 			SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
@@ -99,13 +101,13 @@
 	int ret;
 	unsigned int i;
 
-	if ((plat_arm_sgi_get_multi_chip_mode() == 0) &&
-			(CSS_SGI_CHIP_COUNT > 1)) {
-		ERROR("Chip Count is set to %u but multi-chip mode is not "
-			"enabled\n", CSS_SGI_CHIP_COUNT);
+	if ((plat_arm_nrd_get_multi_chip_mode() == 0) &&
+			(NRD_CHIP_COUNT > 1)) {
+		ERROR("Chip Count is %u but multi-chip mode is not enabled\n",
+			NRD_CHIP_COUNT);
 		panic();
-	} else if ((plat_arm_sgi_get_multi_chip_mode() == 1) &&
-			(CSS_SGI_CHIP_COUNT > 1)) {
+	} else if ((plat_arm_nrd_get_multi_chip_mode() == 1) &&
+			(NRD_CHIP_COUNT > 1)) {
 		INFO("Enabling support for multi-chip in RD-V1-MC\n");
 
 		for (i = 0; i < ARRAY_SIZE(rdv1mc_dynamic_mmap); i++) {
@@ -126,6 +128,6 @@
 		gic600_multichip_init(&rdv1mc_multichip_data);
 	}
 
-	sgi_bl31_common_platform_setup();
+	nrd_bl31_common_platform_setup();
 }
 #endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdv1mc/rdv1mc_security.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_security.c
similarity index 63%
rename from plat/arm/board/rdv1mc/rdv1mc_security.c
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_security.c
index adc0bf8..7fca31a 100644
--- a/plat/arm/board/rdv1mc/rdv1mc_security.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_security.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,29 +14,29 @@
 	{}
 };
 
-#if CSS_SGI_CHIP_COUNT > 1
-static const arm_tzc_regions_info_t tzc_regions_mc[][CSS_SGI_CHIP_COUNT - 1] = {
+#if NRD_CHIP_COUNT > 1
+static const arm_tzc_regions_info_t tzc_regions_mc[][NRD_CHIP_COUNT - 1] = {
 	{
 		/* TZC memory regions for second chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
 		{}
 	},
-#if CSS_SGI_CHIP_COUNT > 2
+#if NRD_CHIP_COUNT > 2
 	{
 		/* TZC memory regions for third chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
 		{}
 	},
 #endif
-#if CSS_SGI_CHIP_COUNT > 3
+#if NRD_CHIP_COUNT > 3
 	{
 		/* TZC memory regions for fourth chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
+		NRD_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
 		{}
 	},
 #endif
 };
-#endif /* CSS_SGI_CHIP_COUNT */
+#endif /* NRD_CHIP_COUNT */
 
 /* Initialize the secure environment */
 void plat_arm_security_setup(void)
@@ -49,14 +49,14 @@
 		arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
 	}
 
-#if CSS_SGI_CHIP_COUNT > 1
+#if NRD_CHIP_COUNT > 1
 	unsigned int j;
 
-	for (i = 1; i < CSS_SGI_CHIP_COUNT; i++) {
+	for (i = 1; i < NRD_CHIP_COUNT; i++) {
 		INFO("Configuring TrustZone Controller for Chip %u\n", i);
 
 		for (j = 0; j < TZC400_COUNT; j++) {
-			arm_tzc400_setup(CSS_SGI_REMOTE_CHIP_MEM_OFFSET(i)
+			arm_tzc400_setup(NRD_REMOTE_CHIP_MEM_OFFSET(i)
 				+ TZC400_BASE(j), tzc_regions_mc[i-1]);
 		}
 	}
diff --git a/plat/arm/board/rdv1mc/rdv1mc_topology.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_topology.c
similarity index 69%
rename from plat/arm/board/rdv1mc/rdv1mc_topology.c
rename to plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_topology.c
index 4486e5c..52514ca 100644
--- a/plat/arm/board/rdv1mc/rdv1mc_topology.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,34 +7,35 @@
 #include <common/debug.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/arm/css/common/css_pm.h>
-#include <sgi_variant.h>
+
+#include <nrd_variant.h>
 
 /******************************************************************************
  * The power domain tree descriptor.
  ******************************************************************************/
 const unsigned char rd_v1_mc_pd_tree_desc_multi_chip[] = {
-	((PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT)),
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-#if (CSS_SGI_CHIP_COUNT > 1)
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	((PLAT_ARM_CLUSTER_COUNT) * (NRD_CHIP_COUNT)),
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+#if (NRD_CHIP_COUNT > 1)
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #endif
-#if (CSS_SGI_CHIP_COUNT > 2)
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (NRD_CHIP_COUNT > 2)
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER
+#if (NRD_CHIP_COUNT > 3)
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER
 #endif
 };
 
@@ -43,7 +44,7 @@
  ******************************************************************************/
 const unsigned char *plat_get_power_domain_tree_desc(void)
 {
-	if (plat_arm_sgi_get_multi_chip_mode() == 1)
+	if (plat_arm_nrd_get_multi_chip_mode() == 1)
 		return rd_v1_mc_pd_tree_desc_multi_chip;
 	panic();
 }
@@ -57,19 +58,19 @@
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
-#if (CSS_SGI_CHIP_COUNT > 1)
+#if (NRD_CHIP_COUNT > 1)
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 2)
+#if (NRD_CHIP_COUNT > 2)
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x2)),
 	(SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x3)),
 #endif
-#if (CSS_SGI_CHIP_COUNT > 3)
+#if (NRD_CHIP_COUNT > 3)
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x0)),
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x1)),
 	(SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x2)),
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_trusted_boot.c
similarity index 88%
copy from plat/arm/board/rde1edge/rde1edge_trusted_boot.c
copy to plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_trusted_boot.c
index 4592b8f..84622d0 100644
--- a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_fw_config.dts
similarity index 86%
rename from plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_fw_config.dts
index d3b7fba..fe62b6d 100644
--- a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <common/tbbr/tbbr_img_def.h>
 
 /dts-v1/;
+
 / {
 	dtb-registry {
 		compatible = "fconf,dyn_cfg-dtb_registry";
@@ -24,4 +25,3 @@
 		};
 	};
 };
-
diff --git a/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_nt_fw_config.dts
similarity index 86%
rename from plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_nt_fw_config.dts
index 260247a..0573488 100644
--- a/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_nt_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_tb_fw_config.dts
similarity index 89%
rename from plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
rename to plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_tb_fw_config.dts
index 49eda27..c370623 100644
--- a/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/fdts/sgi575_tb_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/sgi575/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/sgi575/include/platform_def.h
similarity index 70%
rename from plat/arm/board/sgi575/include/platform_def.h
rename to plat/arm/board/neoverse_rd/platform/sgi575/include/platform_def.h
index 82a38c5..9658ee1 100644
--- a/plat/arm/board/sgi575/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,12 +9,12 @@
 
 #include <lib/utils_def.h>
 
-#include <sgi_sdei.h>
-#include <sgi_soc_platform_def.h>
+#include <nrd_sdei.h>
+#include <nrd_soc_platform_def.h>
 
 #define PLAT_ARM_CLUSTER_COUNT		U(2)
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(4)
-#define CSS_SGI_MAX_PE_PER_CPU		U(1)
+#define NRD_MAX_CPUS_PER_CLUSTER	U(4)
+#define NRD_MAX_PE_PER_CPU		U(1)
 
 #define PLAT_CSS_MHU_BASE		UL(0x45000000)
 
@@ -28,14 +28,14 @@
 #define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
 
 /* Maximum number of address bits used per chip */
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(36)
+#define NRD_ADDR_BITS_PER_CHIP	U(36)
 
 /*
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << NRD_ADDR_BITS_PER_CHIP)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << NRD_ADDR_BITS_PER_CHIP)
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
diff --git a/plat/arm/board/sgi575/platform.mk b/plat/arm/board/neoverse_rd/platform/sgi575/platform.mk
similarity index 75%
rename from plat/arm/board/sgi575/platform.mk
rename to plat/arm/board/neoverse_rd/platform/sgi575/platform.mk
index 2f2bf73..d34e555 100644
--- a/plat/arm/board/sgi575/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/platform.mk
@@ -1,22 +1,22 @@
 #
-# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 $(warning Platform ${PLAT} is deprecated. Some of the features might not work as expected)
 
-include plat/arm/css/sgi/sgi-common.mk
+include plat/arm/board/neoverse_rd/common/nrd-common.mk
 
-SGI575_BASE		=	plat/arm/board/sgi575
+SGI575_BASE		=	plat/arm/board/neoverse_rd/platform/sgi575
 
 PLAT_INCLUDES		+=	-I${SGI575_BASE}/include/
 
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/cortex_a75.S
+NRD_CPU_SOURCES		:=	lib/cpus/aarch64/cortex_a75.S
 
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c
+PLAT_BL_COMMON_SOURCES	+=	${NRD_COMMON_BASE}/nrd_plat.c
 
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL1_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${SGI575_BASE}/sgi575_err.c
 
 BL2_SOURCES		+=	${SGI575_BASE}/sgi575_plat.c		\
@@ -26,7 +26,7 @@
 				lib/utils/mem_region.c			\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+BL31_SOURCES		+=	${NRD_CPU_SOURCES}			\
 				${SGI575_BASE}/sgi575_plat.c		\
 				${SGI575_BASE}/sgi575_topology.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
@@ -56,12 +56,12 @@
 # Add the NT_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config,${NT_FW_CONFIG}))
 
-ifneq ($(CSS_SGI_CHIP_COUNT),1)
+ifneq ($(NRD_CHIP_COUNT),1)
  $(error  "Chip count for SGI575 should be 1, currently set to \
-   ${CSS_SGI_CHIP_COUNT}.")
+   ${NRD_CHIP_COUNT}.")
 endif
 
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
- $(error "CSS_SGI_PLATFORM_VARIANT for SGI575 should always be 0,\
-     currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+ifneq ($(NRD_PLATFORM_VARIANT),0)
+ $(error "NRD_PLATFORM_VARIANT for SGI575 should always be 0,\
+     currently set to ${NRD_PLATFORM_VARIANT}.")
 endif
diff --git a/plat/arm/board/sgi575/sgi575_err.c b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_err.c
similarity index 71%
rename from plat/arm/board/sgi575/sgi575_err.c
rename to plat/arm/board/neoverse_rd/platform/sgi575/sgi575_err.c
index 21bfcb7..7e656ab 100644
--- a/plat/arm/board/sgi575/sgi575_err.c
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_err.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_plat.c b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_plat.c
new file mode 100644
index 0000000..8b74616
--- /dev/null
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_plat.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <nrd_plat.h>
+#include <nrd_variant.h>
+
+unsigned int plat_arm_nrd_get_platform_id(void)
+{
+	return mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK;
+}
+
+unsigned int plat_arm_nrd_get_config_id(void)
+{
+	return (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT)
+			& SSC_VERSION_CONFIG_MASK;
+}
+
+unsigned int plat_arm_nrd_get_multi_chip_mode(void)
+{
+	return 0;
+}
+
+void bl31_platform_setup(void)
+{
+	nrd_bl31_common_platform_setup();
+}
diff --git a/plat/arm/board/sgi575/sgi575_security.c b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_security.c
similarity index 84%
rename from plat/arm/board/sgi575/sgi575_security.c
rename to plat/arm/board/neoverse_rd/platform/sgi575/sgi575_security.c
index 17d07d1..8b8a382 100644
--- a/plat/arm/board/sgi575/sgi575_security.c
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_security.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,7 +7,7 @@
 #include <platform_def.h>
 
 #include <common/debug.h>
-#include <sgi_dmc620_tzc_regions.h>
+#include <nrd_dmc620_tzc_regions.h>
 
 uintptr_t sgi575_dmc_base[] = {
 	SGI575_DMC620_BASE0,
@@ -20,7 +20,7 @@
 };
 
 static const tzc_dmc620_acc_addr_data_t sgi575_acc_addr_data[] = {
-	CSS_SGI_DMC620_TZC_REGIONS_DEF
+	NRD_DMC620_TZC_REGIONS_DEF
 };
 
 static const tzc_dmc620_config_data_t sgi575_plat_config_data = {
diff --git a/plat/arm/board/sgi575/sgi575_topology.c b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_topology.c
similarity index 89%
rename from plat/arm/board/sgi575/sgi575_topology.c
rename to plat/arm/board/neoverse_rd/platform/sgi575/sgi575_topology.c
index f7c3856..15ffc65 100644
--- a/plat/arm/board/sgi575/sgi575_topology.c
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_topology.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.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,8 +11,8 @@
  ******************************************************************************/
 static const unsigned char sgi575_pd_tree_desc[] = {
 	PLAT_ARM_CLUSTER_COUNT,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER
+	NRD_MAX_CPUS_PER_CLUSTER,
+	NRD_MAX_CPUS_PER_CLUSTER
 };
 
 /*******************************************************************************
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_trusted_boot.c
similarity index 88%
copy from plat/arm/board/rde1edge/rde1edge_trusted_boot.c
copy to plat/arm/board/neoverse_rd/platform/sgi575/sgi575_trusted_boot.c
index 4592b8f..84622d0 100644
--- a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
+++ b/plat/arm/board/neoverse_rd/platform/sgi575/sgi575_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts
deleted file mode 100644
index 69fb0d4..0000000
--- a/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <common/tbbr/tbbr_img_def.h>
-
-/dts-v1/;
-
-/ {
-	dtb-registry {
-		compatible = "fconf,dyn_cfg-dtb_registry";
-
-		tb_fw-config {
-			load-address = <0x0 0x4001300>;
-			max-size = <0x200>;
-			id = <TB_FW_CONFIG_ID>;
-		};
-
-		nt_fw-config {
-			load-address = <0x0 0xFEF00000>;
-			max-size = <0x0100000>;
-			id = <NT_FW_CONFIG_ID>;
-		};
-	};
-};
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
deleted file mode 100644
index 0af821e..0000000
--- a/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/dts-v1/;
-/ {
-	/* compatible string */
-	compatible = "arm,rd-e1edge";
-
-	/*
-	 * Place holder for system-id node with default values. The
-	 * value of platform-id and config-id will be set to the
-	 * correct values during the BL2 stage of boot.
-	 */
-	system-id {
-		platform-id = <0x0>;
-		config-id = <0x0>;
-		multi-chip-mode = <0x0>;
-	};
-
-};
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
deleted file mode 100644
index dba91e5..0000000
--- a/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/dts-v1/;
-
-/ {
-	tb_fw-config {
-		compatible = "arm,tb_fw";
-
-		/* Disable authentication for development */
-		disable_auth = <0x0>;
-
-		/*
-		 * The following two entries are placeholders for Mbed TLS
-		 * heap information. The default values don't matter since
-		 * they will be overwritten by BL1.
-		 * In case of having shared Mbed TLS heap between BL1 and BL2,
-		 * BL1 will populate these two properties with the respective
-		 * info about the shared heap. This info will be available for
-		 * BL2 in order to locate and re-use the heap.
-		 */
-		mbedtls_heap_addr = <0x0 0x0>;
-		mbedtls_heap_size = <0x0>;
-	};
-};
diff --git a/plat/arm/board/rde1edge/include/platform_def.h b/plat/arm/board/rde1edge/include/platform_def.h
deleted file mode 100644
index 69bfd7b..0000000
--- a/plat/arm/board/rde1edge/include/platform_def.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PLATFORM_DEF_H
-#define PLATFORM_DEF_H
-
-#include <lib/utils_def.h>
-
-#include <sgi_sdei.h>
-#include <sgi_soc_platform_def.h>
-
-#define PLAT_ARM_CLUSTER_COUNT		U(2)
-#define CSS_SGI_MAX_CPUS_PER_CLUSTER	U(8)
-#define CSS_SGI_MAX_PE_PER_CPU		U(2)
-
-#define PLAT_CSS_MHU_BASE		UL(0x45400000)
-
-/* Base address of DMC-620 instances */
-#define RDE1EDGE_DMC620_BASE0		UL(0x4e000000)
-#define RDE1EDGE_DMC620_BASE1		UL(0x4e100000)
-
-#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
-
-#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL3
-
-/* Maximum number of address bits used per chip */
-#define CSS_SGI_ADDR_BITS_PER_CHIP	U(36)
-
-/*
- * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
- */
-#ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
-#else
-#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
-#endif
-
-/* GIC related constants */
-#define PLAT_ARM_GICD_BASE		UL(0x30000000)
-#define PLAT_ARM_GICC_BASE		UL(0x2C000000)
-#define PLAT_ARM_GICR_BASE		UL(0x300C0000)
-
-#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rde1edge/platform.mk b/plat/arm/board/rde1edge/platform.mk
deleted file mode 100644
index 4a9a467..0000000
--- a/plat/arm/board/rde1edge/platform.mk
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Copyright (c) 2018-2023, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-$(warning Platform ${PLAT} is deprecated. \
-  Some of the features might not work as expected)
-
-include plat/arm/css/sgi/sgi-common.mk
-
-RDE1EDGE_BASE		=	plat/arm/board/rde1edge
-
-PLAT_INCLUDES		+=	-I${RDE1EDGE_BASE}/include/
-
-SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_e1.S
-
-PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c
-
-BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
-				${RDE1EDGE_BASE}/rde1edge_err.c
-
-BL2_SOURCES		+=	${RDE1EDGE_BASE}/rde1edge_plat.c	\
-				${RDE1EDGE_BASE}/rde1edge_security.c	\
-				${RDE1EDGE_BASE}/rde1edge_err.c		\
-				drivers/arm/tzc/tzc_dmc620.c		\
-				lib/utils/mem_region.c			\
-				plat/arm/common/arm_nor_psci_mem_protect.c
-
-BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
-				${RDE1EDGE_BASE}/rde1edge_plat.c	\
-				${RDE1EDGE_BASE}/rde1edge_topology.c	\
-				drivers/cfi/v2m/v2m_flash.c		\
-				lib/utils/mem_region.c			\
-				plat/arm/common/arm_nor_psci_mem_protect.c
-
-ifeq (${TRUSTED_BOARD_BOOT}, 1)
-BL1_SOURCES		+=	${RDE1EDGE_BASE}/rde1edge_trusted_boot.c
-BL2_SOURCES		+=	${RDE1EDGE_BASE}/rde1edge_trusted_boot.c
-endif
-
-# Add the FDT_SOURCES and options for Dynamic Config
-FDT_SOURCES		+=	${RDE1EDGE_BASE}/fdts/${PLAT}_fw_config.dts	\
-				${RDE1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
-FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
-TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
-
-# Add the FW_CONFIG to FIP and specify the same to certtool
-$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
-# Add the TB_FW_CONFIG to FIP and specify the same to certtool
-$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
-
-FDT_SOURCES		+=	${RDE1EDGE_BASE}/fdts/${PLAT}_nt_fw_config.dts
-NT_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
-
-# Add the NT_FW_CONFIG to FIP and specify the same to certtool
-$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config,${NT_FW_CONFIG}))
-
-ifneq ($(CSS_SGI_CHIP_COUNT),1)
- $(error  "Chip count for RDE1Edge should be 1, currently set to \
-   ${CSS_SGI_CHIP_COUNT}.")
-endif
-
-ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
- $(error "CSS_SGI_PLATFORM_VARIANT for RD-E1-Edge should always be 0, \
-     currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
-endif
-
-override CTX_INCLUDE_AARCH32_REGS	:= 0
diff --git a/plat/arm/board/rde1edge/rde1edge_err.c b/plat/arm/board/rde1edge/rde1edge_err.c
deleted file mode 100644
index c72c18c..0000000
--- a/plat/arm/board/rde1edge/rde1edge_err.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * rde1edge error handler
- */
-void __dead2 plat_arm_error_handler(int err)
-{
-	while (true) {
-		wfi();
-	}
-}
diff --git a/plat/arm/board/rde1edge/rde1edge_plat.c b/plat/arm/board/rde1edge/rde1edge_plat.c
deleted file mode 100644
index 44d818a..0000000
--- a/plat/arm/board/rde1edge/rde1edge_plat.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/common/platform.h>
-#include <sgi_plat.h>
-
-unsigned int plat_arm_sgi_get_platform_id(void)
-{
-	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
-				& SID_SYSTEM_ID_PART_NUM_MASK;
-}
-
-unsigned int plat_arm_sgi_get_config_id(void)
-{
-	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
-}
-
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
-{
-	return 0;
-}
-
-void bl31_platform_setup(void)
-{
-	sgi_bl31_common_platform_setup();
-}
diff --git a/plat/arm/board/rde1edge/rde1edge_security.c b/plat/arm/board/rde1edge/rde1edge_security.c
deleted file mode 100644
index 35f81d1..0000000
--- a/plat/arm/board/rde1edge/rde1edge_security.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <platform_def.h>
-
-#include <common/debug.h>
-#include <sgi_dmc620_tzc_regions.h>
-
-uintptr_t rde1edge_dmc_base[] = {
-	RDE1EDGE_DMC620_BASE0,
-	RDE1EDGE_DMC620_BASE1
-};
-
-static const tzc_dmc620_driver_data_t rde1edge_plat_driver_data = {
-	.dmc_base = rde1edge_dmc_base,
-	.dmc_count = ARRAY_SIZE(rde1edge_dmc_base)
-};
-
-static const tzc_dmc620_acc_addr_data_t rde1edge_acc_addr_data[] = {
-	CSS_SGI_DMC620_TZC_REGIONS_DEF
-};
-
-static const tzc_dmc620_config_data_t rde1edge_plat_config_data = {
-	.plat_drv_data = &rde1edge_plat_driver_data,
-	.plat_acc_addr_data = rde1edge_acc_addr_data,
-	.acc_addr_count = ARRAY_SIZE(rde1edge_acc_addr_data)
-};
-
-/* Initialize the secure environment */
-void plat_arm_security_setup(void)
-{
-	arm_tzc_dmc620_setup(&rde1edge_plat_config_data);
-}
diff --git a/plat/arm/board/rde1edge/rde1edge_topology.c b/plat/arm/board/rde1edge/rde1edge_topology.c
deleted file mode 100644
index 91cc37e..0000000
--- a/plat/arm/board/rde1edge/rde1edge_topology.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/******************************************************************************
- * The power domain tree descriptor. RD-E1-Edge platform consists of two
- * clusters with eight CPUs in each cluster. The CPUs are multi-threaded with
- * two threads per CPU.
- ******************************************************************************/
-static const unsigned char rde1edge_pd_tree_desc[] = {
-	CSS_SGI_CHIP_COUNT,
-	PLAT_ARM_CLUSTER_COUNT,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU,
-	CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU
-};
-
-/******************************************************************************
- * This function returns the topology tree information.
- ******************************************************************************/
-const unsigned char *plat_get_power_domain_tree_desc(void)
-{
-	return rde1edge_pd_tree_desc;
-}
-
-/*******************************************************************************
- * The array mapping platform core position (implemented by plat_my_core_pos())
- * to the SCMI power domain ID implemented by SCP.
- ******************************************************************************/
-const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
-	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-	16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
-};
diff --git a/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c b/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c
deleted file mode 100644
index 4592b8f..0000000
--- a/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * Return the ROTPK hash in the following ASN.1 structure in DER format:
- *
- * AlgorithmIdentifier  ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * DigestInfo ::= SEQUENCE {
- *     digestAlgorithm   AlgorithmIdentifier,
- *     digest            OCTET STRING
- * }
- */
-int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
-			unsigned int *flags)
-{
-	return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
-}
diff --git a/plat/arm/board/rdn2/include/rdn2_ras.h b/plat/arm/board/rdn2/include/rdn2_ras.h
deleted file mode 100644
index 1d9af60..0000000
--- a/plat/arm/board/rdn2/include/rdn2_ras.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef RDN2_RAS_H
-#define RDN2_RAS_H
-
-#include <sgi_ras.h>
-
-extern struct plat_sgi_ras_config ras_config;
-
-#endif /* RDN2_RAS_H */
diff --git a/plat/arm/board/rdn2/rdn2_security.c b/plat/arm/board/rdn2/rdn2_security.c
deleted file mode 100644
index 7cd4a1c..0000000
--- a/plat/arm/board/rdn2/rdn2_security.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <common/debug.h>
-#include <plat/arm/common/plat_arm.h>
-#include <platform_def.h>
-
-#define RDN2_TZC_CPER_REGION					\
-	{CSS_SGI_SP_CPER_BUF_BASE, (CSS_SGI_SP_CPER_BUF_BASE +	\
-	CSS_SGI_SP_CPER_BUF_SIZE) - 1, TZC_REGION_S_NONE,	\
-	PLAT_ARM_TZC_NS_DEV_ACCESS}
-
-static const arm_tzc_regions_info_t tzc_regions[] = {
-	ARM_TZC_REGIONS_DEF,
-#if ENABLE_FEAT_RAS && FFH_SUPPORT
-	RDN2_TZC_CPER_REGION,
-#endif
-	{}
-};
-
-#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
-static const arm_tzc_regions_info_t tzc_regions_mc[][CSS_SGI_CHIP_COUNT - 1] = {
-	{
-		/* TZC memory regions for second chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
-		{}
-	},
-#if CSS_SGI_CHIP_COUNT > 2
-	{
-		/* TZC memory regions for third chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
-		{}
-	},
-#endif
-#if CSS_SGI_CHIP_COUNT > 3
-	{
-		/* TZC memory regions for fourth chip */
-		SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
-		{}
-	},
-#endif
-};
-#endif /* CSS_SGI_PLATFORM_VARIANT && CSS_SGI_CHIP_COUNT */
-
-/* Initialize the secure environment */
-void plat_arm_security_setup(void)
-{
-	unsigned int i;
-
-	INFO("Configuring TrustZone Controller for Chip 0\n");
-
-	for (i = 0; i < TZC400_COUNT; i++) {
-		arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
-	}
-
-#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
-	unsigned int j;
-
-	for (i = 1; i < CSS_SGI_CHIP_COUNT; i++) {
-		INFO("Configuring TrustZone Controller for Chip %u\n", i);
-
-		for (j = 0; j < TZC400_COUNT; j++) {
-			arm_tzc400_setup(CSS_SGI_REMOTE_CHIP_MEM_OFFSET(i)
-				+ TZC400_BASE(j), tzc_regions_mc[i-1]);
-		}
-	}
-#endif
-}
diff --git a/plat/arm/board/rdn2/rdn2_trusted_boot.c b/plat/arm/board/rdn2/rdn2_trusted_boot.c
deleted file mode 100644
index 4592b8f..0000000
--- a/plat/arm/board/rdn2/rdn2_trusted_boot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * Return the ROTPK hash in the following ASN.1 structure in DER format:
- *
- * AlgorithmIdentifier  ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * DigestInfo ::= SEQUENCE {
- *     digestAlgorithm   AlgorithmIdentifier,
- *     digest            OCTET STRING
- * }
- */
-int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
-			unsigned int *flags)
-{
-	return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
-}
diff --git a/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts b/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts
deleted file mode 100644
index 9c9cefe..0000000
--- a/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <common/tbbr/tbbr_img_def.h>
-
-/dts-v1/;
-
-/ {
-	dtb-registry {
-		compatible = "fconf,dyn_cfg-dtb_registry";
-
-		tb_fw-config {
-			load-address = <0x0 0x4001300>;
-			max-size = <0x200>;
-			id = <TB_FW_CONFIG_ID>;
-		};
-
-		nt_fw-config {
-			load-address = <0x0 0xFEF00000>;
-			max-size = <0x0100000>;
-			id = <NT_FW_CONFIG_ID>;
-		};
-	};
-};
diff --git a/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts b/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts
deleted file mode 100644
index 49eda27..0000000
--- a/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/dts-v1/;
-
-/ {
-	tb_fw-config {
-		compatible = "arm,tb_fw";
-
-		/* Disable authentication for development */
-		disable_auth = <0x0>;
-
-		/*
-		 * The following two entries are placeholders for Mbed TLS
-		 * heap information. The default values don't matter since
-		 * they will be overwritten by BL1.
-		 * In case of having shared Mbed TLS heap between BL1 and BL2,
-		 * BL1 will populate these two properties with the respective
-		 * info about the shared heap. This info will be available for
-		 * BL2 in order to locate and re-use the heap.
-		 */
-		mbedtls_heap_addr = <0x0 0x0>;
-		mbedtls_heap_size = <0x0>;
-	};
-};
diff --git a/plat/arm/board/rdv1/rdv1_plat.c b/plat/arm/board/rdv1/rdv1_plat.c
deleted file mode 100644
index ab5251e..0000000
--- a/plat/arm/board/rdv1/rdv1_plat.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/common/platform.h>
-#include <sgi_plat.h>
-
-unsigned int plat_arm_sgi_get_platform_id(void)
-{
-	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
-				& SID_SYSTEM_ID_PART_NUM_MASK;
-}
-
-unsigned int plat_arm_sgi_get_config_id(void)
-{
-	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
-}
-
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
-{
-	return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
-			SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
-}
-
-void bl31_platform_setup(void)
-{
-	sgi_bl31_common_platform_setup();
-}
diff --git a/plat/arm/board/rdv1/rdv1_trusted_boot.c b/plat/arm/board/rdv1/rdv1_trusted_boot.c
deleted file mode 100644
index 4592b8f..0000000
--- a/plat/arm/board/rdv1/rdv1_trusted_boot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * Return the ROTPK hash in the following ASN.1 structure in DER format:
- *
- * AlgorithmIdentifier  ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * DigestInfo ::= SEQUENCE {
- *     digestAlgorithm   AlgorithmIdentifier,
- *     digest            OCTET STRING
- * }
- */
-int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
-			unsigned int *flags)
-{
-	return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
-}
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts b/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts
deleted file mode 100644
index 9c9cefe..0000000
--- a/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <common/tbbr/tbbr_img_def.h>
-
-/dts-v1/;
-
-/ {
-	dtb-registry {
-		compatible = "fconf,dyn_cfg-dtb_registry";
-
-		tb_fw-config {
-			load-address = <0x0 0x4001300>;
-			max-size = <0x200>;
-			id = <TB_FW_CONFIG_ID>;
-		};
-
-		nt_fw-config {
-			load-address = <0x0 0xFEF00000>;
-			max-size = <0x0100000>;
-			id = <NT_FW_CONFIG_ID>;
-		};
-	};
-};
diff --git a/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c b/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c
deleted file mode 100644
index 4592b8f..0000000
--- a/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * Return the ROTPK hash in the following ASN.1 structure in DER format:
- *
- * AlgorithmIdentifier  ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * DigestInfo ::= SEQUENCE {
- *     digestAlgorithm   AlgorithmIdentifier,
- *     digest            OCTET STRING
- * }
- */
-int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
-			unsigned int *flags)
-{
-	return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
-}
diff --git a/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts
deleted file mode 100644
index 84fc1ad..0000000
--- a/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <common/tbbr/tbbr_img_def.h>
-
-/dts-v1/;
-
-/ {
-	dtb-registry {
-		compatible = "fconf,dyn_cfg-dtb_registry";
-
-		tb_fw-config {
-			load-address = <0x0 0x4001300>;
-			max-size = <0x200>;
-			id = <TB_FW_CONFIG_ID>;
-		};
-
-		nt_fw-config {
-			load-address = <0x0 0xFEF00000>;
-			max-size = <0x0100000>;
-			id = <NT_FW_CONFIG_ID>;
-		};
-	};
-};
diff --git a/plat/arm/board/sgi575/sgi575_plat.c b/plat/arm/board/sgi575/sgi575_plat.c
deleted file mode 100644
index dc294e6..0000000
--- a/plat/arm/board/sgi575/sgi575_plat.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/common/platform.h>
-#include <sgi_plat.h>
-#include <sgi_variant.h>
-
-unsigned int plat_arm_sgi_get_platform_id(void)
-{
-	return mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK;
-}
-
-unsigned int plat_arm_sgi_get_config_id(void)
-{
-	return (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT)
-			& SSC_VERSION_CONFIG_MASK;
-}
-
-unsigned int plat_arm_sgi_get_multi_chip_mode(void)
-{
-	return 0;
-}
-
-void bl31_platform_setup(void)
-{
-	sgi_bl31_common_platform_setup();
-}
diff --git a/plat/arm/board/sgi575/sgi575_trusted_boot.c b/plat/arm/board/sgi575/sgi575_trusted_boot.c
deleted file mode 100644
index 4592b8f..0000000
--- a/plat/arm/board/sgi575/sgi575_trusted_boot.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <plat/arm/common/plat_arm.h>
-
-/*
- * Return the ROTPK hash in the following ASN.1 structure in DER format:
- *
- * AlgorithmIdentifier  ::=  SEQUENCE  {
- *     algorithm         OBJECT IDENTIFIER,
- *     parameters        ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * DigestInfo ::= SEQUENCE {
- *     digestAlgorithm   AlgorithmIdentifier,
- *     digest            OCTET STRING
- * }
- */
-int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
-			unsigned int *flags)
-{
-	return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
-}
diff --git a/plat/arm/board/tc/fdts/dice_prot_env.dtsi b/plat/arm/board/tc/fdts/dice_prot_env.dtsi
new file mode 100644
index 0000000..118f995
--- /dev/null
+++ b/plat/arm/board/tc/fdts/dice_prot_env.dtsi
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* DICE Protection Environment Client Config */
+dice_protection_environment: context_handle {
+	compatible = "arm,dpe_ctx_handle";
+	dpe_ctx_handle = <0x0>;
+};
diff --git a/plat/arm/board/tc/fdts/tc_fw_config.dts b/plat/arm/board/tc/fdts/tc_fw_config.dts
index 982da5b..b210e75 100644
--- a/plat/arm/board/tc/fdts/tc_fw_config.dts
+++ b/plat/arm/board/tc/fdts/tc_fw_config.dts
@@ -30,5 +30,10 @@
 			max-size = <PLAT_HW_CONFIG_DTB_SIZE>;
 			id = <HW_CONFIG_ID>;
 		};
+		nt_fw-config {
+			load-address = <0x0 (PLAT_HW_CONFIG_DTB_BASE + PLAT_HW_CONFIG_DTB_SIZE)>;
+			max-size = <0x1000>;
+			id = <NT_FW_CONFIG_ID>;
+		};
 	};
 };
diff --git a/plat/arm/board/tc/fdts/tc_nt_fw_config.dts b/plat/arm/board/tc/fdts/tc_nt_fw_config.dts
new file mode 100644
index 0000000..bb3086d
--- /dev/null
+++ b/plat/arm/board/tc/fdts/tc_nt_fw_config.dts
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+#if DICE_PROTECTION_ENVIRONMENT
+	#include "dice_prot_env.dtsi"
+#endif
+};
diff --git a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
index c58f17b..cb741a3 100644
--- a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
+++ b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
@@ -82,4 +82,7 @@
 #endif
 #endif /* ARM_BL2_SP_LIST_DTS */
 	};
+#if DICE_PROTECTION_ENVIRONMENT
+	#include "dice_prot_env.dtsi"
+#endif
 };
diff --git a/plat/arm/board/tc/include/platform_def.h b/plat/arm/board/tc/include/platform_def.h
index a42e39d..f7a4807 100644
--- a/plat/arm/board/tc/include/platform_def.h
+++ b/plat/arm/board/tc/include/platform_def.h
@@ -32,6 +32,9 @@
  *               |       DTB      |
  *               |      (32K)     |
  *  0x8000_8000  ------------------
+ *               | NT_FW_CONFIG   |
+ *               |      (4KB)     |
+ *  0x8000_9000  ------------------
  *               |       ...      |
  *  0xf8a0_0000  ------------------   TC_NS_FWU_BASE
  *               |    FWU shmem   |
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 652a17e..2f23d80 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -137,14 +137,18 @@
 
 # Add the FDT_SOURCES and options for Dynamic Config
 FDT_SOURCES		+=	${TC_BASE}/fdts/${PLAT}_fw_config.dts	\
-				${TC_BASE}/fdts/${PLAT}_tb_fw_config.dts
+				${TC_BASE}/fdts/${PLAT}_tb_fw_config.dts \
+				${TC_BASE}/fdts/${PLAT}_nt_fw_config.dts
 FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
 TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+FVP_NT_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
 
 # Add the FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
 # Add the TB_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_NT_FW_CONFIG},--nt-fw-config,${FVP_NT_FW_CONFIG}))
 
 ifeq (${SPD},spmd)
 ifeq ($(ARM_SPMC_MANIFEST_DTS),)
@@ -170,27 +174,56 @@
 # Include Measured Boot makefile before any Crypto library makefile.
 # Crypto library makefile may need default definitions of Measured Boot build
 # flags present in Measured Boot makefile.
+$(info Including rss_comms.mk)
 ifeq (${MEASURED_BOOT},1)
-    MEASURED_BOOT_MK := drivers/measured_boot/rss/rss_measured_boot.mk
-    $(info Including ${MEASURED_BOOT_MK})
-    include ${MEASURED_BOOT_MK}
-    $(info Including rss_comms.mk)
-    include drivers/arm/rss/rss_comms.mk
+        $(info Including rss_comms.mk)
+        include drivers/arm/rss/rss_comms.mk
 
-    BL1_SOURCES		+=	${MEASURED_BOOT_SOURCES} \
+	BL1_SOURCES	+=	${RSS_COMMS_SOURCES}
+	BL2_SOURCES	+=	${RSS_COMMS_SOURCES}
+	PLAT_INCLUDES	+=	-Iinclude/lib/psa
+
+    ifeq (${DICE_PROTECTION_ENVIRONMENT},1)
+        $(info Including qcbor.mk)
+        include drivers/measured_boot/rss/qcbor.mk
+        $(info Including dice_prot_env.mk)
+        include drivers/measured_boot/rss/dice_prot_env.mk
+
+	BL1_SOURCES	+=	${QCBOR_SOURCES} \
+				${DPE_SOURCES} \
+				plat/arm/board/tc/tc_common_dpe.c \
+				plat/arm/board/tc/tc_bl1_dpe.c \
+				lib/psa/dice_protection_environment.c \
+				drivers/arm/css/sds/sds.c \
+				drivers/delay_timer/delay_timer.c \
+				drivers/delay_timer/generic_delay_timer.c
+
+	BL2_SOURCES	+=	${QCBOR_SOURCES} \
+				${DPE_SOURCES} \
+				plat/arm/board/tc/tc_common_dpe.c \
+				plat/arm/board/tc/tc_bl2_dpe.c \
+				lib/psa/dice_protection_environment.c
+
+	PLAT_INCLUDES	+=	-I${QCBOR_INCLUDES} \
+				-Iinclude/lib/dice
+    else
+        $(info Including rss_measured_boot.mk)
+        include drivers/measured_boot/rss/rss_measured_boot.mk
+
+	BL1_SOURCES	+=	${MEASURED_BOOT_SOURCES} \
 				plat/arm/board/tc/tc_common_measured_boot.c \
 				plat/arm/board/tc/tc_bl1_measured_boot.c \
-				lib/psa/measured_boot.c			 \
-				${RSS_COMMS_SOURCES}
+				lib/psa/measured_boot.c
 
-    BL2_SOURCES		+=	${MEASURED_BOOT_SOURCES} \
+	BL2_SOURCES		+=	${MEASURED_BOOT_SOURCES} \
 				plat/arm/board/tc/tc_common_measured_boot.c \
 				plat/arm/board/tc/tc_bl2_measured_boot.c \
-				lib/psa/measured_boot.c			 \
-				${RSS_COMMS_SOURCES}
-
-PLAT_INCLUDES		+=	-Iinclude/lib/psa
+				lib/psa/measured_boot.c
+    endif
+endif
 
+ifeq (${TRNG_SUPPORT},1)
+	BL31_SOURCES	+=	plat/arm/board/tc/tc_trng.c
 endif
 
 ifneq (${PLATFORM_TEST},)
diff --git a/plat/arm/board/tc/tc_bl1_dpe.c b/plat/arm/board/tc/tc_bl1_dpe.c
new file mode 100644
index 0000000..dc60fb6
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl1_dpe.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/arm/rss_comms.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/measured_boot/rss/dice_prot_env.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/zero_oid.h>
+
+#include "tc_dpe_cert.h"
+
+struct dpe_metadata tc_dpe_metadata[] = {
+	{
+		.id = FW_CONFIG_ID,
+		.cert_id = DPE_AP_FW_CERT_ID,
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_FW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = ZERO_OID },
+	{
+		.id = TB_FW_CONFIG_ID,
+		.cert_id = DPE_AP_FW_CERT_ID,
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_TB_FW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = ZERO_OID },
+	{
+		.id = BL2_IMAGE_ID,
+		.cert_id = DPE_AP_FW_CERT_ID,
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_BL2_IMAGE_STRING,
+		.allow_new_context_to_derive = true,
+		.retain_parent_context = false,
+		.create_certificate = false,
+		.pk_oid = ZERO_OID },
+	{
+		.id = DPE_INVALID_ID }
+};
+
+/* Effective timeout of 10000 ms */
+#define RSS_DPE_BOOT_10US_RETRIES		1000000
+#define TC2_SDS_DPE_CTX_HANDLE_STRUCT_ID	0x0000000A
+
+/* Context handle is meant to be used by BL2. Sharing it via TB_FW_CONFIG */
+static int new_ctx_handle;
+
+void plat_dpe_share_context_handle(int *ctx_handle)
+{
+	new_ctx_handle = *ctx_handle;
+}
+
+void plat_dpe_get_context_handle(int *ctx_handle)
+{
+	int retry = RSS_DPE_BOOT_10US_RETRIES;
+	int ret;
+
+	/* Initialize System level generic or SP804 timer */
+	generic_delay_timer_init();
+
+	/* Check the initialization of the Shared Data Storage area between RSS
+	 * and AP. Since AP_BL1 is executed first then a bit later the RSS
+	 * runtime, which initialize this area, therefore AP needs to check it
+	 * in a loop until it gets written by RSS Secure Runtime.
+	 */
+	VERBOSE("Waiting for DPE service initialization in RSS Secure Runtime\n");
+	while (retry > 0) {
+		ret = sds_init(SDS_RSS_AP_REGION_ID);
+		if (ret != SDS_OK) {
+			udelay(10);
+			retry--;
+		} else {
+			break;
+		}
+	}
+
+	if (retry == 0) {
+		ERROR("DPE init timeout\n");
+		plat_panic_handler();
+	} else {
+		VERBOSE("DPE init succeeded in %dms.\n",
+			(RSS_DPE_BOOT_10US_RETRIES - retry) / 100);
+	}
+
+	/* TODO: call this in a loop to avoid reading unfinished data */
+	ret = sds_struct_read(SDS_RSS_AP_REGION_ID,
+			      TC2_SDS_DPE_CTX_HANDLE_STRUCT_ID,
+			      0,
+			      ctx_handle,
+			      sizeof(*ctx_handle),
+			      SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Unable to get DPE context handle from SDS area\n");
+		plat_panic_handler();
+	}
+
+	VERBOSE("Received DPE context handle: 0x%x\n", *ctx_handle);
+}
+
+void bl1_plat_mboot_init(void)
+{
+	/* Initialize the communication channel between AP and RSS */
+	(void)rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE,
+			     PLAT_RSS_AP_RCV_MHU_BASE);
+
+	dpe_init(tc_dpe_metadata);
+}
+
+void bl1_plat_mboot_finish(void)
+{
+	int rc;
+
+	VERBOSE("Share DPE context handle with BL2: 0x%x\n", new_ctx_handle);
+	rc = arm_set_tb_fw_info(&new_ctx_handle);
+	if (rc != 0) {
+		ERROR("Unable to set DPE context handle in TB_FW_CONFIG\n");
+		/*
+		 * It is a fatal error because on TC platform, BL2 software
+		 * assumes that a valid DPE context_handle is passed through
+		 * the DTB object by BL1.
+		 */
+		plat_panic_handler();
+	}
+}
diff --git a/plat/arm/board/tc/tc_bl1_measured_boot.c b/plat/arm/board/tc/tc_bl1_measured_boot.c
index 6821a6a..2e58954 100644
--- a/plat/arm/board/tc/tc_bl1_measured_boot.c
+++ b/plat/arm/board/tc/tc_bl1_measured_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,8 +7,8 @@
 #include <stdint.h>
 
 #include <drivers/arm/rss_comms.h>
+#include <drivers/measured_boot/metadata.h>
 #include <drivers/measured_boot/rss/rss_measured_boot.h>
-#include <lib/psa/measured_boot.h>
 #include <tools_share/zero_oid.h>
 
 #include <plat/arm/common/plat_arm.h>
@@ -22,21 +22,21 @@
 		.id = FW_CONFIG_ID,
 		.slot = U(6),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_FW_CONFIG_STRING,
+		.sw_type = MBOOT_FW_CONFIG_STRING,
 		.pk_oid = ZERO_OID,
 		.lock_measurement = true },
 	{
 		.id = TB_FW_CONFIG_ID,
 		.slot = U(7),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_TB_FW_CONFIG_STRING,
+		.sw_type = MBOOT_TB_FW_CONFIG_STRING,
 		.pk_oid = ZERO_OID,
 		.lock_measurement = true },
 	{
 		.id = BL2_IMAGE_ID,
 		.slot = U(8),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_BL2_STRING,
+		.sw_type = MBOOT_BL2_IMAGE_STRING,
 		.pk_oid = ZERO_OID,
 		.lock_measurement = true },
 
diff --git a/plat/arm/board/tc/tc_bl2_dpe.c b/plat/arm/board/tc/tc_bl2_dpe.c
new file mode 100644
index 0000000..e50508f
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl2_dpe.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/arm/rss_comms.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/measured_boot/rss/dice_prot_env.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/tbbr_oid.h>
+
+#include "tc_dpe_cert.h"
+
+/*
+ * The content and the values of this array depends on:
+ * - build config: Which components are loaded: SPMD, TOS, SPx, etc ?
+ * - boot order: the last element in a layer should be treated differently.
+ */
+
+/*
+ * TODO:
+ *     - The content of the array must be tailored according to the build
+ *       config (TOS, SPMD, etc). All loaded components (executables and
+ *       config blobs) must be present in this array.
+ *     - Current content is according to the Trusty build config.
+ */
+struct dpe_metadata tc_dpe_metadata[] = {
+	{
+		.id = BL31_IMAGE_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_BL31_IMAGE_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = BL31_IMAGE_KEY_OID },
+	{
+		.id = BL32_IMAGE_ID,
+		.cert_id =  DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_BL32_IMAGE_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = BL32_IMAGE_KEY_OID },
+	{
+		.id = BL33_IMAGE_ID,
+		.cert_id = DPE_HYPERVISOR_CERT_ID,
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_BL33_IMAGE_STRING,
+		.allow_new_context_to_derive = true,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = BL33_IMAGE_KEY_OID },
+
+	{
+		.id = HW_CONFIG_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_HW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = HW_CONFIG_KEY_OID },
+	{
+		.id = NT_FW_CONFIG_ID,
+		.cert_id = DPE_HYPERVISOR_CERT_ID,
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_NT_FW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NT_FW_CONFIG_KEY_OID },
+	{
+		.id = SCP_BL2_IMAGE_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SCP_BL2_IMAGE_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = SCP_BL2_IMAGE_KEY_OID },
+	{
+		.id = SOC_FW_CONFIG_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SOC_FW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = SOC_FW_CONFIG_KEY_OID },
+	{
+		.id = TOS_FW_CONFIG_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_TOS_FW_CONFIG_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = TOS_FW_CONFIG_KEY_OID },
+#if defined(SPD_spmd)
+	{
+		.id = SP_PKG1_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP1_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = true, /* With Trusty only one SP is loaded */
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG2_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP2_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG3_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP3_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG4_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP4_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG5_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP5_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG6_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP6_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG7_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP7_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+	{
+		.id = SP_PKG8_ID,
+		.cert_id = DPE_CERT_ID_SAME_AS_PARENT, /* AP_BL2: DPE_AP_FW_CERT_ID */
+		.signer_id_size = SIGNER_ID_MIN_SIZE,
+		.sw_type = MBOOT_SP8_STRING,
+		.allow_new_context_to_derive = false,
+		.retain_parent_context = true,
+		.create_certificate = false,
+		.pk_oid = NULL },
+
+#endif
+	{
+		.id = DPE_INVALID_ID }
+};
+
+/* Context handle is meant to be used by BL33. Sharing it via NT_FW_CONFIG */
+static int new_ctx_handle;
+
+void plat_dpe_share_context_handle(int *ctx_handle)
+{
+	new_ctx_handle = *ctx_handle;
+}
+
+void plat_dpe_get_context_handle(int *ctx_handle)
+{
+	int rc;
+
+	rc = arm_get_tb_fw_info(ctx_handle);
+	if (rc != 0) {
+		ERROR("Unable to get DPE context handle from TB_FW_CONFIG\n");
+		/*
+		 * It is a fatal error because on FVP platform, BL2 software
+		 * assumes that a valid DPE context_handle is passed through
+		 * the DTB object by BL1.
+		 */
+		plat_panic_handler();
+	}
+
+	VERBOSE("Received DPE context handle: 0x%x\n", *ctx_handle);
+}
+
+void bl2_plat_mboot_init(void)
+{
+	/* Initialize the communication channel between AP and RSS */
+	(void)rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE,
+			     PLAT_RSS_AP_RCV_MHU_BASE);
+
+	dpe_init(tc_dpe_metadata);
+}
+
+void bl2_plat_mboot_finish(void)
+{
+	int rc;
+
+	VERBOSE("Share DPE context handle with BL33: 0x%x\n", new_ctx_handle);
+	rc = arm_set_nt_fw_info(&new_ctx_handle);
+	if (rc != 0) {
+		ERROR("Unable to set DPE context handle in NT_FW_CONFIG\n");
+		/*
+		 * It is a fatal error because on TC platform, BL33 software
+		 * assumes that a valid DPE context_handle is passed through
+		 * the DTB object by BL2.
+		 */
+		plat_panic_handler();
+	}
+}
diff --git a/plat/arm/board/tc/tc_bl2_measured_boot.c b/plat/arm/board/tc/tc_bl2_measured_boot.c
index 4b79170..fd80fdc 100644
--- a/plat/arm/board/tc/tc_bl2_measured_boot.c
+++ b/plat/arm/board/tc/tc_bl2_measured_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,8 +7,8 @@
 #include <stdint.h>
 
 #include <drivers/arm/rss_comms.h>
+#include <drivers/measured_boot/metadata.h>
 #include <drivers/measured_boot/rss/rss_measured_boot.h>
-#include <lib/psa/measured_boot.h>
 #include <tools_share/tbbr_oid.h>
 
 #include <plat/common/common_def.h>
@@ -22,21 +22,21 @@
 		.id = BL31_IMAGE_ID,
 		.slot = U(9),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_BL31_STRING,
+		.sw_type = MBOOT_BL31_IMAGE_STRING,
 		.pk_oid = BL31_IMAGE_KEY_OID,
 		.lock_measurement = true },
 	{
 		.id = HW_CONFIG_ID,
 		.slot = U(10),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_HW_CONFIG_STRING,
+		.sw_type = MBOOT_HW_CONFIG_STRING,
 		.pk_oid = HW_CONFIG_KEY_OID,
 		.lock_measurement = true },
 	{
 		.id = SOC_FW_CONFIG_ID,
 		.slot = U(11),
 		.signer_id_size = SIGNER_ID_MIN_SIZE,
-		.sw_type = RSS_MBOOT_SOC_FW_CONFIG_STRING,
+		.sw_type = MBOOT_SOC_FW_CONFIG_STRING,
 		.pk_oid = SOC_FW_CONFIG_KEY_OID,
 		.lock_measurement = true },
 	{
diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c
index d884366..5742d07 100644
--- a/plat/arm/board/tc/tc_bl31_setup.c
+++ b/plat/arm/board/tc/tc_bl31_setup.c
@@ -75,25 +75,6 @@
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 				u_register_t arg2, u_register_t arg3)
 {
-	/*
-	 * Pass the hw_config to BL33 in R0. You'll notice that
-	 * arm_bl31_early_platform_setup does something similar but only behind
-	 * ARM_LINUX_KERNEL_AS_BL33 and we want to pass the DTB even to a
-	 * bootloader. Lucky for us, it copies the ep_info BL2 gave us to BL33
-	 * unconditionally in the generic case so hijack that.
-	 * TODO: this goes away with firmware handoff when it will be proper
-	 */
-
-	bl_params_node_t *bl_params = ((bl_params_t *)arg0)->head;
-
-	while (bl_params != NULL) {
-		if (bl_params->image_id == BL33_IMAGE_ID) {
-			bl_params->ep_info->args.arg0 = arg2;
-			break;
-		}
-		bl_params = bl_params->next_params_info;
-	}
-
 	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
 
 	/* Fill the properties struct with the info from the config dtb */
@@ -154,10 +135,10 @@
 #if defined(SPD_spmd) && (SPMC_AT_EL3 == 0)
 void tc_bl31_plat_runtime_setup(void)
 {
-	arm_bl31_plat_runtime_setup();
-
 	/* Start secure watchdog timer. */
 	plat_arm_secure_wdt_start();
+
+	arm_bl31_plat_runtime_setup();
 }
 
 void bl31_plat_runtime_setup(void)
diff --git a/plat/arm/board/tc/tc_common_dpe.c b/plat/arm/board/tc/tc_common_dpe.c
new file mode 100644
index 0000000..42b5468
--- /dev/null
+++ b/plat/arm/board/tc/tc_common_dpe.c
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <drivers/measured_boot/rss/dice_prot_env.h>
+
+extern struct dpe_metadata tc_dpe_metadata[];
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+	int err;
+
+	/* Calculate image hash and record it in the DPE service in RSS. */
+	err = dpe_measure_and_record(tc_dpe_metadata,
+				     image_data->image_base,
+				     image_data->image_size,
+				     image_id);
+	if (err != 0) {
+		ERROR("%s%s image id %u (%i)\n",
+		      "Failed to ", "record in DPE", image_id, err);
+	}
+
+	return err;
+}
+
+int plat_mboot_measure_key(void *pk_oid, void *pk_ptr, unsigned int pk_len)
+{
+	return dpe_set_signer_id(tc_dpe_metadata, pk_oid, pk_ptr, pk_len);
+}
diff --git a/plat/arm/board/tc/tc_dpe_cert.h b/plat/arm/board/tc/tc_dpe_cert.h
new file mode 100644
index 0000000..25855ec
--- /dev/null
+++ b/plat/arm/board/tc/tc_dpe_cert.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TC_DPE_CERT_H
+#define TC_DPE_CERT_H
+
+/*
+ * The certificate structure on the TC platform:
+ *   - The arrows indicate the parent/child relationships (who loads who).
+ *   - The boxes indicate the certificates.
+ *
+ *                                                                  AP FW Cert.
+ *                                                      +--------------------------------+
+ *                                                      |                                |
+ *                             Plat Cert.               |                +->SPx          |           Hyper Cert.
+ *                     +--------------------------+     |                +->SP1          |     +--------------------+
+ *     RoT Cert.       |                          |     |                +->TOS_FW_CONF  |     |                    |
+ *  +------------+     |      +->SCP_BL1    +-----+-----+-->FW_CONF      +->AP_BL32      |     |     +->PVMFW       |
+ *  |            |     |      |             |     |     |                |               |     |     |              |
+ *  | RSS_BL1_2--+-----+-->RSS_BL2------->AP_BL1--+-----+------------->AP_BL2------------+-----+-->AP_BL33          |
+ *  |            |     |      |             |     |     |                |               |     |     |              |
+ *  +------------+     |      +->RSS_S      +-----+-----+-->TB_FW_CONF   +->AP_BL31      |     |     +->HYPERVISOR  |
+ *                     |      +->RSS_NS           |     |                +->SCP_BL2      |     |                    |
+ *                     |                          |     |                +->HW_CONF      |     |                    |
+ *                     +--------------------------+     |                +---------------+-----+-->NT_FW_CONF       |
+ *                                                      |                                |     |                    |
+ *                                                      +--------------------------------+     +--------------------+
+ */
+
+#define DPE_AP_FW_CERT_ID		0x300 /* Includes: FW_CONF - SP1 */
+#define DPE_HYPERVISOR_CERT_ID		0x400 /* Includes: AP_BL33 - PVMFW */
+
+/* Common definition */
+#define DPE_CERT_ID_SAME_AS_PARENT	0xFFFFFFFF
+
+#endif /* TC_DPE_CERT_H */
diff --git a/plat/arm/board/tc/tc_trng.c b/plat/arm/board/tc/tc_trng.c
new file mode 100644
index 0000000..e5ec48a
--- /dev/null
+++ b/plat/arm/board/tc/tc_trng.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2024, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arm_acle.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/trng_svc.h>
+#include <smccc_helpers.h>
+
+DEFINE_SVC_UUID2(_plat_trng_uuid,
+	0x23523c58, 0x7448, 0x4083, 0x9d, 0x16,
+	0xe3, 0xfa, 0xb9, 0xf1, 0x73, 0xbc
+);
+uuid_t plat_trng_uuid;
+
+/* Dummy implementation */
+bool plat_get_entropy(uint64_t *out)
+{
+	*out = 0xABBAEDDAACDCDEAD;
+
+	return true;
+}
+
+void plat_entropy_setup(void)
+{
+	uint64_t dummy;
+
+	plat_trng_uuid = _plat_trng_uuid;
+
+	/* Initialise the entropy source and trigger RNG generation */
+	plat_get_entropy(&dummy);
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 8e90615..33043b7 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_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
  */
@@ -325,12 +325,9 @@
 /*******************************************************************************
  * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
  * standard platforms
- * Perform BL31 platform setup
  ******************************************************************************/
 void arm_bl31_plat_runtime_setup(void)
 {
-	console_switch_state(CONSOLE_FLAG_RUNTIME);
-
 	/* Initialize the runtime console */
 	arm_console_runtime_init();
 
@@ -394,6 +391,9 @@
 void bl31_plat_runtime_setup(void)
 {
 	arm_bl31_plat_runtime_setup();
+
+	console_flush();
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
 }
 
 /*******************************************************************************
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
index 5dc1115..d13be99 100644
--- a/plat/arm/common/arm_dyn_cfg_helpers.c
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -124,6 +124,150 @@
 }
 
 #if MEASURED_BOOT
+#if DICE_PROTECTION_ENVIRONMENT
+
+#include <common/desc_image_load.h>
+
+#define DTB_PROP_DPE_CTX_HANDLE		"dpe_ctx_handle"
+
+static int arm_set_dpe_context_handle(uintptr_t config_base,
+				      int *ctx_handle)
+{
+	/* As libfdt uses void *, we can't avoid this cast */
+	void *dtb = (void *)config_base;
+	const char *compatible = "arm,dpe_ctx_handle";
+	int err, node;
+
+	/*
+	 * Verify that the DTB is valid, before attempting to write to it,
+	 * and get the DTB root node.
+	 */
+
+	/* Check if the pointer to DT is correct */
+	err = fdt_check_header(dtb);
+	if (err < 0) {
+		WARN("Invalid DTB file passed\n");
+		return err;
+	}
+
+	/* Assert the node offset point to compatible property */
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
+	if (node < 0) {
+		WARN("The compatible property '%s' not%s", compatible,
+			" found in the config\n");
+		return node;
+	}
+
+	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
+
+	err = fdtw_write_inplace_cells(dtb, node,
+		DTB_PROP_DPE_CTX_HANDLE, 1, ctx_handle);
+	if (err < 0) {
+		ERROR("%sDTB property '%s'\n",
+			"Unable to write ", DTB_PROP_DPE_CTX_HANDLE);
+	} else {
+		/*
+		 * Ensure that the info written to the DTB is visible
+		 * to other images.
+		 */
+		flush_dcache_range(config_base, fdt_totalsize(dtb));
+	}
+
+	return err;
+}
+
+/*
+ * This function writes the DPE context handle value to the NT_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *	0 = success
+ *    < 0 = error
+ */
+int arm_set_nt_fw_info(int *ctx_handle)
+{
+	uintptr_t config_base;
+	const bl_mem_params_node_t *cfg_mem_params;
+
+	/* Get the config load address and size from NT_FW_CONFIG */
+	cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+	assert(cfg_mem_params != NULL);
+
+	config_base = cfg_mem_params->image_info.image_base;
+
+	/* Write the context handle value in the DTB */
+	return arm_set_dpe_context_handle(config_base, ctx_handle);
+}
+
+/*
+ * This function writes the DPE context handle value to the TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL1.
+ *
+ * Returns:
+ *	0 = success
+ *    < 0 = error
+ */
+int arm_set_tb_fw_info(int *ctx_handle)
+{
+	/*
+	 * Read tb_fw_config device tree for Event Log properties
+	 * and write the Event Log address and its size in the DTB
+	 */
+	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+	uintptr_t tb_fw_cfg_dtb;
+
+	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+	assert(tb_fw_config_info != NULL);
+
+	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
+
+	/* Write the context handle value in the DTB */
+	return arm_set_dpe_context_handle(tb_fw_cfg_dtb, ctx_handle);
+}
+
+/*
+ * This function reads the initial DPE context handle from TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *	0 = success
+ *    < 0 = error
+ */
+
+int arm_get_tb_fw_info(int *ctx_handle)
+{
+	/* As libfdt uses void *, we can't avoid this cast */
+	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+	int node, rc;
+
+	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+	assert(tb_fw_config_info != NULL);
+
+	void *dtb = (void *)tb_fw_config_info->config_addr;
+	const char *compatible = "arm,dpe_ctx_handle";
+
+	/* Assert the node offset point to compatible property */
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
+	if (node < 0) {
+		WARN("The compatible property '%s'%s", compatible,
+		     " not specified in TB_FW config.\n");
+		return node;
+	}
+
+	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
+
+	rc = fdt_read_uint32(dtb, node, DTB_PROP_DPE_CTX_HANDLE, (uint32_t *)ctx_handle);
+	if (rc != 0) {
+		ERROR("%s%s", DTB_PROP_DPE_CTX_HANDLE,
+		      " not specified in TB_FW config.\n");
+	}
+
+	return rc;
+}
+#else
 /*
  * Write the Event Log address and its size in the DTB.
  *
@@ -393,4 +537,5 @@
 
 	return rc;
 }
+#endif /* DICE_PROTECTION_ENVIRONMENT */
 #endif /* MEASURED_BOOT */
diff --git a/plat/arm/common/plat_arm_sip_svc.c b/plat/arm/common/plat_arm_sip_svc.c
index d496d2e..d6341e2 100644
--- a/plat/arm/common/plat_arm_sip_svc.c
+++ b/plat/arm/common/plat_arm_sip_svc.c
@@ -111,11 +111,11 @@
 
 #if (ENABLE_RME == 1) && (defined(SPD_spmd) && SPMD_SPM_AT_SEL2 == 1)
 	case PLAT_PROTECT_MEM_SMC64:
-		INFO("Sip Call - Protect memory\n");
+		VERBOSE("Sip Call - Protect memory\n");
 		return plat_protect_memory(true, secure_origin, x1, x2, handle);
 		break;
 	case PLAT_UNPROTECT_MEM_SMC64:
-		INFO("Sip Call - Unprotect memory\n");
+		VERBOSE("Sip Call - Unprotect memory\n");
 		return plat_protect_memory(false, secure_origin, x1, x2, handle);
 		break;
 #endif
diff --git a/plat/arm/css/sgi/include/sgi_plat.h b/plat/arm/css/sgi/include/sgi_plat.h
deleted file mode 100644
index a5fbded..0000000
--- a/plat/arm/css/sgi/include/sgi_plat.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SGI_PLAT_H
-#define SGI_PLAT_H
-
-/* BL31 platform setup common to all SGI based platforms */
-void sgi_bl31_common_platform_setup(void);
-
-#endif /* SGI_PLAT_H */
diff --git a/plat/arm/css/sgi/include/sgi_sdei.h b/plat/arm/css/sgi/include/sgi_sdei.h
deleted file mode 100644
index f380122..0000000
--- a/plat/arm/css/sgi/include/sgi_sdei.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef SGI_SDEI_H
-#define SGI_SDEI_H
-
-#if SDEI_SUPPORT
-
-/* ARM SDEI dynamic shared event numbers */
-#define SGI_SDEI_DS_EVENT_0		U(804)
-#define SGI_SDEI_DS_EVENT_1		U(805)
-
-#define PLAT_ARM_PRIVATE_SDEI_EVENTS					      \
-		SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI),			      \
-		SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \
-		SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL),
-
-#define PLAT_ARM_SHARED_SDEI_EVENTS
-
-#endif /* SDEI_SUPPORT */
-
-#endif /* SGI_SDEI_H */
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/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
index ab99b15..19c4e48 100644
--- a/plat/common/aarch64/plat_common.c
+++ b/plat/common/aarch64/plat_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,6 +35,7 @@
 
 void bl31_plat_runtime_setup(void)
 {
+	console_flush();
 	console_switch_state(CONSOLE_FLAG_RUNTIME);
 }
 
@@ -71,12 +72,19 @@
 
 const char *get_el_str(unsigned int el)
 {
-	if (el == MODE_EL3) {
+	switch (el) {
+	case MODE_EL3:
 		return "EL3";
-	} else if (el == MODE_EL2) {
+	case MODE_EL2:
 		return "EL2";
+	case MODE_EL1:
+		return "EL1";
+	case MODE_EL0:
+		return "EL0";
+	default:
+		assert(false);
+		return NULL;
 	}
-	return "EL1";
 }
 
 #if FFH_SUPPORT
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
index baa70e0..d0c7a31 100644
--- a/plat/common/plat_gicv3.c
+++ b/plat/common/plat_gicv3.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.
  * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -344,6 +344,11 @@
 	return gicv3_set_pmr(mask);
 }
 
+unsigned int plat_ic_deactivate_priority(unsigned int mask)
+{
+	return gicv3_deactivate_priority(mask);
+}
+
 unsigned int plat_ic_get_interrupt_id(unsigned int raw)
 {
 	unsigned int id = raw & INT_ID_MASK;
diff --git a/plat/imx/common/imx8_helpers.S b/plat/imx/common/imx8_helpers.S
index 19293bf..eb93833 100644
--- a/plat/imx/common/imx8_helpers.S
+++ b/plat/imx/common/imx8_helpers.S
@@ -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
  */
@@ -86,6 +86,51 @@
 	ret
 endfunc plat_calc_core_pos
 
+	/* ----------------------------------------------
+	 * function to handle platform specific reset.
+	 * ----------------------------------------------
+	 */
+func plat_reset_handler
+#if defined(PLAT_imx8ulp)
+	/* enable the 512KB cache by default */
+	mov	x0, #IMX_SIM1_BASE
+	/*
+	 * if the RVBADDR is ROM entry, that means we did
+	 * NOT switch the L2 cache to 512KB. default is 256K config,
+	 * so skip
+	 */
+	ldr	w1, [x0, #0x5c]
+	cmp	w1, #0x1000
+	b.eq	1f
+	add	x0, x0, #0x30
+	ldr	w1, [x0]
+	/* if already 512KB config, skip */
+	tbnz	w1, #4, 1f
+	ldr	w1, [x0]
+	orr	w1, w1, #0x10
+	str	w1, [x0]
+	orr	w1, w1, #0x10000
+	str	w1, [x0]
+	b	.
+1:	mrs	x0, CORTEX_A35_CPUECTLR_EL1
+	orr     x0, x0, #(0x1 << 0)
+	orr     x0, x0, #(0x1 << 3)
+	msr	CORTEX_A35_CPUECTLR_EL1, x0
+
+	mrs	x0, CORTEX_A35_L2ECTLR_EL1
+	orr     x0, x0, #(0x1 << 0)
+	msr	CORTEX_A35_L2ECTLR_EL1, x0
+	isb
+#endif
+	/* enable EL2 cpuectlr RW access */
+	mov	x0, #0x73
+	msr	actlr_el3, x0
+	msr	actlr_el2, x0
+	isb
+
+	ret
+endfunc plat_reset_handler
+
 	/* ---------------------------------------------
 	 * function to get the entrypoint.
 	 * ---------------------------------------------
diff --git a/plat/imx/common/imx_bl31_common.c b/plat/imx/common/imx_bl31_common.c
new file mode 100644
index 0000000..f6d7e24
--- /dev/null
+++ b/plat/imx/common/imx_bl31_common.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <imx_plat_common.h>
+
+uint32_t plat_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
diff --git a/plat/imx/common/imx_sip_handler.c b/plat/imx/common/imx_sip_handler.c
index f830b64..5d29186 100644
--- a/plat/imx/common/imx_sip_handler.c
+++ b/plat/imx/common/imx_sip_handler.c
@@ -332,3 +332,16 @@
 
 	return 0;
 }
+
+#if defined(PLAT_imx8ulp)
+int imx_hifi_xrdc(uint32_t smc_fid)
+{
+	mmio_setbits_32(IMX_SIM2_BASE + 0x8, BIT_32(19) | BIT_32(17) | BIT_32(18));
+	mmio_clrbits_32(IMX_SIM2_BASE + 0x8, BIT_32(16));
+
+	extern int xrdc_apply_hifi_config(void);
+	xrdc_apply_hifi_config();
+
+	return 0;
+}
+#endif
diff --git a/plat/imx/common/imx_sip_svc.c b/plat/imx/common/imx_sip_svc.c
index 69d4f05..c625704 100644
--- a/plat/imx/common/imx_sip_svc.c
+++ b/plat/imx/common/imx_sip_svc.c
@@ -1,14 +1,17 @@
 /*
- * 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
  */
 
 #include <stdint.h>
+
 #include <common/debug.h>
 #include <common/runtime_svc.h>
+#include <drivers/scmi-msg.h>
 #include <lib/pmf/pmf.h>
 #include <tools_share/uuid.h>
+
 #include <imx_sip_svc.h>
 
 static int32_t imx_sip_setup(void)
@@ -29,6 +32,17 @@
 	case IMX_SIP_AARCH32:
 		SMC_RET1(handle, imx_kernel_entry_handler(smc_fid, x1, x2, x3, x4));
 		break;
+#if defined(PLAT_imx8ulp)
+	case IMX_SIP_SCMI:
+		scmi_smt_fastcall_smc_entry(0);
+		SMC_RET1(handle, 0);
+		break;
+	case IMX_SIP_HIFI_XRDC:
+		SMC_RET1(handle, imx_hifi_xrdc(smc_fid));
+		break;
+	case IMX_SIP_DDR_DVFS:
+		return dram_dvfs_handler(smc_fid, handle, x1, x2, x3);
+#endif
 #if defined(PLAT_imx8mq)
 	case IMX_SIP_GET_SOC_INFO:
 		SMC_RET1(handle, imx_soc_info_handler(smc_fid, x1, x2, x3));
diff --git a/plat/imx/common/include/imx_plat_common.h b/plat/imx/common/include/imx_plat_common.h
new file mode 100644
index 0000000..8ec9481
--- /dev/null
+++ b/plat/imx/common/include/imx_plat_common.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_PLAT_COMMON_H
+#define IMX_PLAT_COMMON_H
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+uint32_t plat_get_spsr_for_bl33_entry(void);
+
+#endif /*IMX_PLAT_COMMON_H */
diff --git a/plat/imx/common/include/imx_sip_svc.h b/plat/imx/common/include/imx_sip_svc.h
index 35a9f47..e154530 100644
--- a/plat/imx/common/include/imx_sip_svc.h
+++ b/plat/imx/common/include/imx_sip_svc.h
@@ -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
  */
@@ -52,6 +52,11 @@
 int imx_kernel_entry_handler(uint32_t smc_fid, u_register_t x1,
 			     u_register_t x2, u_register_t x3,
 			     u_register_t x4);
+
+#define IMX_SIP_SCMI			0xC20000FE
+
+#define IMX_SIP_HIFI_XRDC		0xC200000E
+
 #if defined(PLAT_imx8mq)
 int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1,
 			 u_register_t x2, u_register_t x3);
@@ -96,5 +101,12 @@
 uint64_t imx_buildinfo_handler(uint32_t smc_fid, u_register_t x1,
 			       u_register_t x2, u_register_t x3,
 			       u_register_t x4);
+int scmi_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3);
+int imx_hifi_xrdc(uint32_t smc_fid);
+
+#if defined(PLAT_imx8ulp)
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+	u_register_t x1, u_register_t x2, u_register_t x3);
+#endif
 
 #endif /* __IMX_SIP_SVC_H__ */
diff --git a/plat/imx/imx8m/imx8m_measured_boot.c b/plat/imx/imx8m/imx8m_measured_boot.c
index bfcd6ce..159be00 100644
--- a/plat/imx/imx8m/imx8m_measured_boot.c
+++ b/plat/imx/imx8m/imx8m_measured_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  * Copyright (c) 2022, Linaro.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -9,6 +9,7 @@
 
 #include "./include/imx8m_measured_boot.h"
 #include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
 #include <plat/arm/common/plat_arm.h>
 
 /* Event Log data */
@@ -16,11 +17,11 @@
 
 /* FVP table with platform specific image IDs, names and PCRs */
 static const event_log_metadata_t imx8m_event_log_metadata[] = {
-	{ BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
-	{ BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
-	{ BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
-	{ BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
-	{ BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
+	{ BL31_IMAGE_ID, MBOOT_BL31_IMAGE_STRING, PCR_0 },
+	{ BL32_IMAGE_ID, MBOOT_BL32_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA1_IMAGE_ID, MBOOT_BL32_EXTRA1_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA2_IMAGE_ID, MBOOT_BL32_EXTRA2_IMAGE_STRING, PCR_0 },
+	{ BL33_IMAGE_ID, MBOOT_BL33_IMAGE_STRING, PCR_0 },
 	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
 };
 
diff --git a/plat/imx/imx8ulp/apd_context.c b/plat/imx/imx8ulp/apd_context.c
new file mode 100644
index 0000000..54b8795
--- /dev/null
+++ b/plat/imx/imx8ulp/apd_context.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_imx8.h>
+#include <xrdc.h>
+
+#define PCC_PR	BIT(31)
+#define PFD_VALID_MASK	U(0x40404040)
+
+#define S400_MU_BASE	U(0x27020000)
+#define S400_MU_RSR	(S400_MU_BASE + 0x12c)
+#define S400_MU_TRx(i)	(S400_MU_BASE + 0x200 + (i) * 4)
+#define S400_MU_RRx(i)	(S400_MU_BASE + 0x280 + (i) * 4)
+
+/*
+ * need to re-init the PLL, CGC1, PCC, CMC, XRDC, SIM, GPIO etc.
+ * init the PLL &PFD first, then switch the CA35 clock to PLL for
+ * performance consideration, restore other bus fabric clock.
+ */
+
+extern void imx8ulp_caam_init(void);
+extern void upower_wait_resp(void);
+extern void dram_enter_retention(void);
+extern void dram_exit_retention(void);
+
+struct plat_gic_ctx imx_gicv3_ctx;
+static uint32_t cmc1_pmprot;
+static uint32_t cmc1_srie;
+
+/* TPM5: global timer */
+static uint32_t tpm5[3];
+
+static uint32_t wdog3[2];
+
+/* CGC1 PLL2 */
+uint32_t pll2[][2] = {
+	{0x292c0510, 0x0}, {0x292c0518, 0x0}, {0x292c051c, 0x0},
+	{0x292c0520, 0x0}, {0x292c0500, 0x0},
+};
+
+/* CGC1 PLL3 */
+uint32_t pll3[][2] = {
+	{0x292c0604, 0x0}, {0x292c0608, 0x0}, {0x292c060c, 0x0},
+	{0x292c0610, 0x0}, {0x292c0618, 0x0}, {0x292c061c, 0x0},
+	{0x292c0620, 0x0}, {0x292c0624, 0x0}, {0x292c0600, 0x0},
+	{0x292c0614, 0x0},
+};
+
+/* CGC1 others */
+uint32_t cgc1[][2] = {
+	{0x292c0014, 0x0}, {0x292c0034, 0x0}, {0x292c0038, 0x0},
+	{0x292c0108, 0x0}, {0x292c0208, 0x0}, {0x292c0700, 0x0},
+	{0x292c0810, 0x0}, {0x292c0900, 0x0}, {0x292c0904, 0x0},
+	{0x292c0908, 0x0}, {0x292c090c, 0x0}, {0x292c0a00, 0x0},
+};
+
+static uint32_t pcc3[61];
+static uint32_t pcc4[32];
+
+static uint32_t pcc5_0[33];
+static uint32_t pcc5_1[][2] = {
+	{0x2da70084, 0x0}, {0x2da70088, 0x0}, {0x2da7008c, 0x0},
+	{0x2da700a0, 0x0}, {0x2da700a4, 0x0}, {0x2da700a8, 0x0},
+	{0x2da700ac, 0x0}, {0x2da700b0, 0x0}, {0x2da700b4, 0x0},
+	{0x2da700bc, 0x0}, {0x2da700c0, 0x0}, {0x2da700c8, 0x0},
+	{0x2da700cc, 0x0}, {0x2da700d0, 0x0}, {0x2da700f0, 0x0},
+	{0x2da700f4, 0x0}, {0x2da700f8, 0x0}, {0x2da70108, 0x0},
+	{0x2da7010c, 0x0}, {0x2da70110, 0x0}, {0x2da70114, 0x0},
+};
+
+static uint32_t cgc2[][2] = {
+	{0x2da60014, 0x0}, {0x2da60020, 0x0}, {0x2da6003c, 0x0},
+	{0x2da60040, 0x0}, {0x2da60108, 0x0}, {0x2da60208, 0x0},
+	{0x2da60900, 0x0}, {0x2da60904, 0x0}, {0x2da60908, 0x0},
+	{0x2da60910, 0x0}, {0x2da60a00, 0x0},
+};
+
+static uint32_t pll4[][2] = {
+	{0x2da60604, 0x0}, {0x2da60608, 0x0}, {0x2da6060c, 0x0},
+	{0x2da60610, 0x0}, {0x2da60618, 0x0}, {0x2da6061c, 0x0},
+	{0x2da60620, 0x0}, {0x2da60624, 0x0}, {0x2da60600, 0x0},
+	{0x2da60614, 0x0},
+};
+
+static uint32_t lpav_sim[][2] = {
+	{0x2da50000, 0x0}, {0x2da50004, 0x0}, {0x2da50008, 0x0},
+	{0x2da5001c, 0x0}, {0x2da50020, 0x0}, {0x2da50024, 0x0},
+	{0x2da50034, 0x0},
+};
+
+#define APD_GPIO_CTRL_NUM		2
+#define LPAV_GPIO_CTRL_NUM		1
+#define GPIO_CTRL_REG_NUM		8
+#define GPIO_PIN_MAX_NUM	32
+#define GPIO_CTX(addr, num)	\
+	{.base = (addr), .pin_num = (num), }
+
+struct gpio_ctx {
+	/* gpio base */
+	uintptr_t base;
+	/* port control */
+	uint32_t port_ctrl[GPIO_CTRL_REG_NUM];
+	/* GPIO ICR, Max 32 */
+	uint32_t pin_num;
+	uint32_t gpio_icr[GPIO_PIN_MAX_NUM];
+};
+
+static uint32_t gpio_ctrl_offset[GPIO_CTRL_REG_NUM] = {
+	 0xc, 0x10, 0x14, 0x18, 0x1c, 0x40, 0x54, 0x58
+};
+static struct gpio_ctx apd_gpio_ctx[APD_GPIO_CTRL_NUM] = {
+	GPIO_CTX(IMX_GPIOE_BASE, 24),
+	GPIO_CTX(IMX_GPIOF_BASE, 32),
+};
+
+static struct gpio_ctx lpav_gpio_ctx = GPIO_CTX(IMX_GPIOD_BASE, 24);
+/* iomuxc setting */
+#define IOMUXC_SECTION_NUM	8
+struct iomuxc_section {
+	uint32_t offset;
+	uint32_t reg_num;
+};
+
+struct iomuxc_section iomuxc_sections[IOMUXC_SECTION_NUM] = {
+	{.offset = IOMUXC_PTD_PCR_BASE, .reg_num = 24},
+	{.offset = IOMUXC_PTE_PCR_BASE, .reg_num = 24},
+	{.offset = IOMUXC_PTF_PCR_BASE, .reg_num = 32},
+	{.offset = IOMUXC_PSMI_BASE0, .reg_num = 10},
+	{.offset = IOMUXC_PSMI_BASE1, .reg_num = 61},
+	{.offset = IOMUXC_PSMI_BASE2, .reg_num = 12},
+	{.offset = IOMUXC_PSMI_BASE3, .reg_num = 20},
+	{.offset = IOMUXC_PSMI_BASE4, .reg_num = 75},
+};
+static uint32_t iomuxc_ctx[258];
+
+#define PORTS_NUM		3U
+void apd_io_pad_off(void)
+{
+	unsigned int i, j;
+
+	/* off the PTD/E/F, need to be customized based on actual user case */
+	for (i = 0; i < PORTS_NUM; i++) {
+		for (j = 0; j < iomuxc_sections[i].reg_num; j++) {
+			mmio_write_32(iomuxc_sections[i].offset + j * 4, 0);
+		}
+	}
+
+	/* disable the PTD compensation */
+	mmio_write_32(IMX_SIM1_BASE + 0x48, 0x800);
+}
+
+void iomuxc_save(void)
+{
+	unsigned int i, j;
+	unsigned int index = 0U;
+
+	for (i = 0U; i < IOMUXC_SECTION_NUM; i++) {
+		for (j = 0U; j < iomuxc_sections[i].reg_num; j++) {
+			iomuxc_ctx[index++] = mmio_read_32(iomuxc_sections[i].offset + j * 4);
+		}
+	}
+
+	apd_io_pad_off();
+}
+
+void iomuxc_restore(void)
+{
+	unsigned int i, j;
+	unsigned int index = 0U;
+
+	for (i = 0U; i < IOMUXC_SECTION_NUM; i++) {
+		for (j = 0U; j < iomuxc_sections[i].reg_num; j++) {
+			mmio_write_32(iomuxc_sections[i].offset + j * 4, iomuxc_ctx[index++]);
+		}
+	}
+}
+
+void gpio_save(struct gpio_ctx *ctx, int port_num)
+{
+	unsigned int i, j;
+
+	for (i = 0U; i < port_num; i++) {
+		/* save the port control setting */
+		for (j = 0U; j < GPIO_CTRL_REG_NUM; j++) {
+			if (j < 4U) {
+				ctx->port_ctrl[j] = mmio_read_32(ctx->base + gpio_ctrl_offset[j]);
+				/*
+				 * clear the permission setting to read the GPIO
+				 * non-secure world setting.
+				 */
+				mmio_write_32(ctx->base + gpio_ctrl_offset[j], 0x0);
+			} else {
+				ctx->port_ctrl[j] = mmio_read_32(ctx->base + gpio_ctrl_offset[j]);
+			}
+		}
+		/* save the gpio icr setting */
+		for (j = 0U; j < ctx->pin_num; j++) {
+			ctx->gpio_icr[j] = mmio_read_32(ctx->base + 0x80 + j * 4);
+		}
+
+		ctx++;
+	}
+}
+
+void gpio_restore(struct gpio_ctx *ctx, int port_num)
+{
+	unsigned int i, j;
+
+	for (i = 0U; i < port_num; i++) {
+		for (j = 0U; j < ctx->pin_num; j++)
+			mmio_write_32(ctx->base + 0x80 + j * 4, ctx->gpio_icr[j]);
+
+		for (j = 4U; j < GPIO_CTRL_REG_NUM; j++) {
+			mmio_write_32(ctx->base + gpio_ctrl_offset[j], ctx->port_ctrl[j]);
+		}
+
+		/* permission config retore last */
+		for (j = 0U; j < 4; j++) {
+			mmio_write_32(ctx->base + gpio_ctrl_offset[j], ctx->port_ctrl[j]);
+		}
+
+		ctx++;
+	}
+}
+
+void cgc1_save(void)
+{
+	unsigned int i;
+
+	/* PLL2 */
+	for (i = 0U; i < ARRAY_SIZE(pll2); i++) {
+		pll2[i][1] = mmio_read_32(pll2[i][0]);
+	}
+
+	/* PLL3 */
+	for (i = 0U; i < ARRAY_SIZE(pll3); i++) {
+		pll3[i][1] = mmio_read_32(pll3[i][0]);
+	}
+
+	/* CGC1 others */
+	for (i = 0U; i < ARRAY_SIZE(cgc1); i++) {
+		cgc1[i][1] = mmio_read_32(cgc1[i][0]);
+	}
+}
+
+void cgc1_restore(void)
+{
+	unsigned int i;
+
+	/* PLL2 */
+	for (i = 0U; i < ARRAY_SIZE(pll2); i++) {
+		mmio_write_32(pll2[i][0], pll2[i][1]);
+	}
+	/* wait for PLL2 lock */
+	while (!(mmio_read_32(pll2[4][0]) & BIT(24))) {
+		;
+	}
+
+	/* PLL3 */
+	for (i = 0U; i < 9U; i++) {
+		mmio_write_32(pll3[i][0], pll3[i][1]);
+	}
+
+	/* wait for PLL3 lock */
+	while (!(mmio_read_32(pll3[4][0]) & BIT(24))) {
+		;
+	}
+
+	/* restore the PFDs */
+	mmio_write_32(pll3[9][0], pll3[9][1] & ~(BIT(31) | BIT(23) | BIT(15) | BIT(7)));
+	mmio_write_32(pll3[9][0], pll3[9][1]);
+
+	/* wait for the PFD is stable, only need to check the enabled PFDs */
+	while (!(mmio_read_32(pll3[9][0]) & PFD_VALID_MASK)) {
+		;
+	}
+
+	/* CGC1 others */
+	for (i = 0U; i < ARRAY_SIZE(cgc1); i++) {
+		mmio_write_32(cgc1[i][0], cgc1[i][1]);
+	}
+}
+
+void tpm5_save(void)
+{
+	tpm5[0] = mmio_read_32(IMX_TPM5_BASE + 0x10);
+	tpm5[1] = mmio_read_32(IMX_TPM5_BASE + 0x18);
+	tpm5[2] = mmio_read_32(IMX_TPM5_BASE + 0x20);
+}
+
+void tpm5_restore(void)
+{
+	mmio_write_32(IMX_TPM5_BASE + 0x10, tpm5[0]);
+	mmio_write_32(IMX_TPM5_BASE + 0x18, tpm5[1]);
+	mmio_write_32(IMX_TPM5_BASE + 0x20, tpm5[2]);
+}
+
+void wdog3_save(void)
+{
+	/* enable wdog3 clock */
+	mmio_write_32(IMX_PCC3_BASE + 0xa8, 0xd2800000);
+
+	/* save the CS & TOVAL regiter */
+	wdog3[0] = mmio_read_32(IMX_WDOG3_BASE);
+	wdog3[1] = mmio_read_32(IMX_WDOG3_BASE + 0x8);
+}
+
+void wdog3_restore(void)
+{
+	/* enable wdog3 clock */
+	mmio_write_32(IMX_PCC3_BASE + 0xa8, 0xd2800000);
+
+	/* reconfig the CS */
+	mmio_write_32(IMX_WDOG3_BASE, wdog3[0]);
+	/* set the tiemout value */
+	mmio_write_32(IMX_WDOG3_BASE + 0x8, wdog3[1]);
+
+	/* wait for the lock status */
+	while ((mmio_read_32(IMX_WDOG3_BASE) & BIT(11))) {
+		;
+	}
+
+	/* wait for the config done */
+	while (!(mmio_read_32(IMX_WDOG3_BASE) & BIT(10))) {
+		;
+	}
+}
+
+static uint32_t lpuart_regs[4];
+#define LPUART_BAUD     0x10
+#define LPUART_CTRL     0x18
+#define LPUART_FIFO     0x28
+#define LPUART_WATER    0x2c
+
+void lpuart_save(void)
+{
+	lpuart_regs[0] = mmio_read_32(IMX_LPUART5_BASE + LPUART_BAUD);
+	lpuart_regs[1] = mmio_read_32(IMX_LPUART5_BASE + LPUART_FIFO);
+	lpuart_regs[2] = mmio_read_32(IMX_LPUART5_BASE + LPUART_WATER);
+	lpuart_regs[3] = mmio_read_32(IMX_LPUART5_BASE + LPUART_CTRL);
+}
+
+void lpuart_restore(void)
+{
+	mmio_write_32(IMX_LPUART5_BASE + LPUART_BAUD, lpuart_regs[0]);
+	mmio_write_32(IMX_LPUART5_BASE + LPUART_FIFO, lpuart_regs[1]);
+	mmio_write_32(IMX_LPUART5_BASE + LPUART_WATER, lpuart_regs[2]);
+	mmio_write_32(IMX_LPUART5_BASE + LPUART_CTRL, lpuart_regs[3]);
+}
+
+bool is_lpav_owned_by_apd(void)
+{
+	return (mmio_read_32(0x2802b044) & BIT(7)) ? true : false;
+}
+
+void lpav_ctx_save(void)
+{
+	unsigned int i;
+	uint32_t val;
+
+	/* CGC2 save */
+	for (i = 0U; i < ARRAY_SIZE(cgc2); i++) {
+		cgc2[i][1] = mmio_read_32(cgc2[i][0]);
+	}
+
+	/* PLL4 */
+	for (i = 0U; i < ARRAY_SIZE(pll4); i++) {
+		pll4[i][1] = mmio_read_32(pll4[i][0]);
+	}
+
+	/* PCC5 save */
+	for (i = 0U; i < ARRAY_SIZE(pcc5_0); i++) {
+		val = mmio_read_32(IMX_PCC5_BASE + i * 4);
+		if (val & PCC_PR) {
+			pcc5_0[i] = val;
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(pcc5_1); i++) {
+		val = mmio_read_32(pcc5_1[i][0]);
+		if (val & PCC_PR) {
+			pcc5_1[i][1] = val;
+		}
+	}
+
+	/* LPAV SIM save */
+	for (i = 0U; i < ARRAY_SIZE(lpav_sim); i++) {
+		lpav_sim[i][1] = mmio_read_32(lpav_sim[i][0]);
+	}
+
+	/* Save GPIO port D */
+	gpio_save(&lpav_gpio_ctx, LPAV_GPIO_CTRL_NUM);
+
+	/* put DDR into retention */
+	dram_enter_retention();
+}
+
+void lpav_ctx_restore(void)
+{
+	unsigned int i;
+
+	/* PLL4 */
+	for (i = 0U; i < 9U; i++) {
+		mmio_write_32(pll4[i][0], pll4[i][1]);
+	}
+
+	/* wait for PLL4 lock */
+	while (!(mmio_read_32(pll4[8][0]) & BIT(24))) {
+		;
+	}
+
+	/* restore the PLL4 PFDs */
+	mmio_write_32(pll4[9][0], pll4[9][1] & ~(BIT(31) | BIT(23) | BIT(15) | BIT(7)));
+	mmio_write_32(pll4[9][0], pll4[9][1]);
+
+	/* wait for the PFD is stable */
+	while (!(mmio_read_32(pll4[9][0]) & PFD_VALID_MASK)) {
+		;
+	}
+
+	/* CGC2 restore */
+	for (i = 0U; i < ARRAY_SIZE(cgc2); i++) {
+		mmio_write_32(cgc2[i][0], cgc2[i][1]);
+	}
+
+	/* PCC5 restore */
+	for (i = 0U; i < ARRAY_SIZE(pcc5_0); i++) {
+		if (pcc5_0[i] & PCC_PR) {
+			mmio_write_32(IMX_PCC5_BASE + i * 4, pcc5_0[i]);
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(pcc5_1); i++) {
+		if (pcc5_1[i][1] & PCC_PR) {
+			mmio_write_32(pcc5_1[i][0], pcc5_1[i][1]);
+		}
+	}
+
+	/* LPAV_SIM */
+	for (i = 0U; i < ARRAY_SIZE(lpav_sim); i++) {
+		mmio_write_32(lpav_sim[i][0], lpav_sim[i][1]);
+	}
+
+	gpio_restore(&lpav_gpio_ctx, LPAV_GPIO_CTRL_NUM);
+	/* DDR retention exit */
+	dram_exit_retention();
+}
+
+void imx_apd_ctx_save(unsigned int proc_num)
+{
+	unsigned int i;
+	uint32_t val;
+
+	/* enable LPUART5's clock by default */
+	mmio_setbits_32(IMX_PCC3_BASE + 0xe8, BIT(30));
+
+	/* save the gic config */
+	plat_gic_save(proc_num, &imx_gicv3_ctx);
+
+	cmc1_pmprot = mmio_read_32(IMX_CMC1_BASE + 0x18);
+	cmc1_srie = mmio_read_32(IMX_CMC1_BASE + 0x8c);
+
+	/* save the PCC3 */
+	for (i = 0U; i < ARRAY_SIZE(pcc3); i++) {
+		/* save the pcc if it is exist */
+		val = mmio_read_32(IMX_PCC3_BASE + i * 4);
+		if (val & PCC_PR) {
+			pcc3[i] = val;
+		}
+	}
+
+	/* save the PCC4 */
+	for (i = 0U; i < ARRAY_SIZE(pcc4); i++) {
+		/* save the pcc if it is exist */
+		val = mmio_read_32(IMX_PCC4_BASE + i * 4);
+		if (val & PCC_PR) {
+			pcc4[i] = val;
+		}
+	}
+
+	/* save the CGC1 */
+	cgc1_save();
+
+	wdog3_save();
+
+	gpio_save(apd_gpio_ctx, APD_GPIO_CTRL_NUM);
+
+	iomuxc_save();
+
+	tpm5_save();
+
+	lpuart_save();
+
+	/*
+	 * save the lpav ctx & put the ddr into retention
+	 * if lpav master is assigned to APD domain.
+	 */
+	if (is_lpav_owned_by_apd()) {
+		lpav_ctx_save();
+	}
+}
+
+void xrdc_reinit(void)
+{
+	xrdc_apply_apd_config();
+	xrdc_apply_lpav_config();
+
+	xrdc_enable();
+}
+
+void s400_release_caam(void)
+{
+	uint32_t msg, resp;
+
+	mmio_write_32(S400_MU_TRx(0), 0x17d70206);
+	mmio_write_32(S400_MU_TRx(1), 0x7);
+
+	do {
+		resp = mmio_read_32(S400_MU_RSR);
+	} while ((resp & 0x3) != 0x3);
+
+	msg = mmio_read_32(S400_MU_RRx(0));
+	resp = mmio_read_32(S400_MU_RRx(1));
+
+	VERBOSE("resp %x; %x", msg, resp);
+}
+
+void imx_apd_ctx_restore(unsigned int proc_num)
+{
+	unsigned int i;
+
+	/* restore the CCG1 */
+	cgc1_restore();
+
+	for (i = 0U; i < ARRAY_SIZE(pcc3); i++) {
+		/* save the pcc if it is exist */
+		if (pcc3[i] & PCC_PR) {
+			mmio_write_32(IMX_PCC3_BASE + i * 4, pcc3[i]);
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(pcc4); i++) {
+		if (pcc4[i] & PCC_PR) {
+			mmio_write_32(IMX_PCC4_BASE + i * 4, pcc4[i]);
+		}
+	}
+
+	wdog3_restore();
+
+	iomuxc_restore();
+
+	tpm5_restore();
+
+	xrdc_reinit();
+
+	/* Restore GPIO after xrdc_reinit, otherwise MSCs are invalid */
+	gpio_restore(apd_gpio_ctx, APD_GPIO_CTRL_NUM);
+
+	/* restore the gic config */
+	plat_gic_restore(proc_num, &imx_gicv3_ctx);
+
+	mmio_write_32(IMX_CMC1_BASE + 0x18, cmc1_pmprot);
+	mmio_write_32(IMX_CMC1_BASE + 0x8c, cmc1_srie);
+
+	/* enable LPUART5's clock by default */
+	mmio_setbits_32(IMX_PCC3_BASE + 0xe8, BIT(30));
+
+	/* restore the console lpuart */
+	lpuart_restore();
+
+	/* FIXME: make uart work for ATF */
+	mmio_write_32(IMX_LPUART_BASE + 0x18, 0xc0000);
+
+	/* Allow M core to reset A core */
+	mmio_clrbits_32(IMX_MU0B_BASE + 0x10, BIT(2));
+	/*
+	 * Ask S400 to release caam to APD as it is owned by s400
+	 */
+	s400_release_caam();
+
+	/* re-init the caam */
+	imx8ulp_caam_init();
+
+	/*
+	 * ack the upower, seems a necessary steps, otherwise the upower can
+	 * not response to the new API service call. put this just before the
+	 * ddr retention exit because that the dram retention exit flow need to
+	 * communicate with upower.
+	 */
+	upower_wait_resp();
+
+	/*
+	 * restore the lpav ctx & make ddr out of retention
+	 * if lpav master is assigned to APD domain.
+	 */
+	if (is_lpav_owned_by_apd()) {
+		lpav_ctx_restore();
+	}
+}
+
+#define DGO_CTRL1	U(0xc)
+#define USB_WAKEUP	U(0x44)
+#define USB1_PHY_DPD_WAKEUP_EN	BIT_32(5)
+#define USB0_PHY_DPD_WAKEUP_EN	BIT_32(4)
+#define USB1_PHY_WAKEUP_ISO_DISABLE	BIT_32(1)
+#define USB0_PHY_WAKEUP_ISO_DISABLE	BIT_32(0)
+
+void usb_wakeup_enable(bool enable)
+{
+	if (enable) {
+		mmio_setbits_32(IMX_SIM1_BASE + USB_WAKEUP,
+				USB1_PHY_WAKEUP_ISO_DISABLE | USB0_PHY_WAKEUP_ISO_DISABLE);
+		mmio_setbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
+			;
+		}
+
+		mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
+
+		/* Need to delay for a while to make sure the wakeup logic can work */
+		udelay(500);
+
+		mmio_setbits_32(IMX_SIM1_BASE + USB_WAKEUP,
+				USB1_PHY_DPD_WAKEUP_EN | USB0_PHY_DPD_WAKEUP_EN);
+		mmio_setbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
+			;
+		}
+
+		mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
+	} else {
+		/*
+		 * USBx_PHY_DPD_WAKEUP_EN should be cleared before USB0_PHY_WAKEUP_ISO_DISABLE
+		 * to provide the correct the wake-up functionality.
+		 */
+		mmio_write_32(IMX_SIM1_BASE + USB_WAKEUP, USB1_PHY_WAKEUP_ISO_DISABLE |
+			USB0_PHY_WAKEUP_ISO_DISABLE);
+		mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
+			;
+		}
+
+		mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
+		mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
+	}
+}
diff --git a/plat/imx/imx8ulp/dram.c b/plat/imx/imx8ulp/dram.c
new file mode 100644
index 0000000..00a5220
--- /dev/null
+++ b/plat/imx/imx8ulp/dram.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+#include <dram.h>
+#include <upower_api.h>
+
+#define PHY_FREQ_SEL_INDEX(x)		((x) << 16)
+#define PHY_FREQ_MULTICAST_EN(x)	((x) << 8)
+#define DENALI_PHY_1537			U(0x5804)
+
+#define IMX_DDRC_BASE			U(0x2E060000)
+#define SAVED_DRAM_DATA_BASE		U(0x20055000)
+#define DENALI_CTL_143			U(0x23C)
+#define DENALI_CTL_144			U(0x240)
+#define DENALI_CTL_146			U(0x248)
+#define LP_STATE_CS_IDLE		U(0x404000)
+#define LP_STATE_CS_PD_CG		U(0x4F4F00)
+#define LPI_WAKEUP_EN_SHIFT		U(8)
+#define IMX_LPAV_SIM_BASE		0x2DA50000
+#define LPDDR_CTRL			0x14
+#define LPDDR_AUTO_LP_MODE_DISABLE	BIT(24)
+#define SOC_LP_CMD_SHIFT		U(15)
+#define LPDDR_CTRL2			0x18
+#define LPDDR_EN_CLKGATE		(0x1<<17)
+#define LPDDR_MAX_CLKDIV_EN		(0x1 << 16)
+#define LP_AUTO_ENTRY_EN		0x4
+#define LP_AUTO_EXIT_EN			0xF
+
+#define DENALI_CTL_00			U(0x0)
+#define DENALI_CTL_23			U(0x5c)
+#define DFIBUS_FREQ_INIT_SHIFT		U(24)
+#define TSREF2PHYMSTR_SHIFT		U(8)
+#define TSREF2PHYMSTR_MASK		GENMASK(13, 8)
+
+#define DENALI_CTL_24			U(0x60)
+#define DENALI_CTL_25			U(0x64)
+
+#define DENALI_CTL_93			U(0x174)
+#define PWRUP_SREFRESH_EXIT		BIT(0)
+
+#define DENALI_CTL_127				U(0x1fc)
+#define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE	BIT(16)
+
+#define DENALI_CTL_147			U(0x24c)
+#define DENALI_CTL_153			U(0x264)
+#define PCPCS_PD_EN			BIT(8)
+
+#define DENALI_CTL_249			U(0x3E4)
+#define DENALI_CTL_266			U(0x428)
+
+#define DENALI_PHY_1547			U(0x582c)
+#define PHY_LP4_BOOT_DISABLE		BIT(8)
+
+#define DENALI_PHY_1559			U(0x585c)
+#define DENALI_PHY_1590			U(0x58D8)
+
+#define DENALI_PI_00			U(0x2000)
+#define DENALI_PI_04			U(0x2010)
+#define DENALI_PI_52			U(0x20D0)
+#define DENALI_PI_26			U(0x2068)
+#define DENALI_PI_33			U(0x2084)
+#define DENALI_PI_65			U(0x2104)
+#define DENALI_PI_77			U(0x2134)
+#define DENALI_PI_134			U(0x2218)
+#define DENALI_PI_131			U(0x220C)
+#define DENALI_PI_132			U(0x2210)
+#define DENALI_PI_134			U(0x2218)
+#define DENALI_PI_137			U(0x2224)
+#define DENALI_PI_174			U(0x22B8)
+#define DENALI_PI_175			U(0x22BC)
+#define DENALI_PI_181			U(0x22D4)
+#define DENALI_PI_182			U(0x22D8)
+#define DENALI_PI_191			U(0x22FC)
+#define DENALI_PI_192			U(0x2300)
+#define DENALI_PI_212			U(0x2350)
+#define DENALI_PI_214			U(0x2358)
+#define DENALI_PI_217			U(0x2364)
+
+#define LPDDR3_TYPE	U(0x7)
+#define LPDDR4_TYPE	U(0xB)
+
+extern void upower_wait_resp(void);
+
+struct dram_cfg_param {
+	uint32_t reg;
+	uint32_t val;
+};
+
+struct dram_timing_info {
+	/* ddr controller config */
+	struct dram_cfg_param *ctl_cfg;
+	unsigned int ctl_cfg_num;
+	/* pi config */
+	struct dram_cfg_param *pi_cfg;
+	unsigned int pi_cfg_num;
+	/* phy freq1 config */
+	struct dram_cfg_param *phy_f1_cfg;
+	unsigned int phy_f1_cfg_num;
+	/* phy freq2 config */
+	struct dram_cfg_param *phy_f2_cfg;
+	unsigned int phy_f2_cfg_num;
+	/* automatic low power config */
+	struct dram_cfg_param *auto_lp_cfg;
+	unsigned int auto_lp_cfg_num;
+	/* initialized drate table */
+	unsigned int fsp_table[3];
+};
+
+#define CTL_NUM		U(680)
+#define PI_NUM		U(298)
+#define PHY_NUM		U(1654)
+#define PHY_DIFF_NUM	U(49)
+#define AUTO_LP_NUM	U(3)
+struct dram_cfg {
+	uint32_t ctl_cfg[CTL_NUM];
+	uint32_t pi_cfg[PI_NUM];
+	uint32_t phy_full[PHY_NUM];
+	uint32_t phy_diff[PHY_DIFF_NUM];
+	uint32_t auto_lp_cfg[AUTO_LP_NUM];
+};
+
+struct dram_timing_info *info;
+struct dram_cfg *dram_timing_cfg;
+
+/* mark if dram cfg is already saved */
+static bool dram_cfg_saved;
+static bool dram_auto_lp_true;
+static uint32_t dram_class, dram_ctl_143;
+
+/* PHY register index for frequency diff */
+uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
+90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
+346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
+370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
+616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
+871, 872, 882, 1063, 1319, 1566, 1624, 1625
+};
+
+/* lock used for DDR DVFS */
+spinlock_t dfs_lock;
+static volatile uint32_t core_count;
+static volatile bool in_progress;
+static volatile bool sys_dvfs;
+static int num_fsp;
+
+static void ddr_init(void)
+{
+	unsigned int i;
+
+	/* restore the ddr ctl config */
+	for (i = 0U; i < CTL_NUM; i++) {
+		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
+	}
+
+	/* load the PI registers */
+	for (i = 0U; i < PI_NUM; i++) {
+		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
+	}
+
+
+	 /* restore all PHY registers for all the fsp. */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
+	/* restore all the phy configs */
+	for (i = 0U; i < PHY_NUM; i++) {
+		/* skip the reserved registers space */
+		if (i >= 121U && i <= 255U) {
+			continue;
+		}
+		if (i >= 377U && i <= 511U) {
+			continue;
+		}
+		if (i >= 633U && i <= 767U) {
+			continue;
+		}
+		if (i >= 889U && i <= 1023U) {
+			continue;
+		}
+		if (i >= 1065U && i <= 1279U) {
+			continue;
+		}
+		if (i >= 1321U && i <= 1535U) {
+			continue;
+		}
+		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
+	}
+
+	if (dram_class == LPDDR4_TYPE) {
+		/* restore only the diff. */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
+		for (i = 0U; i < PHY_DIFF_NUM; i++) {
+			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
+				      dram_timing_cfg->phy_diff[i]);
+		}
+	}
+
+	/* Re-enable MULTICAST mode */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
+}
+
+void dram_lp_auto_disable(void)
+{
+	uint32_t lp_auto_en;
+
+	dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
+					      sizeof(struct dram_timing_info));
+	lp_auto_en = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & (LP_AUTO_ENTRY_EN << 24));
+	/* Save initial config */
+	dram_ctl_143 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_143);
+
+	if (lp_auto_en && !dram_auto_lp_true) {
+		/* 0.a Save DDRC auto low-power mode parameter */
+		dram_timing_cfg->auto_lp_cfg[0] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
+		dram_timing_cfg->auto_lp_cfg[1] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_147);
+		dram_timing_cfg->auto_lp_cfg[2] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146);
+		/* Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to Maximum */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_143, 0xF << 24);
+		/* 0.b Disable DDRC auto low-power mode interface */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_146, LP_AUTO_ENTRY_EN << 24);
+		/* 0.c Read any location to get DRAM out of Self-refresh */
+		mmio_read_32(DEVICE2_BASE);
+		/* 0.d Confirm DRAM is out of Self-refresh */
+		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
+			LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
+			;
+		}
+		/* 0.e Disable DDRC auto low-power exit */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_147, LP_AUTO_EXIT_EN);
+		/* dram low power mode flag */
+		dram_auto_lp_true = true;
+	}
+}
+
+void dram_lp_auto_enable(void)
+{
+	/* Switch back to Auto Low-power mode */
+	if (dram_auto_lp_true) {
+		/* 12.a Confirm DRAM is out of Self-refresh */
+		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
+			LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
+			;
+		}
+		/* 12.b Enable DDRC auto low-power exit */
+		/*
+		 * 12.c TBC! : Set DENALI_CTL_144 [LPI_CTRL_REQ_EN[24]] and
+		 * [DFI_LP_VERSION[16]] back to default settings = 1b'1.
+		 */
+		/*
+		 * 12.d Reconfigure DENALI_CTL_144 [LPI_WAKEUP_EN[5:0]] bit
+		 * LPI_WAKEUP_EN[3] = 1b'1.
+		 */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, dram_timing_cfg->auto_lp_cfg[0]);
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_147, dram_timing_cfg->auto_lp_cfg[1]);
+		/* 12.e Re-enable DDRC auto low-power mode interface */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_146, dram_timing_cfg->auto_lp_cfg[2]);
+		/* restore ctl config */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_143, dram_ctl_143);
+		/* dram low power mode flag */
+		dram_auto_lp_true = false;
+	}
+}
+
+void dram_enter_self_refresh(void)
+{
+	/* disable auto low power interface */
+	dram_lp_auto_disable();
+	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
+	/* 1.a Clock gate PCC_LPDDR4[CGC] and no software reset PCC_LPDDR4[SWRST] */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, (BIT(30) | BIT(28)));
+
+	/*
+	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
+	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
+	 * long with mem and ctlr clk gating or self-refresh power-down long
+	 * with mem and ctlr clk gating'
+	 */
+	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
+	/* TODO: Needed ? 2.a DENALI_CTL_144[LPI_TIMER_WAKEUP_F2] */
+	//mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(0));
+
+	/*
+	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
+	 * the logic to automatic handles low power entry/exit. This is the recommended
+	 * option over handling through software.
+	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
+	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
+	 * since LPPDR logic will be power gated).
+	 */
+	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
+	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
+			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
+	/* 3.c clock gate ddr controller */
+	mmio_setbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_EN_CLKGATE);
+	/* 3.d lpddr max clk div en */
+	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_MAX_CLKDIV_EN);
+}
+
+void dram_exit_self_refresh(void)
+{
+	dram_lp_auto_enable();
+}
+
+void dram_enter_retention(void)
+{
+	unsigned int i;
+
+	dram_lp_auto_disable();
+
+	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
+
+	/*
+	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
+	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
+	 * long with mem and ctlr clk gating or self-refresh  power-down
+	 * long with mem and ctlr clk gating'
+	 */
+	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
+
+	/*
+	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
+	 * the logic to automatic handles low power entry/exit. This is the recommended
+	 * option over handling through software.
+	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
+	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
+	 * since LPPDR logic will be power gated).
+	 */
+	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
+	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
+			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
+
+	/* Save DDR Controller & PHY config.
+	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
+	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
+	 * F1 & F2 into phy_f2_cfg.
+	 */
+	if (!dram_cfg_saved) {
+		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
+		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
+					sizeof(struct dram_timing_info));
+
+		/* get the dram type */
+		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
+		dram_class = (dram_class >> 8) & 0xf;
+
+		/* save the ctl registers */
+		for (i = 0U; i < CTL_NUM; i++) {
+			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
+		}
+		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
+
+		/* save the PI registers */
+		for (i = 0U; i < PI_NUM; i++) {
+			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
+		}
+		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
+
+		/*
+		 * Read and store all PHY registers. full array is a full
+		 * copy for all the setpoint
+		 */
+		if (dram_class == LPDDR4_TYPE) {
+			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
+			for (i = 0U; i < PHY_NUM; i++) {
+				/* Make sure MULTICASE is enabled */
+				if (i == 1537U) {
+					dram_timing_cfg->phy_full[i] = 0x100;
+				} else {
+					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
+				}
+			}
+
+			/*
+			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
+			 * Read and store only the diff.
+			 */
+			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
+			/* save only the frequency based diff config to save memory */
+			for (i = 0U; i < PHY_DIFF_NUM; i++) {
+				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
+									    freq_specific_reg_array[i] * 4);
+			}
+		} else {
+			/* LPDDR3, only f1 need to save */
+			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
+				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
+			}
+		}
+
+		dram_cfg_saved = true;
+	}
+}
+
+void dram_exit_retention(void)
+{
+	uint32_t val;
+
+	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
+
+	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
+
+	/* 3. Reload the LPDDR CTL/PI/PHY register */
+	ddr_init();
+
+	if (dram_class == LPDDR4_TYPE) {
+		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
+
+		/*
+		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
+		 * from controller.
+		 */
+		/*
+		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
+		 * self refresh exit from PI
+		 */
+		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
+		/*
+		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
+		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
+		 * Enable non initialization trainings.
+		 */
+		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
+		/* 4f. PI_DLL_RESET=0x1 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
+		/* PI_PWRUP_SELF_REF_EXIT = 1 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
+		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
+		/* PI_INT_LVL_EN = 0 */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
+		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
+		/* PI_WRLVL_EN_F2 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
+		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
+		/* PI_CALVL_EN_F2 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
+		/* PI_WDQLVL_EN_F0 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
+		/* PI_WDQLVL_EN_F1 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
+		/* PI_WDQLVL_EN_F2 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
+		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
+		/*
+		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
+		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
+		 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
+		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
+	} else {
+		/* PI_DLL_RESET=1 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
+		/* PI_PWRUP_SELF_REF_EXIT=1 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
+		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
+		/* PI_INT_LVL_EN=0 */
+		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
+		/* PI_WRLVL_EN_F0=3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
+		/* PI_CALVL_EN_F0=3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
+		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
+		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
+	}
+
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
+
+	/* Force in-order AXI read data */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
+
+	/*
+	 * Disable special R/W group switches so that R/W group placement
+	 * is always at END of R/W group.
+	 */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
+
+	/* Reduce time for IO pad calibration */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
+
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
+
+	/* PD disable */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
+	/*
+	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
+	 * to 1b'0, PCPCS_PD_EN to 1b'0
+	 */
+
+	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
+	upower_wait_resp();
+
+	if (dram_class == LPDDR4_TYPE) {
+		/* 7. Write PI START parameter to 1'b1 */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
+
+		/* 8. Write CTL START parameter to 1'b1 */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
+	} else {
+		/* 7. Write PI START parameter to 1'b1 */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
+
+		/* 8. Write CTL START parameter to 1'b1 */
+		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
+	}
+
+	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
+	do {
+		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
+	} while (val != 0x2);
+
+	/*
+	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
+	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
+	 */
+	if (dram_class == LPDDR4_TYPE) {
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
+
+		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
+		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
+			;
+		}
+	} else {
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
+		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
+		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
+			;
+		}
+	}
+
+	dram_lp_auto_enable();
+}
+
+#define LPDDR_DONE       (0x1<<4)
+#define SOC_FREQ_CHG_ACK (0x1<<6)
+#define SOC_FREQ_CHG_REQ (0x1<<7)
+#define LPI_WAKEUP_EN    (0x4<<8)
+#define SOC_FREQ_REQ     (0x1<<11)
+
+static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
+{
+
+	/* Wait until the reg is unlocked for writing */
+	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31))
+		;
+
+	mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21));
+	/* Wait for the clock switching done */
+	while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27)))
+		;
+}
+static void set_ddr_clk(uint32_t ddr_freq)
+{
+	/* Disable DDR clock */
+	mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
+	switch (ddr_freq) {
+	/* boot frequency ? */
+	case 48:
+		set_cgc2_ddrclk(2, 0);
+		break;
+	/* default bypass frequency for fsp 1 */
+	case 192:
+		set_cgc2_ddrclk(0, 1);
+		break;
+	case 384:
+		set_cgc2_ddrclk(0, 0);
+		break;
+	case 264:
+		set_cgc2_ddrclk(4, 3);
+		break;
+	case 528:
+		set_cgc2_ddrclk(4, 1);
+		break;
+	default:
+		break;
+	}
+	/* Enable DDR clock */
+	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
+
+	/* Wait until the reg is unlocked for writing */
+	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) {
+		;
+	}
+}
+
+#define AVD_SIM_LPDDR_CTRL	(IMX_LPAV_SIM_BASE + 0x14)
+#define AVD_SIM_LPDDR_CTRL2	(IMX_LPAV_SIM_BASE + 0x18)
+#define MAX_FSP_NUM	U(3)
+#define DDR_DFS_GET_FSP_COUNT	0x10
+#define DDR_BYPASS_DRATE	U(400)
+
+extern int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val);
+
+/* Normally, we only switch frequency between 1(bypass) and 2(highest) */
+int lpddr4_dfs(uint32_t freq_index)
+{
+	uint32_t lpddr_ctrl, lpddr_ctrl2;
+	uint32_t ddr_ctl_144;
+
+	/*
+	 * Valid index: 0 to 2
+	 * index 0: boot frequency
+	 * index 1: bypass frequency
+	 * index 2: highest frequency
+	 */
+	if (freq_index > 2U) {
+		return -1;
+	}
+
+	/*
+	 * increase the voltage to 1.1V firstly before increase frequency
+	 * and APD enter OD mode
+	 */
+	if (freq_index == 2U && sys_dvfs) {
+		upower_pmic_i2c_write(0x22, 0x28);
+	}
+
+	/* Enable LPI_WAKEUP_EN */
+	ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
+	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN);
+
+	/* put DRAM into long self-refresh & clock gating */
+	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
+	lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9);
+	mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl);
+
+	/* Gating the clock */
+	lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2);
+	mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE);
+
+	/* Request frequency change */
+	mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ);
+
+	do {
+		lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
+		if (lpddr_ctrl & SOC_FREQ_CHG_REQ) {
+			/* Bypass mode */
+			if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) {
+				/* Change to PLL bypass mode */
+				mmio_write_32(IMX_LPAV_SIM_BASE, 0x1);
+				/* change the ddr clock source & frequency */
+				set_ddr_clk(info->fsp_table[freq_index]);
+			} else {
+				/* Change to PLL unbypass mode */
+				mmio_write_32(IMX_LPAV_SIM_BASE, 0x0);
+				/* change the ddr clock source & frequency */
+				set_ddr_clk(info->fsp_table[freq_index] >> 1);
+			}
+
+			mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK);
+			continue;
+		}
+	} while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */
+
+	/* restore the original setting */
+	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144);
+	mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2);
+
+	/* Check the DFS result */
+	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF;
+	if (lpddr_ctrl != 0U) {
+		/* Must be something wrong, return failure */
+		return -1;
+	}
+
+	/* decrease the BUCK3 voltage after frequency changed to lower
+	 * and APD in ND_MODE
+	 */
+	if (freq_index == 1U && sys_dvfs) {
+		upower_pmic_i2c_write(0x22, 0x20);
+	}
+
+	/* DFS done successfully */
+	return 0;
+}
+
+/* for the non-primary core, waiting for DFS done */
+static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
+		void *handle, void *cookie)
+{
+	uint32_t irq;
+
+	irq = plat_ic_acknowledge_interrupt();
+	if (irq < 1022U) {
+		plat_ic_end_of_interrupt(irq);
+	}
+
+	/* set the WFE done status */
+	spin_lock(&dfs_lock);
+	core_count++;
+	dsb();
+	spin_unlock(&dfs_lock);
+
+	while (in_progress) {
+		wfe();
+	}
+
+	return 0;
+}
+
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+		u_register_t x1, u_register_t x2, u_register_t x3)
+{
+	unsigned int fsp_index = x1;
+	uint32_t online_cpus = x2 - 1;
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* Get the number of FSPs */
+	if (x1 == DDR_DFS_GET_FSP_COUNT) {
+		SMC_RET2(handle, num_fsp, info->fsp_table[1]);
+	}
+
+	/* start lpddr frequency scaling */
+	in_progress = true;
+	sys_dvfs = x3 ? true : false;
+	dsb();
+
+	/* notify other core wait for scaling done */
+	for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++)
+		/* Skip raise SGI for current CPU */
+		if (i != cpu_id) {
+			plat_ic_raise_el3_sgi(0x8, i);
+		}
+
+	/* Make sure all the cpu in WFE */
+	while (online_cpus != core_count) {
+		;
+	}
+
+	/* Flush the L1/L2 cache */
+	dcsw_op_all(DCCSW);
+
+	lpddr4_dfs(fsp_index);
+
+	in_progress = false;
+	core_count = 0;
+	dsb();
+	sev();
+	isb();
+
+	SMC_RET1(handle, 0);
+}
+
+void dram_init(void)
+{
+	uint32_t flags = 0;
+	uint32_t rc;
+	unsigned int i;
+
+	/* Register the EL3 handler for DDR DVFS */
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
+	if (rc) {
+		panic();
+	}
+
+	info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
+
+	/* Get the num of the supported Fsp */
+	for (i = 0; i < MAX_FSP_NUM; i++) {
+		if (!info->fsp_table[i]) {
+			break;
+		}
+	}
+
+	num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i;
+}
diff --git a/plat/imx/imx8ulp/imx8ulp_bl31_setup.c b/plat/imx/imx8ulp/imx8ulp_bl31_setup.c
new file mode 100644
index 0000000..696f4b6
--- /dev/null
+++ b/plat/imx/imx8ulp/imx8ulp_bl31_setup.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <dram.h>
+#include <imx8_lpuart.h>
+#include <imx8ulp_caam.h>
+#include <imx_plat_common.h>
+#include <plat_imx8.h>
+#include <upower_api.h>
+#include <xrdc.h>
+
+#define MAP_BL31_TOTAL										   \
+	MAP_REGION_FLAT(BL31_BASE, BL31_LIMIT - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE)
+#define MAP_BL31_RO										   \
+	MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_MEMORY | MT_RO | MT_SECURE)
+#define MAP_BL32_TOTAL MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW)
+#define MAP_COHERENT_MEM									\
+	MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, (BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE),	\
+			 MT_DEVICE | MT_RW | MT_SECURE)
+
+#define TRUSTY_PARAMS_LEN_BYTES      (4096*2)
+
+static const mmap_region_t imx_mmap[] = {
+	DEVICE0_MAP, DEVICE1_MAP, DEVICE2_MAP,
+	ELE_MAP, SEC_SIM_MAP, SRAM0_MAP,
+	{0}
+};
+
+extern uint32_t upower_init(void);
+extern void imx8ulp_init_scmi_server(void);
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_t console;
+
+	/* config the TPM5 clock */
+	mmio_write_32(IMX_PCC3_BASE + 0xd0, 0x92000000);
+	mmio_write_32(IMX_PCC3_BASE + 0xd0, 0xd2000000);
+
+	/* enable the GPIO D,E,F non-secure access by default */
+	mmio_write_32(IMX_PCC4_BASE + 0x78, 0xc0000000);
+	mmio_write_32(IMX_PCC4_BASE + 0x7c, 0xc0000000);
+	mmio_write_32(IMX_PCC5_BASE + 0x114, 0xc0000000);
+
+	mmio_write_32(IMX_GPIOE_BASE + 0x10, 0xffffffff);
+	mmio_write_32(IMX_GPIOE_BASE + 0x14, 0x3);
+	mmio_write_32(IMX_GPIOE_BASE + 0x18, 0xffffffff);
+	mmio_write_32(IMX_GPIOE_BASE + 0x1c, 0x3);
+
+	mmio_write_32(IMX_GPIOF_BASE + 0x10, 0xffffffff);
+	mmio_write_32(IMX_GPIOF_BASE + 0x14, 0x3);
+	mmio_write_32(IMX_GPIOF_BASE + 0x18, 0xffffffff);
+	mmio_write_32(IMX_GPIOF_BASE + 0x1c, 0x3);
+
+	mmio_write_32(IMX_GPIOD_BASE + 0x10, 0xffffffff);
+	mmio_write_32(IMX_GPIOD_BASE + 0x14, 0x3);
+	mmio_write_32(IMX_GPIOD_BASE + 0x18, 0xffffffff);
+	mmio_write_32(IMX_GPIOD_BASE + 0x1c, 0x3);
+
+	console_lpuart_register(IMX_LPUART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		     IMX_CONSOLE_BAUDRATE, &console);
+
+	/* This console is only used for boot stage */
+	console_set_scope(&console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = 0;
+
+	/* Pass TEE base and size to bl33 */
+	bl33_image_ep_info.args.arg1 = BL32_BASE;
+	bl33_image_ep_info.args.arg2 = BL32_SIZE;
+
+#ifdef SPD_trusty
+	bl32_image_ep_info.args.arg0 = BL32_SIZE;
+	bl32_image_ep_info.args.arg1 = BL32_BASE;
+#else
+	/* Make sure memory is clean */
+	mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
+	bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+	bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+#endif
+#endif
+}
+
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_BL31_TOTAL,
+		MAP_BL31_RO,
+#if USE_COHERENT_MEM
+		MAP_COHERENT_MEM,
+#endif
+#if defined(SPD_opteed) || defined(SPD_trusty)
+		MAP_BL32_TOTAL,
+#endif
+		{0},
+	};
+
+	setup_page_tables(bl_regions, imx_mmap);
+	enable_mmu_el3(0);
+
+	/* TODO: Hack, refine this piece, scmi channel free */
+	mmio_write_32(SRAM0_BASE + 0x4, 1);
+
+	/* Allow M core to reset A core */
+	mmio_clrbits_32(IMX_MU0B_BASE + 0x10, BIT(2));
+}
+
+void bl31_platform_setup(void)
+{
+	/* select the arch timer source */
+	mmio_setbits_32(IMX_SIM1_BASE + 0x30, 0x8000000);
+
+	generic_delay_timer_init();
+
+	plat_gic_driver_init();
+	plat_gic_init();
+
+	imx8ulp_init_scmi_server();
+	upower_init();
+
+	xrdc_apply_apd_config();
+	xrdc_apply_lpav_config();
+	xrdc_enable();
+
+	imx8ulp_caam_init();
+
+	dram_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE) {
+		return &bl33_image_ep_info;
+	} else {
+		return &bl32_image_ep_info;
+	}
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+	args->arg0 = BL32_SIZE;
+	args->arg1 = BL32_BASE;
+	args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+}
+#endif
diff --git a/plat/imx/imx8ulp/imx8ulp_caam.c b/plat/imx/imx8ulp/imx8ulp_caam.c
new file mode 100644
index 0000000..d150fe2
--- /dev/null
+++ b/plat/imx/imx8ulp/imx8ulp_caam.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2021-2024 NXP.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx8ulp_caam.h>
+
+void imx8ulp_caam_init(void)
+{
+	/* config CAAM JRaMID set MID to Cortex A */
+	mmio_write_32(CAAM_JR0MID, CAAM_NS_MID);
+	mmio_write_32(CAAM_JR1MID, CAAM_NS_MID);
+	mmio_write_32(CAAM_JR2MID, CAAM_NS_MID);
+	mmio_write_32(CAAM_JR3MID, CAAM_NS_MID);
+}
diff --git a/plat/imx/imx8ulp/imx8ulp_psci.c b/plat/imx/imx8ulp/imx8ulp_psci.c
new file mode 100644
index 0000000..628acea
--- /dev/null
+++ b/plat/imx/imx8ulp/imx8ulp_psci.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <plat_imx8.h>
+#include <upower_api.h>
+
+extern void cgc1_save(void);
+extern void cgc1_restore(void);
+extern void imx_apd_ctx_save(unsigned int cpu);
+extern void imx_apd_ctx_restore(unsigned int cpu);
+extern void usb_wakeup_enable(bool enable);
+extern void upower_wait_resp(void);
+extern bool is_lpav_owned_by_apd(void);
+extern void apd_io_pad_off(void);
+extern int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val);
+extern void imx8ulp_init_scmi_server(void);
+
+static uintptr_t secure_entrypoint;
+
+#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+#define RVBARADDRx(c)		(IMX_SIM1_BASE + 0x5c + 0x4 * (c))
+#define WKPUx(c)		(IMX_SIM1_BASE + 0x3c + 0x4 * (c))
+#define AD_COREx_LPMODE(c)	(IMX_CMC1_BASE + 0x50 + 0x4 * (c))
+
+#define PMIC_CFG(v, m, msk)		\
+	{				\
+		.volt = (v),		\
+		.mode = (m),		\
+		.mode_msk = (msk),	\
+	}
+
+#define PAD_CFG(c, r, t)		\
+	{				\
+		.pad_close = (c),	\
+		.pad_reset = (r),	\
+		.pad_tqsleep = (t)	\
+	}
+
+#define BIAS_CFG(m, n, p, mbias)	\
+	{				\
+		.dombias_cfg = {	\
+			.mode = (m),	\
+			.rbbn = (n),	\
+			.rbbp = (p),	\
+		},			\
+		.membias_cfg = {mbias},	\
+	}
+
+#define SWT_BOARD(swt_on, msk)	\
+	{			\
+		.on = (swt_on),	\
+		.mask = (msk),	\
+	}
+
+#define SWT_MEM(a, p, m)	\
+	{			\
+		.array = (a),	\
+		.perif = (p),	\
+		.mask = (m),	\
+	}
+
+static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
+{
+	mmio_write_32(RVBARADDRx(cpu), entry);
+
+	/* set update bit */
+	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
+	/* wait for ack */
+	while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
+	}
+
+	/* clear update bit */
+	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
+	/* clear ack bit */
+	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
+
+	return 0;
+}
+
+static volatile uint32_t cgc1_nicclk;
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
+
+	imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
+
+	/* slow down the APD NIC bus clock */
+	cgc1_nicclk = mmio_read_32(IMX_CGC1_BASE + 0x34);
+	mmio_clrbits_32(IMX_CGC1_BASE + 0x34, GENMASK_32(29, 28));
+
+	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
+	mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
+
+	/* enable wku wakeup for idle */
+	mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
+	plat_gic_pcpu_init();
+	plat_gic_cpuif_enable();
+
+	/* set APD NIC back to orignally setting */
+	mmio_write_32(IMX_CGC1_BASE + 0x34, cgc1_nicclk);
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
+
+	plat_gic_cpuif_disable();
+
+	/* disable wakeup */
+	mmio_write_32(WKPUx(cpu), 0);
+
+	/* set core power mode to PD */
+	mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
+}
+
+/* APD power mode config */
+ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = {
+	[DPD_PWR_MODE] = {
+		.swt_board_offs = 0x180,
+		.swt_mem_offs = 0x188,
+		.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
+		.pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a02),
+		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
+	},
+
+	/* PD */
+	[PD_PWR_MODE] = {
+		.swt_board_offs = 0x170,
+		.swt_mem_offs = 0x178,
+		.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
+		.pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a00),
+		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
+	},
+
+	[ADMA_PWR_MODE] = {
+		.swt_board_offs = 0x120,
+		.swt_mem_offs = 0x128,
+		.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
+		.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
+		.bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
+	},
+
+	[ACT_PWR_MODE] = {
+		.swt_board_offs = 0x110,
+		.swt_mem_offs = 0x118,
+		.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
+		.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
+		.bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
+	},
+};
+
+/* APD power switch config */
+ps_apd_swt_cfgs_t apd_swt_cfgs = {
+	[DPD_PWR_MODE] = {
+		.swt_board[0] = SWT_BOARD(0x0, 0x1fffc),
+		.swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff),
+		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
+	},
+
+	[PD_PWR_MODE] = {
+		.swt_board[0] = SWT_BOARD(0x0, 0x00001fffc),
+		.swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff),
+		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0),
+	},
+
+	[ADMA_PWR_MODE] = {
+		.swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
+		.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
+		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
+	},
+
+	[ACT_PWR_MODE] = {
+		.swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
+		.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
+		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
+	},
+};
+
+/* PMIC config for power down, LDO1 should be OFF */
+ps_apd_pmic_reg_data_cfgs_t pd_pmic_reg_cfgs = {
+	[0] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = PD_PWR_MODE,
+		.i2c_addr = 0x30,
+		.i2c_data = 0x9c,
+	},
+	[1] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = PD_PWR_MODE,
+		.i2c_addr = 0x22,
+		.i2c_data = 0xb,
+	},
+	[2] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = ACT_PWR_MODE,
+		.i2c_addr = 0x30,
+		.i2c_data = 0x9d,
+	},
+	[3] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = ACT_PWR_MODE,
+		.i2c_addr = 0x22,
+		.i2c_data = 0x28,
+	},
+};
+
+/* PMIC config for deep power down, BUCK3 should be OFF */
+ps_apd_pmic_reg_data_cfgs_t dpd_pmic_reg_cfgs = {
+	[0] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = DPD_PWR_MODE,
+		.i2c_addr = 0x21,
+		.i2c_data = 0x78,
+	},
+	[1] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = DPD_PWR_MODE,
+		.i2c_addr = 0x30,
+		.i2c_data = 0x9c,
+	},
+	[2] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = ACT_PWR_MODE,
+		.i2c_addr = 0x21,
+		.i2c_data = 0x79,
+	},
+	[3] = {
+		.tag = PMIC_REG_VALID_TAG,
+		.power_mode = ACT_PWR_MODE,
+		.i2c_addr = 0x30,
+		.i2c_data = 0x9d,
+	},
+};
+
+struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR;
+
+void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode)
+{
+	uint32_t volt;
+
+	if (mode >= NUM_PWR_MODES) {
+		return;
+	}
+
+	/* apd power mode config */
+	memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode],
+		 sizeof(struct ps_apd_pwr_mode_cfg_t));
+
+	/* apd power switch config */
+	memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t));
+
+	/*
+	 * BUCK3 & LDO1 can only be shutdown when LPAV is owned by APD side
+	 * otherwise RTD side is responsible to control them in low power mode.
+	 */
+	if (is_lpav_owned_by_apd()) {
+		/* power off the BUCK3 in DPD mode */
+		if (mode == DPD_PWR_MODE) {
+			memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &dpd_pmic_reg_cfgs,
+				 sizeof(ps_apd_pmic_reg_data_cfgs_t));
+		/* LDO1 should be power off in PD mode */
+		} else if (mode == PD_PWR_MODE) {
+			/* overwrite the buck3 voltage setting in active mode */
+			upower_pmic_i2c_read(0x22, &volt);
+			pd_pmic_reg_cfgs[3].i2c_data = volt;
+			memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &pd_pmic_reg_cfgs,
+				 sizeof(ps_apd_pmic_reg_data_cfgs_t));
+		}
+	}
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+		imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
+		/* core put into power down */
+		mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3);
+		/* FIXME config wakeup interrupt in WKPU */
+		mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
+	} else {
+		/* for core standby/retention mode */
+		mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1);
+		mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
+
+	if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
+		/*
+		 * just for sleep mode for now, need to update to
+		 * support more modes, same for suspend finish call back.
+		 */
+		mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1);
+		mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1);
+
+	} else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		/*
+		 * for cluster off state, put cluster into power down mode,
+		 * config the cluster clock to be off.
+		 */
+		mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
+		mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf);
+	}
+
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
+		/*
+		 * low power mode config info used by upower
+		 * to do low power mode transition.
+		 */
+		imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
+		imx_set_pwr_mode_cfg(ACT_PWR_MODE);
+		imx_set_pwr_mode_cfg(PD_PWR_MODE);
+
+		/* clear the upower wakeup */
+		upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
+		upower_wait_resp();
+
+		/* enable the USB wakeup */
+		usb_wakeup_enable(true);
+
+		/* config the WUU to enabled the wakeup source */
+		mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
+
+		/* !!! clear all the pad wakeup pending event */
+		mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
+
+		/* enable upower usb phy wakeup by default */
+		mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0));
+
+		/* enabled all pad wakeup by default */
+		mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff);
+
+		/* save the AD domain context before entering PD mode */
+		imx_apd_ctx_save(cpu);
+	}
+}
+
+#define DRAM_LPM_STATUS		U(0x2802b004)
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
+
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
+		/* restore the ap domain context */
+		imx_apd_ctx_restore(cpu);
+
+		/* clear the upower wakeup */
+		upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
+		upower_wait_resp();
+
+		/* disable all pad wakeup */
+		mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0);
+
+		/* clear all the pad wakeup pending event */
+		mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
+
+		/*
+		 * disable the usb wakeup after resume to make sure the pending
+		 * usb wakeup in WUU can be cleared successfully, otherwise,
+		 * APD will resume failed in next PD mode.
+		 */
+		usb_wakeup_enable(false);
+
+		/* re-init the SCMI channel */
+		imx8ulp_init_scmi_server();
+	}
+
+	/*
+	 * wait for DDR is ready when DDR is under the RTD
+	 * side control for power saving
+	 */
+	while (mmio_read_32(DRAM_LPM_STATUS) != 0) {
+		;
+	}
+
+	/*
+	 * when resume from low power mode, need to delay for a while
+	 * before access the CMC register.
+	 */
+	udelay(5);
+
+	/* clear cluster's LPM setting. */
+	mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0);
+	mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0);
+
+	/* clear core's LPM setting */
+	mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0);
+	mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0);
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
+		plat_gic_cpuif_enable();
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
+}
+
+void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+	while (1) {
+		wfi();
+	}
+}
+
+void __dead2 imx8ulp_system_reset(void)
+{
+	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
+
+	/* Write invalid command to WDOG CNT to trigger reset */
+	mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
+
+	while (true) {
+		wfi();
+	}
+}
+
+int imx_validate_power_state(unsigned int power_state,
+			 psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (pwr_type == PSTATE_TYPE_STANDBY) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	/* No power down state support */
+	if (pwr_type == PSTATE_TYPE_POWERDOWN) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
+		req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE;
+	}
+}
+
+void __dead2 imx_system_off(void)
+{
+	unsigned int i;
+
+	/* config the all the core into OFF mode and IRQ masked. */
+	for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+		/* disable wakeup from wkpu */
+		mmio_write_32(WKPUx(i), 0x0);
+
+		/* reset the core reset entry to 0x1000 */
+		imx_pwr_set_cpu_entry(i, 0x1000);
+
+		/* config the core power mode to off */
+		mmio_write_32(AD_COREx_LPMODE(i), 0x3);
+	}
+
+	plat_gic_cpuif_disable();
+
+	/* power off all the pad */
+	apd_io_pad_off();
+
+	/* Config the power mode info for entering DPD mode and ACT mode */
+	imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
+	imx_set_pwr_mode_cfg(ACT_PWR_MODE);
+	imx_set_pwr_mode_cfg(DPD_PWR_MODE);
+
+	/* Set the APD domain into DPD mode */
+	mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
+	mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f);
+
+	/* make sure no pending upower wakeup */
+	upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
+	upower_wait_resp();
+
+	/* enable the upower wakeup from wuu, act as APD boot up method  */
+	mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
+	mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4));
+
+	/* make sure no pad wakeup event is pending */
+	mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
+
+	wfi();
+
+	ERROR("power off failed.\n");
+	panic();
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.system_off = imx_system_off,
+	.system_reset = imx8ulp_system_reset,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.validate_power_state = imx_validate_power_state,
+	.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	secure_entrypoint = sec_entrypoint;
+	imx_pwr_set_cpu_entry(0, sec_entrypoint);
+	*psci_ops = &imx_plat_psci_ops;
+
+	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
+	mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
+
+	return 0;
+}
diff --git a/plat/imx/imx8ulp/include/dram.h b/plat/imx/imx8ulp/include/dram.h
new file mode 100644
index 0000000..9ed8969
--- /dev/null
+++ b/plat/imx/imx8ulp/include/dram.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+void dram_init(void);
+
+#endif /* DRAM_H */
+
diff --git a/plat/imx/imx8ulp/include/imx8ulp_caam.h b/plat/imx/imx8ulp/include/imx8ulp_caam.h
new file mode 100644
index 0000000..1b93d7d
--- /dev/null
+++ b/plat/imx/imx8ulp/include/imx8ulp_caam.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021-2024 NXP.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8ULP_CAAM_H
+#define IMX8ULP_CAAM_H
+
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define CAAM_JR0MID		(IMX_CAAM_BASE + 0x10)
+#define CAAM_JR1MID		(IMX_CAAM_BASE + 0x18)
+#define CAAM_JR2MID		(IMX_CAAM_BASE + 0x20)
+#define CAAM_JR3MID		(IMX_CAAM_BASE + 0x28)
+#define CAAM_NS_MID		(0x7)
+
+#define JR0_BASE		(IMX_CAAM_BASE + 0x1000)
+
+void imx8ulp_caam_init(void);
+
+#endif /* IMX8ULP_CAAM_H */
diff --git a/plat/imx/imx8ulp/include/platform_def.h b/plat/imx/imx8ulp/include/platform_def.h
new file mode 100644
index 0000000..20c5851
--- /dev/null
+++ b/plat/imx/imx8ulp/include/platform_def.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0x400
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	2
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CORE_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	2
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+
+#define IMX_PWR_LVL0			MPIDR_AFFLVL0
+#define IMX_PWR_LVL1			MPIDR_AFFLVL1
+#define IMX_PWR_LVL2			MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL		U(1)
+#define PLAT_MAX_PWR_LVL		U(2)
+
+#define PLAT_SLEEP_RET_STATE		U(1)
+#define PLAT_DEEP_SLEEP_RET_STATE	U(2)
+#define PLAT_MAX_RET_STATE		U(3)
+
+#define PLAT_POWER_DOWN_OFF_STATE	U(4)
+#define PLAT_DEEP_POWER_DOWN_STATE	U(5)
+#define PLAT_MAX_OFF_STATE		U(6)
+
+#define BL31_BASE			0x20040000
+#define BL31_LIMIT			0x20070000
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#ifdef SPD_trusty
+#define MAX_XLAT_TABLES			11
+#define MAX_MMAP_REGIONS		12
+#else
+#define MAX_XLAT_TABLES			10
+#define MAX_MMAP_REGIONS		11
+#endif
+
+#define PLAT_GICD_BASE			U(0x2d400000)
+#define PLAT_GICR_BASE			U(0x2d440000)
+#define DEVICE0_BASE			U(0x20000000)
+#define DEVICE0_SIZE			U(0x10000000)
+#define DEVICE1_BASE			U(0x30000000)
+#define DEVICE1_SIZE			U(0x10000000)
+#define DEVICE2_BASE			U(0x8ff00000)
+#define DEVICE2_SIZE			U(0x00001000)
+#define IMX_LPUART4_BASE		U(0x29390000)
+#define IMX_LPUART5_BASE		U(0x293a0000)
+#define IMX_LPUART_BASE			IMX_LPUART5_BASE
+#define IMX_CAAM_BASE			U(0x292e0000)
+#define IMX_BOOT_UART_CLK_IN_HZ		24000000
+#define IMX_CONSOLE_BAUDRATE		115200
+
+#define IMX_CGC1_BASE			U(0x292c0000)
+#define IMX_PCC3_BASE			U(0x292d0000)
+#define IMX_PCC4_BASE			U(0x29800000)
+#define IMX_SIM2_BASE			U(0x2da50000)
+#define IMX_CGC2_BASE			U(0x2da60000)
+#define IMX_PCC5_BASE			U(0x2da70000)
+#define IMX_MU0B_BASE			U(0x29220000)
+#define IMX_CMC1_BASE			U(0x29240000)
+#define IMX_WUU1_BASE			U(0x29260000)
+#define IMX_SIM1_BASE			U(0x29290000)
+#define IMX_GPIOD_BASE			U(0x2e200000)
+#define IMX_GPIOE_BASE			U(0x2d000000)
+#define IMX_GPIOF_BASE			U(0x2d010000)
+#define IMX_WDOG3_BASE			U(0x292a0000)
+#define IMX_TPM5_BASE			U(0x29340000)
+
+#define SRAM0_BASE			U(0x2201F000)
+
+#define IOMUXC_PTD_PCR_BASE		U(0x298c0000)
+#define IOMUXC_PTE_PCR_BASE		U(0x298c0080)
+#define IOMUXC_PTF_PCR_BASE		U(0x298c0100)
+#define IOMUXC_PSMI_BASE0		U(0x298c0800)
+#define IOMUXC_PSMI_BASE1		U(0x298c0838)
+#define IOMUXC_PSMI_BASE2		U(0x298c0954)
+#define IOMUXC_PSMI_BASE3		U(0x298c0994)
+#define IOMUXC_PSMI_BASE4		U(0x298c0a58)
+
+#define IMX_ROM_ENTRY			U(0x1000)
+#define COUNTER_FREQUENCY		1000000
+
+#define PLAT_NS_IMAGE_OFFSET		0x80200000
+
+#define BL31_NOBITS_BASE    0x20058000
+#define BL31_NOBITS_LIMIT   0x2006d000
+
+#define BL31_RWDATA_BASE    0x2006d000
+#define BL31_RWDATA_LIMIT   0x20070000
+
+#define BL32_FDT_OVERLAY_ADDR		0x9d000000
+
+#ifdef SPD_trusty
+#define IMX_TRUSTY_STACK_SIZE 0x100
+#endif
+
+/* system memory map define */
+#define DEVICE0_MAP	MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW)
+#define DEVICE1_MAP	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW)
+/* Map partial DRAM space for DRAM low-power mode control */
+#define DEVICE2_MAP	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW)
+ /* MU and FSB */
+#define ELE_MAP		MAP_REGION_FLAT(0x27010000, 0x20000, MT_DEVICE | MT_RW | MT_NS)
+#define SEC_SIM_MAP	MAP_REGION_FLAT(0x2802B000, 0x1000, MT_DEVICE | MT_RW | MT_NS) /* SEC SIM */
+/* For SCMI shared memory region */
+#define SRAM0_MAP	MAP_REGION_FLAT(SRAM0_BASE, 0x1000, MT_RW | MT_DEVICE)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx8ulp/include/scmi.h b/plat/imx/imx8ulp/include/scmi.h
new file mode 100644
index 0000000..03e16f5
--- /dev/null
+++ b/plat/imx/imx8ulp/include/scmi.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8_SCMI_H
+#define IMX8_SCMI_H
+
+#include <stdint.h>
+
+#define SCMI_SHMEM_CHANNEL_ERROR	BIT_32(1)
+#define SCMI_SHMEM_CHANNEL_FREE		BIT_32(0)
+
+#define SCMI_SHMEM_FLAG_INTR_ENABLED	BIT_32(0)
+
+enum scmi_std_protocol {
+	SCMI_PROTOCOL_BASE = 0x10,
+	SCMI_PROTOCOL_POWER_DOMAIN = 0x11,
+	SCMI_PROTOCOL_SYS_POWER = 0x12,
+	SCMI_PROTOCOL_PERF_DOMAIN = 0x13,
+	SCMI_PROTOCOL_CLK = 0x14,
+	SCMI_PROTOCOL_SENSOR = 0x15,
+	SCMI_PROTOCOL_RESET_DOMAIN = 0x16,
+};
+
+#define MSG_ID(m)	((m) & 0xff)
+#define MSG_TYPE(m)	(((m) >> 8) & 0x3)
+#define MSG_PRO_ID(m)	(((m) >> 10) & 0xff)
+#define MSG_TOKEN(m)	(((m) >> 18) & 0x3ff)
+
+enum {
+	SCMI_POWER_DOMAIN_PROTOCOL	= 0x11,
+	SCMI_SYS_PWR_DOMAIN_PROTOCOL	= 0x12,
+	SCMI_PER_DOMAIN_PROTOCOL	= 0x13,
+	SCMI_CLK_DOMAIN_PROTOCOL	= 0x14,
+	SCMI_SENSOR_PROTOCOL		= 0x15,
+};
+
+#define PROTOCOL_VERSION			0
+#define PROTOCOL_ATTRIBUTES			1
+#define PROTOCOL_MESSAGE_ATTRIBUTES		2
+#define BASE_DISCOVER_VENDOR			3
+#define BASE_DISCOVER_SUB_VENDOR		4
+#define BASE_DISCOVER_IMPLEMENTATION_VERSION	5
+#define BASE_DISCOVER_LIST_PROTOCOLS		6
+#define BASE_DISCOVER_AGENT			7
+#define BASE_NOTIFY_ERRORS			8
+#define BASE_SET_DEVICE_PERMISSIONS		9
+#define BASE_SET_PROTOCOL_PERMISSIONS		0xA
+#define BASE_RESET_AGENT_CONFIGURATION		0xB
+
+enum {
+	SCMI_RET_SUCCESS = 0,
+	SCMI_RET_NOT_SUPPORTED = -1,
+	SCMI_RET_INVALID_PARAMETERS = -2,
+	SCMI_RET_DENIED = -3,
+	SCMI_RET_NOT_FOUND = -4,
+	SCMI_RET_OUT_OF_RANGE = -5,
+	SCMI_RET_BUSY = -6,
+	SCMI_RET_COMMS_ERROR = -7,
+	SCMI_RET_GENERIC_ERROR = -8,
+	SCMI_RET_HARDWARE_ERROR = -9,
+	SCMI_RET_PROTOCOL_ERROR = -10,
+};
+
+#define POWER_DOMAIN_ATTRIBUTES			3
+#define POWER_DOMAIN_SUPPORT_NOTIFICATION	BIT(31)
+#define POWER_DOMAIN_SUPPORT_ASYNCHRONOUS	BIT(30)
+#define POWER_DOMAIN_SUPPORT_SYNCHRONOUS	BIT(29)
+
+#define POWER_STATE_SET			4
+#define POWER_STATE_GET			5
+#define POWER_STATE_NOTIFY		6
+#define	POWER_STATE_CHANGE_REQUESTED_NOTIFY	7
+
+int scmi_power_domain_handler(uint32_t msg_id, void *shmem);
+
+#define PERFORMANCE_DOMAIN_ATTRIBUTES		3
+#define PERFORMANCE_DESCRIBE_LEVELS		4
+#define PERFORMANCE_LIMITS_SET			5
+#define PERFORMANCE_LIMITS_GET			6
+#define PERFORMANCE_LEVEL_SET			7
+#define PERFORMANCE_LEVEL_GET			8
+#define PERFORMANCE_NOTIFY_LIMITS		9
+#define PERFORMANCE_NOTIFY_LEVEL		0xA
+#define PERFORMANCE_DESCRIBE_FAST_CHANNEL	0xB
+
+int scmi_perf_domain_handler(uint32_t msg_id, void *shmem);
+
+#define SENSOR_DESCRIPTION_GET			0x003
+#define SENSOR_CONFIG_SET			0x004
+#define SENSOR_TRIP_POINT_SET			0x005
+#define SENSOR_READING_GET			0x006
+
+int scmi_sensor_handler(uint32_t msg_id, void *shmem);
+
+#define SMC_SHMEM_BASE	0x2201f000
+
+#endif /* IMX8_SCMI_H */
diff --git a/plat/imx/imx8ulp/include/scmi_sensor.h b/plat/imx/imx8ulp/include/scmi_sensor.h
new file mode 100644
index 0000000..5dab898
--- /dev/null
+++ b/plat/imx/imx8ulp/include/scmi_sensor.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ *      System Control and Management Interface (SCMI) support.
+ */
+
+#ifndef INTERNAL_SCMI_SENSOR_H
+#define INTERNAL_SCMI_SENSOR_H
+
+#include <stdint.h>
+
+#define SCMI_PROTOCOL_VERSION_SENSOR UINT32_C(0x10000)
+
+/*
+ * PROTOCOL_ATTRIBUTES
+ */
+struct scmi_sensor_protocol_attributes_p2a {
+	int32_t status;
+	uint32_t attributes;
+	uint32_t sensor_reg_address_low;
+	uint32_t sensor_reg_address_high;
+	uint32_t sensor_reg_len;
+};
+
+/*
+ * SENSOR_READING_GET
+ */
+#define SCMI_SENSOR_PROTOCOL_READING_GET_ASYNC_FLAG_MASK    (1 << 0)
+
+struct scmi_sensor_protocol_reading_get_a2p {
+	uint32_t sensor_id;
+	uint32_t flags;
+};
+
+struct scmi_sensor_protocol_reading_get_p2a {
+	int32_t status;
+	uint32_t sensor_value_low;
+	uint32_t sensor_value_high;
+};
+
+/*
+ * SENSOR_DESCRIPTION_GET
+ */
+ #define SCMI_SENSOR_DESCS_MAX(MAILBOX_SIZE) \
+	((sizeof(struct scmi_sensor_protocol_description_get_p2a) < MAILBOX_SIZE) \
+	? ((MAILBOX_SIZE - \
+	   sizeof(struct scmi_sensor_protocol_description_get_p2a)) \
+	   / sizeof(struct scmi_sensor_desc)) \
+	: 0)
+
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS              0
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS   11
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS 22
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS   27
+
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_MASK \
+	(UINT32_C(0xFF) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS)
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK \
+	(UINT32_C(0x1F) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS)
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MASK \
+	(UINT32_C(0x1F) << \
+	SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS)
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK \
+	(UINT32_C(0x1F) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS)
+
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MAX \
+	(int32_t)(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK >> 1)
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MIN \
+	(-(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MAX + 1))
+
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MAX \
+	(int32_t)(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK >> 1)
+#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MIN \
+	(-(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MAX + 1))
+
+#define SCMI_SENSOR_DESC_ATTRIBUTES_HIGH(SENSOR_TYPE, UNIT_MULTIPLIER, \
+					 UPDATE_MULTIPLIER, UPDATE_INTERVAL) \
+	( \
+	(((SENSOR_TYPE) << \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS) & \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_MASK) | \
+	   (((UNIT_MULTIPLIER) << \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS) & \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK) | \
+	   (((UPDATE_MULTIPLIER) << \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS) & \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MASK) | \
+	   (((UPDATE_INTERVAL) << \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS) & \
+	   SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK) \
+	)
+
+#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS              0
+#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS   16
+
+#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_MASK \
+	(UINT32_C(0xFFF) << SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS)
+#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_MASK \
+	(UINT32_C(0xFFFF) << SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS)
+
+#define SCMI_SENSOR_NUM_SENSOR_FLAGS(NUM_DESCS, NUM_REMAINING_DESCS) \
+	( \
+	(((NUM_DESCS) << \
+	  SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS) & \
+	  SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_MASK) | \
+	  (((NUM_REMAINING_DESCS) << \
+	    SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS) & \
+	    SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_MASK) \
+	)
+
+#define SCMI_SENSOR_NAME_LEN    16
+
+struct scmi_sensor_desc {
+	uint32_t sensor_id;
+	uint32_t sensor_attributes_low;
+	uint32_t sensor_attributes_high;
+	char sensor_name[SCMI_SENSOR_NAME_LEN];
+};
+
+struct scmi_sensor_protocol_description_get_a2p {
+	uint32_t desc_index;
+};
+
+struct scmi_sensor_protocol_description_get_p2a {
+	int32_t status;
+	uint32_t num_sensor_flags;
+	struct scmi_sensor_desc sensor_desc[];
+};
+
+/* Event indices */
+enum scmi_sensor_api_idx {
+	SCMI_SENSOR_EVENT_IDX_REQUEST,
+	SCMI_SENSOR_EVENT_IDX_COUNT,
+};
+
+#endif /* INTERNAL_SCMI_SENSOR_H */
diff --git a/plat/imx/imx8ulp/include/xrdc.h b/plat/imx/imx8ulp/include/xrdc.h
new file mode 100644
index 0000000..15250f0
--- /dev/null
+++ b/plat/imx/imx8ulp/include/xrdc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8ULP_XRDC_H
+#define IMX8ULP_XRDC_H
+
+#define DID_MAX 8
+#define PAC_SLOT_ALL 128
+#define MSC_SLOT_ALL 8
+
+enum xrdc_mda_sa {
+	MDA_SA_S,
+	MDA_SA_NS,
+	MDA_SA_PT, /* pass through master's secure/nonsecure attribute */
+};
+
+struct xrdc_mda_config {
+	uint16_t mda_id;
+	uint16_t did;
+	enum xrdc_mda_sa sa;
+};
+
+struct xrdc_pac_msc_config {
+	uint16_t pac_msc_id;
+	uint16_t slot_id;
+	uint8_t dsel[DID_MAX];
+};
+
+struct xrdc_mrc_config {
+	uint16_t mrc_id;
+	uint16_t region_id;
+	uint32_t region_start;
+	uint32_t region_size;
+	uint8_t dsel[DID_MAX];
+	uint16_t accset[2];
+};
+
+/* APIs to apply and enable XRDC */
+int xrdc_apply_lpav_config(void);
+int xrdc_apply_hifi_config(void);
+int xrdc_apply_apd_config(void);
+void xrdc_enable(void);
+
+#endif
diff --git a/plat/imx/imx8ulp/platform.mk b/plat/imx/imx8ulp/platform.mk
new file mode 100644
index 0000000..f1e53ca
--- /dev/null
+++ b/plat/imx/imx8ulp/platform.mk
@@ -0,0 +1,69 @@
+#
+# Copyright 2021-2024 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+PLAT_INCLUDES		:=	-Iplat/imx/imx8ulp/include		\
+				-Iplat/imx/common/include		\
+				-Iplat/imx/imx8ulp/upower
+
+IMX_GIC_SOURCES		:=	${GICV3_SOURCES}			\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/lpuart_console.S	\
+				plat/imx/common/imx8_helpers.S		\
+				plat/imx/imx8ulp/imx8ulp_bl31_setup.c	\
+				plat/imx/imx8ulp/imx8ulp_psci.c		\
+				plat/imx/imx8ulp/apd_context.c		\
+				plat/imx/common/imx8_topology.c		\
+				plat/imx/common/imx_sip_svc.c		\
+				plat/imx/common/imx_sip_handler.c	\
+				plat/imx/common/imx_bl31_common.c	\
+				plat/common/plat_psci_common.c		\
+				lib/cpus/aarch64/cortex_a35.S		\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				plat/imx/imx8ulp/xrdc/xrdc_core.c		\
+				plat/imx/imx8ulp/imx8ulp_caam.c         \
+				plat/imx/imx8ulp/dram.c 	        \
+				drivers/scmi-msg/base.c			\
+				drivers/scmi-msg/entry.c		\
+				drivers/scmi-msg/smt.c			\
+				drivers/scmi-msg/power_domain.c		\
+				drivers/scmi-msg/sensor.c		\
+				plat/imx/imx8ulp/scmi/scmi.c		\
+				plat/imx/imx8ulp/scmi/scmi_pd.c		\
+				plat/imx/imx8ulp/scmi/scmi_sensor.c	\
+				plat/imx/imx8ulp/upower/upower_api.c	\
+				plat/imx/imx8ulp/upower/upower_hal.c	\
+				${XLAT_TABLES_LIB_SRCS}			\
+				${IMX_GIC_SOURCES}
+
+ifeq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-fno-strict-aliasing
+endif
+
+USE_COHERENT_MEM	:=	1
+RESET_TO_BL31		:=	1
+SEPARATE_NOBITS_REGION	:=	1
+SEPARATE_RWDATA_REGION	:=	1
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+COLD_BOOT_SINGLE_CPU := 1
+WARMBOOT_ENABLE_DCACHE_EARLY	:=	1
+BL32_BASE		?=	0xa6000000
+BL32_SIZE		?=	0x2000000
+$(eval $(call add_define,BL32_BASE))
+$(eval $(call add_define,BL32_SIZE))
+
+ifeq (${SPD},trusty)
+	BL31_CFLAGS    +=      -DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
diff --git a/plat/imx/imx8ulp/scmi/scmi.c b/plat/imx/imx8ulp/scmi/scmi.c
new file mode 100644
index 0000000..5d3e7d7
--- /dev/null
+++ b/plat/imx/imx8ulp/scmi/scmi.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdint.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+
+#include <platform_def.h>
+
+#define SMT_BUFFER_BASE		0x2201f000
+#define SMT_BUFFER0_BASE	SMT_BUFFER_BASE
+#define SMT_BUFFER1_BASE	(SMT_BUFFER_BASE + 0x200)
+
+static struct scmi_msg_channel scmi_channel[] = {
+	[0] = {
+		.shm_addr = SMT_BUFFER0_BASE,
+		.shm_size = SMT_BUF_SLOT_SIZE,
+	},
+};
+
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
+{
+	assert(agent_id < ARRAY_SIZE(scmi_channel));
+
+	return &scmi_channel[agent_id];
+}
+
+static const char vendor[] = "NXP";
+static const char sub_vendor[] = "";
+
+const char *plat_scmi_vendor_name(void)
+{
+	return vendor;
+}
+
+const char *plat_scmi_sub_vendor_name(void)
+{
+	return sub_vendor;
+}
+
+/* Currently supporting Clocks and Reset Domains */
+static const uint8_t plat_protocol_list[] = {
+	SCMI_PROTOCOL_ID_POWER_DOMAIN,
+	SCMI_PROTOCOL_ID_SENSOR,
+	0U /* Null termination */
+};
+
+size_t plat_scmi_protocol_count(void)
+{
+	return ARRAY_SIZE(plat_protocol_list) - 1U;
+}
+
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
+{
+	return plat_protocol_list;
+}
+
+void imx8ulp_init_scmi_server(void)
+{
+	size_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) {
+		scmi_smt_init_agent_channel(&scmi_channel[i]);
+	}
+}
diff --git a/plat/imx/imx8ulp/scmi/scmi_pd.c b/plat/imx/imx8ulp/scmi/scmi_pd.c
new file mode 100644
index 0000000..8e7e5d6
--- /dev/null
+++ b/plat/imx/imx8ulp/scmi/scmi_pd.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <inttypes.h>
+#include <lib/libc/errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/scmi.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+#include <scmi.h>
+
+#include <upower_api.h>
+
+#define POWER_STATE_ON	(0 << 30)
+#define POWER_STATE_OFF	(1 << 30)
+
+extern bool is_lpav_owned_by_apd(void);
+
+enum {
+	PS0 = 0,
+	PS1 = 1,
+	PS2 = 2,
+	PS3 = 3,
+	PS4 = 4,
+	PS5 = 5,
+	PS6 = 6,
+	PS7 = 7,
+	PS8 = 8,
+	PS9 = 9,
+	PS10 = 10,
+	PS11 = 11,
+	PS12 = 12,
+	PS13 = 13,
+	PS14 = 14,
+	PS15 = 15,
+	PS16 = 16,
+	PS17 = 17,
+	PS18 = 18,
+	PS19 = 19,
+};
+
+#define SRAM_DMA1		BIT(6)
+#define SRAM_FLEXSPI2		BIT(7)
+#define SRAM_USB0		BIT(10)
+#define SRAM_USDHC0		BIT(11)
+#define SRAM_USDHC1		BIT(12)
+#define SRAM_USDHC2_USB1	BIT(13)
+#define SRAM_DCNANO		GENMASK_32(18, 17)
+#define SRAM_EPDC		GENMASK_32(20, 19)
+#define SRAM_DMA2		BIT(21)
+#define SRAM_GPU2D		GENMASK_32(23, 22)
+#define SRAM_GPU3D		GENMASK_32(25, 24)
+#define SRAM_HIFI4		BIT(26)
+#define SRAM_ISI_BUFFER		BIT(27)
+#define SRAM_MIPI_CSI_FIFO	BIT(28)
+#define SRAM_MIPI_DSI_FIFO	BIT(29)
+#define SRAM_PXP		BIT(30)
+
+#define SRAM_DMA0		BIT_64(33)
+#define SRAM_FLEXCAN		BIT_64(34)
+#define SRAM_FLEXSPI0		BIT_64(35)
+#define SRAM_FLEXSPI1		BIT_64(36)
+
+struct psw {
+	char *name;
+	uint32_t reg;
+	int power_state;
+	uint32_t count;
+	int flags;
+};
+
+#define ALWAYS_ON BIT(0)
+
+static struct psw imx8ulp_psw[] = {
+	[PS6] = { .name = "PS6", .reg = PS6, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
+	[PS7] = { .name = "PS7", .reg = PS7, .power_state = POWER_STATE_OFF },
+	[PS8] = { .name = "PS8", .reg = PS8, .power_state = POWER_STATE_OFF },
+	[PS13] = { .name = "PS13", .reg = PS13, .power_state = POWER_STATE_OFF },
+	[PS14] = { .name = "PS14", .reg = PS14, .flags = ALWAYS_ON, .power_state = POWER_STATE_OFF },
+	[PS15] = { .name = "PS15", .reg = PS15, .power_state = POWER_STATE_OFF },
+	[PS16] = { .name = "PS16", .reg = PS16, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
+};
+
+struct power_domain {
+	char *name;
+	uint32_t reg;
+	uint32_t psw_parent;
+	uint32_t sram_parent;
+	uint64_t bits;
+	uint32_t power_state;
+	bool lpav; /* belong to lpav domain */
+	uint32_t sw_rst_reg; /* pcc sw reset reg offset */
+};
+
+/* The Rich OS need flow the macro */
+#define IMX8ULP_PD_DMA1		0
+#define IMX8ULP_PD_FLEXSPI2	1
+#define IMX8ULP_PD_USB0		2
+#define IMX8ULP_PD_USDHC0	3
+#define IMX8ULP_PD_USDHC1	4
+#define IMX8ULP_PD_USDHC2_USB1	5
+#define IMX8ULP_PD_DCNANO	6
+#define IMX8ULP_PD_EPDC		7
+#define IMX8ULP_PD_DMA2		8
+#define IMX8ULP_PD_GPU2D	9
+#define IMX8ULP_PD_GPU3D	10
+#define IMX8ULP_PD_HIFI4	11
+#define IMX8ULP_PD_ISI		12
+#define IMX8ULP_PD_MIPI_CSI	13
+#define IMX8ULP_PD_MIPI_DSI	14
+#define IMX8ULP_PD_PXP		15
+
+#define IMX8ULP_PD_PS6		16
+#define IMX8ULP_PD_PS7		17
+#define IMX8ULP_PD_PS8		18
+#define IMX8ULP_PD_PS13		19
+#define IMX8ULP_PD_PS14		20
+#define IMX8ULP_PD_PS15		21
+#define IMX8ULP_PD_PS16		22
+#define IMX8ULP_PD_MAX		23
+
+/* LPAV peripheral PCC */
+#define PCC_GPU2D	(IMX_PCC5_BASE + 0xf0)
+#define PCC_GPU3D	(IMX_PCC5_BASE + 0xf4)
+#define PCC_EPDC	(IMX_PCC5_BASE + 0xcc)
+#define PCC_CSI		(IMX_PCC5_BASE + 0xbc)
+#define PCC_PXP		(IMX_PCC5_BASE + 0xd0)
+
+#define PCC_SW_RST	BIT(28)
+
+#define PWR_DOMAIN(_name, _reg, _psw_parent, _sram_parent, \
+		   _bits, _state, _lpav, _rst_reg) \
+	{ \
+		.name = _name, \
+		.reg = _reg, \
+		.psw_parent = _psw_parent, \
+		.sram_parent = _sram_parent, \
+		.bits = _bits, \
+		.power_state = _state, \
+		.lpav = _lpav, \
+		.sw_rst_reg = _rst_reg, \
+	}
+
+static struct power_domain scmi_power_domains[] = {
+	PWR_DOMAIN("DMA1", IMX8ULP_PD_DMA1, PS6, PS6, SRAM_DMA1, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("FLEXSPI2", IMX8ULP_PD_FLEXSPI2, PS6, PS6, SRAM_FLEXSPI2, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("USB0", IMX8ULP_PD_USB0, PS6, PS6, SRAM_USB0, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("USDHC0", IMX8ULP_PD_USDHC0, PS6, PS6, SRAM_USDHC0, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("USDHC1", IMX8ULP_PD_USDHC1, PS6, PS6, SRAM_USDHC1, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("USDHC2_USB1", IMX8ULP_PD_USDHC2_USB1, PS6, PS6, SRAM_USDHC2_USB1, POWER_STATE_OFF, false, 0U),
+	PWR_DOMAIN("DCNano", IMX8ULP_PD_DCNANO, PS16, PS16, SRAM_DCNANO, POWER_STATE_OFF, true, 0U),
+	PWR_DOMAIN("EPDC", IMX8ULP_PD_EPDC, PS13, PS13, SRAM_EPDC, POWER_STATE_OFF, true, PCC_EPDC),
+	PWR_DOMAIN("DMA2", IMX8ULP_PD_DMA2, PS16, PS16, SRAM_DMA2, POWER_STATE_OFF, true, 0U),
+	PWR_DOMAIN("GPU2D", IMX8ULP_PD_GPU2D, PS16, PS16, SRAM_GPU2D, POWER_STATE_OFF, true, PCC_GPU2D),
+	PWR_DOMAIN("GPU3D", IMX8ULP_PD_GPU3D, PS7, PS7, SRAM_GPU3D, POWER_STATE_OFF, true, PCC_GPU3D),
+	PWR_DOMAIN("HIFI4", IMX8ULP_PD_HIFI4, PS8, PS8, SRAM_HIFI4, POWER_STATE_OFF, true, 0U),
+	PWR_DOMAIN("ISI", IMX8ULP_PD_ISI, PS16, PS16, SRAM_ISI_BUFFER, POWER_STATE_OFF, true, 0U),
+	PWR_DOMAIN("MIPI_CSI", IMX8ULP_PD_MIPI_CSI, PS15, PS16, SRAM_MIPI_CSI_FIFO, POWER_STATE_OFF, true, PCC_CSI),
+	PWR_DOMAIN("MIPI_DSI", IMX8ULP_PD_MIPI_DSI, PS14, PS16, SRAM_MIPI_DSI_FIFO, POWER_STATE_OFF, true, 0U),
+	PWR_DOMAIN("PXP", IMX8ULP_PD_PXP, PS13, PS13, SRAM_PXP | SRAM_EPDC, POWER_STATE_OFF, true, PCC_PXP)
+};
+
+size_t plat_scmi_pd_count(unsigned int agent_id __unused)
+{
+	return ARRAY_SIZE(scmi_power_domains);
+}
+
+const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
+				  unsigned int pd_id)
+{
+	if (pd_id >= IMX8ULP_PD_PS6) {
+		return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].name;
+	}
+
+	return scmi_power_domains[pd_id].name;
+}
+
+unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
+				    unsigned int pd_id __unused)
+{
+	if (pd_id >= IMX8ULP_PD_PS6) {
+		return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].power_state;
+	}
+
+	return scmi_power_domains[pd_id].power_state;
+}
+
+extern void upower_wait_resp(void);
+int upwr_pwm_power(const uint32_t swton[], const uint32_t memon[], bool on)
+{
+	int ret_val;
+	int ret;
+
+	if (on == true) {
+		ret = upwr_pwm_power_on(swton, memon, NULL);
+	} else {
+		ret = upwr_pwm_power_off(swton, memon, NULL);
+	}
+
+	if (ret != 0U) {
+		WARN("%s failed: ret: %d, state: %x\n", __func__, ret, on);
+		return ret;
+	}
+
+	upower_wait_resp();
+
+	ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
+	if (ret != UPWR_REQ_OK) {
+		WARN("Failure %d, %s\n", ret, __func__);
+		if (ret == UPWR_REQ_BUSY) {
+			return -EBUSY;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int32_t plat_scmi_pd_psw(unsigned int index, unsigned int state)
+{
+	uint32_t psw_parent = scmi_power_domains[index].psw_parent;
+	uint32_t sram_parent = scmi_power_domains[index].sram_parent;
+	uint64_t swt;
+	bool on;
+	int ret = 0;
+
+	if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) != 0U &&
+	    (imx8ulp_psw[sram_parent].flags & ALWAYS_ON) != 0U) {
+		return 0;
+	}
+
+	on = (state == POWER_STATE_ON) ? true : false;
+
+	if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) == 0U) {
+		swt = 1 << imx8ulp_psw[psw_parent].reg;
+		if (imx8ulp_psw[psw_parent].count == 0U) {
+			if (on == false) {
+				WARN("off PSW[%d] that already in off state\n", psw_parent);
+				ret = -EACCES;
+			} else {
+				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
+				imx8ulp_psw[psw_parent].count++;
+			}
+		} else {
+			if (on == true) {
+				imx8ulp_psw[psw_parent].count++;
+			} else {
+				imx8ulp_psw[psw_parent].count--;
+			}
+
+			if (imx8ulp_psw[psw_parent].count == 0U) {
+				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
+			}
+		}
+	}
+
+	if (!(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) && (psw_parent != sram_parent)) {
+		swt = 1 << imx8ulp_psw[sram_parent].reg;
+		if (imx8ulp_psw[sram_parent].count == 0U) {
+			if (on == false) {
+				WARN("off PSW[%d] that already in off state\n", sram_parent);
+				ret = -EACCES;
+			} else {
+				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
+				imx8ulp_psw[sram_parent].count++;
+			}
+		} else {
+			if (on == true) {
+				imx8ulp_psw[sram_parent].count++;
+			} else {
+				imx8ulp_psw[sram_parent].count--;
+			}
+
+			if (imx8ulp_psw[sram_parent].count == 0U) {
+				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
+			}
+		}
+	}
+
+	return ret;
+}
+
+bool pd_allow_power_off(unsigned int pd_id)
+{
+	if (scmi_power_domains[pd_id].lpav) {
+		if (!is_lpav_owned_by_apd()) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void assert_pcc_reset(unsigned int pcc)
+{
+	/* if sw_rst_reg is valid, assert the pcc reset */
+	if (pcc != 0U) {
+		mmio_clrbits_32(pcc, PCC_SW_RST);
+	}
+}
+
+int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
+			       unsigned int flags,
+			       unsigned int pd_id,
+			       unsigned int state)
+{
+	unsigned int ps_idx;
+	uint64_t mem;
+	bool on;
+	int ret;
+
+	if (flags != 0U || pd_id >= IMX8ULP_PD_PS6) {
+		return SCMI_NOT_SUPPORTED;
+	}
+
+	ps_idx = 0;
+	while (ps_idx < IMX8ULP_PD_PS6 && scmi_power_domains[ps_idx].reg != pd_id) {
+		ps_idx++;
+	}
+
+	if (ps_idx == IMX8ULP_PD_PS6) {
+		return SCMI_NOT_FOUND;
+	}
+
+	if (state == scmi_power_domains[ps_idx].power_state) {
+		return SCMI_SUCCESS;
+	}
+
+	mem = scmi_power_domains[ps_idx].bits;
+	on = (state == POWER_STATE_ON ? true : false);
+	if (on == true) {
+		/* Assert pcc sw reset if necessary */
+		assert_pcc_reset(scmi_power_domains[ps_idx].sw_rst_reg);
+
+		ret = plat_scmi_pd_psw(ps_idx, state);
+		if (ret != 0U) {
+			return SCMI_DENIED;
+		}
+
+		ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
+		if (ret != 0U) {
+			return SCMI_DENIED;
+		}
+	} else {
+		if (!pd_allow_power_off(ps_idx)) {
+			return SCMI_DENIED;
+		}
+
+		ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
+		if (ret != 0U) {
+			return SCMI_DENIED;
+		}
+
+		ret = plat_scmi_pd_psw(ps_idx, state);
+		if (ret != 0U) {
+			return SCMI_DENIED;
+		}
+	}
+
+	scmi_power_domains[pd_id].power_state = state;
+
+	return SCMI_SUCCESS;
+}
diff --git a/plat/imx/imx8ulp/scmi/scmi_sensor.c b/plat/imx/imx8ulp/scmi/scmi_sensor.c
new file mode 100644
index 0000000..6976b2e
--- /dev/null
+++ b/plat/imx/imx8ulp/scmi/scmi_sensor.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/libc/errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../../drivers/scmi-msg/sensor.h"
+
+#include <common/debug.h>
+#include <drivers/scmi.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <scmi.h>
+
+#include <upower_api.h>
+
+/* Only Temperature now */
+static uint16_t imx_scmi_sensor_count(unsigned int agent_id __unused)
+{
+	return 1U;
+}
+
+uint8_t imx_scmi_sensor_max_requests(unsigned int agent_id __unused)
+{
+	return 1U;
+}
+
+extern int upower_read_temperature(uint32_t sensor_id, int32_t *temperature);
+int imx_scmi_sensor_reading_get(uint32_t agent_id __unused, uint16_t sensor_id __unused,
+				 uint32_t *val)
+{
+	int32_t temperature;
+	int ret;
+
+	ret = upower_read_temperature(1, &temperature);
+	if (ret != 0U) {
+		val[0] = 0xFFFFFFFF;
+	} else {
+		val[0] = temperature;
+	}
+
+	val[1] = 0;
+	val[2] = 0;
+	val[3] = 0;
+
+	return ret;
+}
+
+#define SCMI_SENSOR_NAME_LENGTH_MAX	16U
+
+uint32_t imx_scmi_sensor_state(uint32_t agent_id __unused, uint16_t sensor_id __unused)
+{
+	return 1U;
+}
+
+uint32_t imx_scmi_sensor_description_get(uint32_t agent_id __unused, uint16_t desc_index __unused,
+					  struct scmi_sensor_desc *desc __unused)
+{
+	desc->id = 0;
+	desc->attr_low = 0;
+	desc->attr_high = 2;
+	strlcpy((char *)desc->name, "UPOWER-TEMP", 12);
+	desc->power = 0;
+	desc->resolution = 0;
+	desc->min_range_low = 0;
+	desc->min_range_high = 0x80000000;
+	desc->max_range_low = 0xffffffff;
+	desc->max_range_high = 0x7fffffff;
+
+	return 1U;
+}
+
+REGISTER_SCMI_SENSOR_OPS(imx_scmi_sensor_count,
+			 imx_scmi_sensor_max_requests,
+			 NULL,
+			 imx_scmi_sensor_reading_get,
+			 imx_scmi_sensor_description_get,
+			 NULL,
+			 imx_scmi_sensor_state,
+			 NULL);
diff --git a/plat/imx/imx8ulp/upower/upmu.h b/plat/imx/imx8ulp/upower/upmu.h
new file mode 100644
index 0000000..ce4f47e
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upmu.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2021-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MU_H
+#define MU_H
+
+#include <stdint.h>
+
+typedef volatile unsigned int vuint32_t;
+
+/****************************************************************************/
+/*				MODULE: Message Unit			    */
+/****************************************************************************/
+/* VER Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t FEATURE : 16;
+		vuint32_t MINOR : 8;
+		vuint32_t MAJOR : 8;
+	} B;
+} MU_VER_t;
+
+/* PAR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t TR_NUM : 8;
+		vuint32_t RR_NUM : 8;
+		vuint32_t GIR_NUM : 8;
+		vuint32_t FLAG_WIDTH : 8;
+	} B;
+} MU_PAR_t;
+
+/* CR Register */
+typedef union  {
+	vuint32_t R;
+	struct {
+		vuint32_t MUR : 1;
+		vuint32_t MURIE : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_CR_t;
+
+/* SR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t MURS : 1;
+		vuint32_t MURIP : 1;
+		vuint32_t EP : 1;
+		vuint32_t FUP : 1;
+		vuint32_t GIRP : 1;
+		vuint32_t TEP : 1;
+		vuint32_t RFP : 1;
+		vuint32_t CEP : 1;
+		vuint32_t rsrv_1 : 24;
+
+	} B;
+} MU_SR_t;
+
+/* CCR0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t NMI : 1;
+		vuint32_t HR  : 1;
+		vuint32_t HRM : 1;
+		vuint32_t CLKE : 1;
+		vuint32_t RSTH : 1;
+		vuint32_t BOOT : 2;
+		vuint32_t rsrv_1 : 25;
+
+	} B;
+} MU_CCR0_t;
+
+/* CIER0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t rsrv_1 : 1;
+		vuint32_t HRIE : 1;
+		vuint32_t RUNIE : 1;
+		vuint32_t RAIE : 1;
+		vuint32_t HALTIE : 1;
+		vuint32_t WAITIE : 1;
+		vuint32_t STOPIE : 1;
+		vuint32_t PDIE : 1;
+		vuint32_t rsrv_2 : 24;
+	} B;
+} MU_CIER0_t;
+
+/* CSSR0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t NMIC : 1;
+		vuint32_t HRIP : 1;
+		vuint32_t RUN  : 1;
+		vuint32_t RAIP : 1;
+		vuint32_t HALT : 1;
+		vuint32_t WAIT : 1;
+		vuint32_t STOP : 1;
+		vuint32_t PD : 1;
+		vuint32_t rsrv_1 : 24;
+	} B;
+} MU_CSSR0_t;
+
+/* CSR0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t rsrv_1 : 1;
+		vuint32_t HRIP : 1;
+		vuint32_t RUN : 1;
+		vuint32_t RAIP : 1;
+		vuint32_t HALT : 1;
+		vuint32_t WAIT : 1;
+		vuint32_t STOP : 1;
+		vuint32_t PD : 1;
+		vuint32_t rsrv_2 : 24;
+	} B;
+} MU_CSR0_t;
+
+/* FCR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t F0 : 1;
+		vuint32_t F1 : 1;
+		vuint32_t F2 : 1;
+		vuint32_t rsrv_1 : 29;
+	} B;
+} MU_FCR_t;
+
+/* FSR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t F0 : 1;
+		vuint32_t F1 : 1;
+		vuint32_t F2 : 1;
+		vuint32_t rsrv_1 : 29;
+	} B;
+} MU_FSR_t;
+
+/* GIER Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t GIE0 : 1;
+		vuint32_t GIE1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_GIER_t;
+
+/* GCR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t GIR0 : 1;
+		vuint32_t GIR1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_GCR_t;
+
+/* GSR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t GIP0 : 1;
+		vuint32_t GIP1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_GSR_t;
+
+/* TCR Register */
+typedef union{
+	vuint32_t R;
+	struct {
+		vuint32_t TIE0 : 1;
+		vuint32_t TIE1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_TCR_t;
+
+/* TSR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t TE0 : 1;
+		vuint32_t TE1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_TSR_t;
+
+/* RCR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t RIE0 : 1;
+		vuint32_t RIE1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_RCR_t;
+
+/* RSR Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t RF0 : 1;
+		vuint32_t RF1 : 1;
+		vuint32_t rsrv_1 : 30;
+	} B;
+} MU_RSR_t;
+
+/* TR0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t TR_DATA : 32;
+	} B;
+} MU_TR0_t;
+
+/* TR1 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t TR_DATA : 32;
+	} B;
+} MU_TR1_t;
+
+/* RR0 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t RR_DATA : 32;
+	} B;
+} MU_RR0_t;
+
+/* RR1 Register */
+typedef union {
+	vuint32_t R;
+	struct {
+		vuint32_t RR_DATA : 32;
+	} B;
+} MU_RR1_t;
+
+struct MU_t {
+	MU_VER_t VER;
+	MU_PAR_t PAR;
+	MU_CR_t CR;
+	MU_SR_t SR;
+	MU_CCR0_t CCR0;
+	MU_CIER0_t CIER0;
+	MU_CSSR0_t CSSR0;
+	MU_CSR0_t CSR0;
+	uint8_t MU_reserved0[224];
+	MU_FCR_t FCR;
+	MU_FSR_t FSR;
+	uint8_t MU_reserved1[8];
+	MU_GIER_t GIER;
+	MU_GCR_t GCR;
+	MU_GSR_t GSR;
+	uint8_t MU_reserved2[4];
+	MU_TCR_t TCR;
+	MU_TSR_t TSR;
+	MU_RCR_t RCR;
+	MU_RSR_t RSR;
+	uint8_t MU_reserved3[208];
+	MU_TR0_t TR[2];
+	uint8_t MU_reserved4[120];
+	MU_RR0_t RR[2];
+};
+
+#endif /* MU_H */
diff --git a/plat/imx/imx8ulp/upower/upower_api.c b/plat/imx/imx8ulp/upower/upower_api.c
new file mode 100644
index 0000000..ce8c1c8
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upower_api.c
@@ -0,0 +1,3095 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/**
+ * Copyright 2019-2024 NXP
+ *
+ * KEYWORDS: micro-power uPower driver API
+ */
+
+#include <string.h>
+
+#include "upower_api.h"
+#include "upower_soc_defs.h"
+
+/* ---------------------------------------------------------------
+ * Common Macros
+ * ---------------------------------------------------------------
+ */
+
+/* tests Service Group busy */
+#define UPWR_SG_BUSY(sg) ((sg_busy & (1U << (sg))) == 1U)
+
+/* install user callback for the Service Group */
+#define UPWR_USR_CALLB(sg, cb) { user_callback[(sg)] = (cb); }
+
+/* fills up common message header info */
+#define UPWR_MSG_HDR(hdr, sg, fn)   {		\
+	(hdr).domain   = (uint32_t)pwr_domain;	\
+	(hdr).srvgrp   = (sg);			\
+	(hdr).function = (fn); }
+
+/* ---------------------------------------------------------------
+ * Common Data Structures
+ * ---------------------------------------------------------------
+ */
+static soc_domain_t pwr_domain;
+
+static upwr_code_vers_t fw_rom_version;
+static upwr_code_vers_t fw_ram_version;
+static uint32_t fw_launch_option;
+
+/* shared memory buffers */
+#define UPWR_API_BUFFER_SIZE	(MAX_SG_EXCEPT_MEM_SIZE + \
+				 MAX_SG_PWRMGMT_MEM_SIZE + MAX_SG_VOLTM_MEM_SIZE)
+
+/* service group shared mem buffer pointers */
+static void *sh_buffer[UPWR_SG_COUNT];
+
+/* Callbacks registered for each service group :
+ *
+ * NULL means no callback is registered;
+ * for sgrp_callback, it also means the service group is
+ * free to receive a new request.
+ */
+static upwr_callb user_callback[UPWR_SG_COUNT];
+static UPWR_RX_CALLB_FUNC_T sgrp_callback[UPWR_SG_COUNT];
+
+/* request data structures for each service group */
+/* message waiting for TX */
+static upwr_down_max_msg  sg_req_msg[UPWR_SG_COUNT];
+/* waiting message size */
+static unsigned int sg_req_siz[UPWR_SG_COUNT];
+/* response msg  */
+static upwr_up_max_msg sg_rsp_msg[UPWR_SG_COUNT];
+/* response msg size */
+static unsigned int sg_rsp_siz[UPWR_SG_COUNT];
+
+/* tx pending status for each (1 bit per service group) */
+static volatile uint32_t sg_tx_pend;
+/* serv.group of current ongoing Tx, if any */
+static volatile upwr_sg_t  sg_tx_curr;
+
+/* service group busy status, only for this domain (MU index 0) */
+/* SG bit = 1 if group is busy with a request */
+static volatile uint32_t sg_busy;
+
+/* OS-dependent memory allocation function */
+static upwr_malloc_ptr_t os_malloc;
+/* OS-dependent pointer->physical address conversion function */
+static upwr_phyadr_ptr_t os_ptr2phy;
+/* OS-dependent function to lock critical code */
+static upwr_lock_ptr_t os_lock;
+
+/* pointer to MU structure */
+static struct MU_t *mu;
+
+/*
+ * indicates that a transmission was done and is pending; this
+ * bit is necessary because the Tx and Rx interrupts are ORed
+ * together, and there is no way of telling if only Rx interrupt
+ * or both occurred just by looking at the MU status registers
+ */
+static uint32_t  mu_tx_pend;
+
+static UPWR_TX_CALLB_FUNC_T  mu_tx_callb;
+static UPWR_RX_CALLB_FUNC_T  mu_rx_callb;
+
+#define	UPWR_API_INIT_WAIT           (0U) /* waiting for ROM firmware initialization */
+#define	UPWR_API_INITLZED            (1U) /* ROM firmware initialized */
+#define	UPWR_API_START_WAIT          (2U) /* waiting for start services */
+#define	UPWR_API_SHUTDOWN_WAIT       (3U) /* waiting for shutdown */
+#define	UPWR_API_READY               (4U) /* ready to receive service requests */
+
+volatile upwr_api_state_t api_state;
+
+/* default pointer->physical address conversion, returns the same address */
+static void *ptr2phys(const void *ptr)
+{
+	return (void *)ptr;
+}
+
+/* ---------------------------------------------------------------
+ * SHARED MEMORY MANAGEMENT
+ * --------------------------------------------------------------
+ */
+
+/*
+ * upwr_ptr2offset() - converts a pointer (casted to uint64_t) to an
+ * address offset from the  shared memory start. If it does not point
+ * to a shared memory location, the structure pointed is copied to a
+ * buffer in the shared memory,  and the buffer offset is returned.
+ * The 2nd argument is the service group to which the buffer belongs;
+ * The 3rd argument is the size of structure to be copied. The 4th argument
+ * is an offset to apply to the copy destination address. The 5th argument
+ * is ptr before the conversion to physical address. 2nd, 3rd. 4th and 5th
+ * arguments are not used if the 1st one points to a location inside the
+ *  shared memory.
+ */
+
+static uint32_t upwr_ptr2offset(unsigned long ptr,
+				upwr_sg_t sg,
+				size_t siz,
+				size_t offset,
+				const void *vptr)
+{
+	if ((ptr >= UPWR_DRAM_SHARED_BASE_ADDR) &&
+	    ((ptr - UPWR_DRAM_SHARED_BASE_ADDR) < UPWR_DRAM_SHARED_SIZE)) {
+		return (uint32_t)(ptr - UPWR_DRAM_SHARED_BASE_ADDR);
+	}
+
+	/* pointer is outside the shared memory, copy the struct to buffer */
+	(void)memcpy((void *)(offset + (char *)sh_buffer[sg]), (void *)vptr, siz);
+	return (uint32_t)((unsigned long)sh_buffer[sg] + offset - UPWR_DRAM_SHARED_BASE_ADDR);
+}
+
+/*
+ * ---------------------------------------------------------------
+ * INTERRUPTS AND CALLBACKS
+ * Service-group specific callbacks are in their own sections
+ * --------------------------------------------------------------
+ */
+
+/*
+ * upwr_lock()- locks (lock=1) or unlocks (lock=0) a critical code section;
+ * for now it only needs to protect a portion of the code from being
+ * interrupted by the MU.
+ */
+static void upwr_lock(int lock)
+{
+	if (os_lock != NULL) {
+		os_lock(lock);
+	}
+}
+
+/* upwr_exp_isr()- handles the exception interrupt from uPower */
+static void upwr_exp_isr(void)
+{
+}
+
+/* upwr_copy2tr prototype; function definition in auxiliary function section */
+void upwr_copy2tr(struct MU_t *local_mu, const uint32_t *msg, unsigned int size);
+
+#define UPWR_MU_TSR_EMPTY ((uint32_t)((1UL << UPWR_MU_MSG_SIZE) - 1UL))
+
+/* upwr_txrx_isr()- handles both the Tx and Rx MU interrupts */
+void upwr_txrx_isr(void)
+{
+	/* Tx pending and TX register empty */
+	if ((mu_tx_pend != 0UL) && (mu->TSR.R == UPWR_MU_TSR_EMPTY)) {
+		mu_tx_pend = 0UL;
+		/* disable the tx interrupts */
+		mu->TCR.R = 0U;
+		/* urgency flag off, in case it was set */
+		mu->FCR.B.F0 = 0U;
+
+		if (mu_tx_callb != NULL) {
+			mu_tx_callb();
+		}
+	}
+
+	/* RX ISR occurred */
+	if (mu->RSR.R != 0UL) {
+		/* disable the interrupt until data is read */
+		mu->RCR.R = 0U;
+
+		if (mu_rx_callb != NULL) {
+			mu_rx_callb();
+		}
+	}
+}
+
+/**
+ * upwr_next_req() - sends the next pending service request message, if any.
+ *
+ * Called upon MU Tx interrupts, it checks if there is any service request
+ * pending amongst the service groups, and sends the request if needed.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void).
+ */
+static void upwr_next_req(void)
+{
+	upwr_sg_t sg = (upwr_sg_t)0U;
+
+	/* no lock needed here, this is called from an MU ISR */
+	sg_tx_pend &= ~((uint32_t)1UL << sg_tx_curr); /* no longer pending */
+
+	if (sg_tx_pend == 0U) {
+		return; /* no other pending */
+	}
+
+	/* find the next one pending */
+	for (uint32_t mask = 1UL; mask < (1UL << UPWR_SG_COUNT); mask = mask << 1UL) {
+		if ((sg_tx_pend & mask) != 0U) {
+			break;
+		}
+
+		sg = (upwr_sg_t)(sg + 1U);
+	}
+
+	sg_tx_curr = sg;
+	if (upwr_tx((uint32_t *)&sg_req_msg[sg], sg_req_siz[sg], upwr_next_req) < 0) {
+		return; /* leave the Tx pending */
+	}
+}
+
+/**
+ * upwr_mu_int_callback() - general MU interrupt callback.
+ *
+ * Called upon MU Rx interrupts, it calls the Service Group-specific callback,
+ * if any registered, based on the service group field in the received message.
+ * Otherwise, calls the user callback, if any registered.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void).
+ */
+static void upwr_mu_int_callback(void)
+{
+	upwr_sg_t sg;       /* service group number */
+	UPWR_RX_CALLB_FUNC_T sg_callb; /* service group callback */
+	upwr_up_max_msg rxmsg = {0};
+	unsigned int size; /* in words */
+
+	if (upwr_rx((char *)&rxmsg, &size) < 0) {
+		return;
+	}
+
+	sg = (upwr_sg_t)rxmsg.hdr.srvgrp;
+
+	/* copy msg to the service group buffer */
+	msg_copy((char *)&sg_rsp_msg[sg], (char *)&rxmsg, size);
+	sg_rsp_siz[sg] = size;
+
+	/* clear the service group busy status */
+	sg_busy &= ~(1UL << sg); /* no lock needed here, we're in the MU ISR */
+
+	sg_callb = sgrp_callback[sg];
+	if (sg_callb == NULL) {
+		upwr_callb user_callb = user_callback[sg];
+		/* no service group callback; call the user callback if any */
+		if (user_callb == NULL) {
+			goto done; /* no user callback */
+		}
+
+		/* make the user callback */
+		user_callb(sg, rxmsg.hdr.function,
+			   (upwr_resp_t)rxmsg.hdr.errcode,
+			   (size == 2U) ? rxmsg.word2 : rxmsg.hdr.ret);
+		goto done;
+	}
+
+	/*
+	 * finally make the group callback. don't uninstall the group
+	 * callback, it is permanent.
+	 */
+	sg_callb();
+done:
+	if (rxmsg.hdr.errcode == UPWR_RESP_SHUTDOWN) { /* shutdown error: */
+		/*
+		 * change the API state automatically. so new requests
+		 * are rejected by the API immediately
+		 */
+		api_state = UPWR_API_INITLZED;
+	}
+}
+
+/**
+ * upwr_srv_req() - sends a service request message.
+ * @sg: message service group.
+ * @msg: pointer to the message
+ * @size: message size in 32-bit words.
+ *
+ * The message is sent right away if possible, or gets pending to be sent later.
+ * If pending, the message is stored in sg_req_msg and will be sent when the
+ * MU transmission buffer is clear and there are no other pending messages
+ * from higher priority service groups.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void)
+ */
+static void upwr_srv_req(upwr_sg_t sg,
+			 uint32_t *msg,
+			 unsigned int size)
+{
+	int rc;
+
+	upwr_lock(1);
+	sg_busy |= (uint32_t)1U << sg;
+	upwr_lock(0);
+
+	rc = upwr_tx(msg, size, upwr_next_req);
+	if (rc  < 0) {
+		/* queue full, make the transmission pending */
+		msg_copy((char *)&sg_req_msg[sg], (char *)msg, size);
+		sg_req_siz[sg] = size;
+
+		upwr_lock(1);
+		sg_tx_curr = sg;
+		sg_tx_pend |= (uint32_t)1U << sg;
+		upwr_lock(0);
+
+		return;
+	}
+}
+
+/**---------------------------------------------------------------
+ * INITIALIZATION, CONFIGURATION
+ *
+ * A reference uPower initialization sequence goes as follows:
+ *
+ * 1. host CPU calls upwr_init.
+ * 2. (optional) host checks the ROM version and SoC code calling upwr_vers(...)
+ *    and optionally performs any configuration or workaround accordingly.
+ * 3. host CPU calls upwr_start to start the uPower services, passing a
+ *    service option number.
+ *    If no RAM code is loaded or it has no service options, the launch option
+ *    number passed must be 0, which will start the services available in ROM.
+ *    upwr_start also receives a pointer to a callback called by the API
+ *    when the firmware is ready to receive service requests.
+ *    The callback may be replaced by polling, calling upwr_req_status in a loop
+ *    or upwr_poll_req_status; in this case the callback pointer may be NULL.
+ *    A host may call upwr_start even if the services were already started by
+ *    any host: if the launch option is the same, the response will be ok,
+ *    but will indicate error if the services were already started with a
+ *    different launch option.
+ * 4. host waits for the callback calling, or polling finishing;
+ *    if no error is returned, it can start making service calls using the API.
+ *
+ * Variations on that reference sequence are possible:
+ *  - the uPower services can be started using the ROM code only, which includes
+ *    the basic Power Management services, among others, with launch option
+ *    number = 0.
+ *    The code RAM can be loaded while these services are running and,
+ *    when the loading is done, the services can be re-started with these 2
+ *    requests executed in order: upwr_xcp_shutdown and upwr_start,
+ *    using the newly loaded RAM code (launch option > 0).
+ *
+ * NOTE: the initialization call upwr_init is not effective and
+ *       returns error when called after the uPower services are started.
+ */
+
+/**
+ * upwr_start_callb() - internal callback for the Rx message from uPower
+ * that indicates the firmware is ready to receive the start commands.
+ * It calls the user callbacks registered in the upwr_start_boot and upwr_start
+ * call.
+ */
+void upwr_start_callb(void)
+{
+	switch (api_state) {
+	case UPWR_API_START_WAIT: {
+		upwr_rdy_callb start_callb = (upwr_rdy_callb)user_callback[UPWR_SG_EXCEPT];
+		upwr_ready_msg *msg = (upwr_ready_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT];
+
+		fw_ram_version.soc_id = fw_rom_version.soc_id;
+		fw_ram_version.vmajor = msg->args.vmajor;
+		fw_ram_version.vminor = msg->args.vminor;
+		fw_ram_version.vfixes = msg->args.vfixes;
+
+		/*
+		 * vmajor == vminor == vfixes == 0 indicates start error
+		 * in this case, go back to the INITLZED state
+		 */
+		if ((fw_ram_version.vmajor != 0U) ||
+		    (fw_ram_version.vminor != 0U) ||
+		    (fw_ram_version.vfixes != 0U)) {
+			api_state = UPWR_API_READY;
+
+			/*
+			 * initialization is over:
+			 * uninstall the user callback just in case
+			 */
+			UPWR_USR_CALLB(UPWR_SG_EXCEPT, NULL);
+
+			if (fw_launch_option == 0U) {
+				/*
+				 * launched ROM firmware:
+				 * RAM fw versions must be all 0s
+				 */
+				fw_ram_version.vmajor = 0U;
+				fw_ram_version.vminor = 0U;
+				fw_ram_version.vfixes = 0U;
+			}
+		} else {
+			api_state = UPWR_API_INITLZED;
+		}
+
+		start_callb(msg->args.vmajor, msg->args.vminor, msg->args.vfixes);
+	}
+	break;
+
+	case UPWR_API_SHUTDOWN_WAIT: {
+		upwr_callb user_callb = (upwr_callb)user_callback[UPWR_SG_EXCEPT];
+		upwr_shutdown_msg *msg = (upwr_shutdown_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT];
+
+		if ((upwr_resp_t)msg->hdr.errcode == UPWR_RESP_OK) {
+			api_state = UPWR_API_INITLZED;
+		}
+
+		if (user_callb != NULL) {
+			user_callb(UPWR_SG_EXCEPT, UPWR_XCP_SHUTDOWN,
+				   (upwr_resp_t)msg->hdr.errcode, 0U);
+		}
+	}
+	break;
+
+	case UPWR_API_READY:
+	{
+		upwr_callb user_callb = (upwr_callb)user_callback[UPWR_SG_EXCEPT];
+		upwr_up_max_msg *msg = (upwr_up_max_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT];
+
+		if (user_callb != NULL) {
+			user_callb(UPWR_SG_EXCEPT, msg->hdr.function,
+				   (upwr_resp_t)msg->hdr.errcode,
+				   (int)((sg_rsp_siz[UPWR_SG_EXCEPT] == 2U) ?
+					 msg->word2 : msg->hdr.ret));
+		}
+	}
+	break;
+
+	default:
+		break;
+	}
+}
+
+/**
+ * upwr_init() - API initialization; must be the first API call after reset.
+ * @domain: SoC-dependent CPU domain id; identifier used by the firmware in
+ * many services. Defined by SoC-dependent type soc_domain_t found in
+ * upower_soc_defs.h.
+ * @muptr: pointer to the MU instance.
+ * @mallocptr: pointer to the memory allocation function
+ * @physaddrptr: pointer to the function to convert pointers to
+ * physical addresses. If NULL, no conversion is made (pointer=physical address)
+ * @isrinstptr: pointer to the function to install the uPower ISR callbacks;
+ * the function receives the pointers to the MU tx/rx and Exception ISRs
+ * callbacks, which must be called from the actual system ISRs.
+ * The function pointed by isrinstptr must also enable the interrupt at the
+ * core/interrupt controller, but must not enable the interrupt at the MU IP.
+ * The system ISRs are responsible for dealing with the interrupt controller,
+ * performing any other context save/restore, and any other housekeeping.
+ * @lockptr: pointer to a function that prevents MU interrupts (if argrument=1)
+ * or allows it (if argument=0). The API calls this function to make small
+ * specific code portions thread safe. Only MU interrupts must be avoided,
+ * the code may be suspended for other reasons.
+ * If no MU interrupts can happen during the execution of an API call or
+ * callback, even if enabled, for some other reason (e.g. interrupt priority),
+ * then this argument may be NULL.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if failed to allocate memory, or use some other resource.
+ *        -2 if any argument is invalid.
+ *        -3 if failed to send the ping message.
+ *        -4 if failed to receive the initialization message, or was invalid
+ */
+int upwr_init(soc_domain_t domain, struct MU_t *muptr,
+	      const upwr_malloc_ptr_t mallocptr,
+	      const upwr_phyadr_ptr_t phyadrptr,
+	      const upwr_inst_isr_ptr_t isrinstptr,
+	      const upwr_lock_ptr_t lockptr)
+{
+	uint32_t j;
+
+	upwr_sg_t sg; /* service group number */
+	unsigned int size;
+	unsigned long dom_buffer_base = (domain == RTD_DOMAIN) ? UPWR_API_BUFFER_BASE :
+					((UPWR_API_BUFFER_ENDPLUS + UPWR_API_BUFFER_BASE) / 2U);
+
+	upwr_init_msg *msg = (upwr_init_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT];
+
+	mu = muptr;
+	/*
+	 * Disable tx and rx interrupts in case not called
+	 * 1st time after reset
+	 */
+	mu->TCR.R = mu->RCR.R = 0U;
+
+	os_malloc = mallocptr;
+	os_ptr2phy = (phyadrptr == (upwr_phyadr_ptr_t)NULL) ? ptr2phys : phyadrptr;
+
+	os_lock = lockptr;
+	api_state = UPWR_API_INIT_WAIT;
+	sg_busy = 0UL;
+	pwr_domain = domain;
+
+	/* initialize the versions, in case they are polled */
+	fw_rom_version.soc_id = 0U;
+	fw_rom_version.vmajor = 0U;
+	fw_rom_version.vminor = 0U;
+	fw_rom_version.vfixes = 0U;
+
+	fw_ram_version.soc_id = 0U;
+	fw_ram_version.vmajor = 0U;
+	fw_ram_version.vminor = 0U;
+	fw_ram_version.vfixes = 0U;
+
+	mu_tx_pend = (uint32_t)0U;
+	sg_tx_pend = (uint32_t)0U;
+
+	sg_tx_curr = UPWR_SG_COUNT; /* means none here */
+
+	sh_buffer[UPWR_SG_EXCEPT] = (void *)(unsigned long)dom_buffer_base;
+	sh_buffer[UPWR_SG_PWRMGMT] = (void *)(unsigned long)(dom_buffer_base +
+					      MAX_SG_EXCEPT_MEM_SIZE);
+	sh_buffer[UPWR_SG_DELAYM] = NULL;
+	sh_buffer[UPWR_SG_VOLTM] = (void *)(unsigned long)(dom_buffer_base +
+					    MAX_SG_EXCEPT_MEM_SIZE + MAX_SG_PWRMGMT_MEM_SIZE);
+	sh_buffer[UPWR_SG_CURRM] = NULL;
+	sh_buffer[UPWR_SG_TEMPM] = NULL;
+	sh_buffer[UPWR_SG_DIAG] = NULL;
+
+	/* (no buffers service groups other than xcp and pwm for now) */
+	for (j = 0; j < UPWR_SG_COUNT; j++) {
+		user_callback[j] = NULL;
+		/* service group Exception gets the initialization callbacks */
+		sgrp_callback[j] = (j == UPWR_SG_EXCEPT) ? upwr_start_callb : NULL;
+		/* response messages with an initial consistent content */
+		sg_rsp_msg[j].hdr.errcode = UPWR_RESP_SHUTDOWN;
+	}
+
+	/* init message already received, assume takss are running on upower */
+	if (mu->FSR.B.F0 != 0U) {
+		/* send a ping message down to get the ROM version back */
+		upwr_xcp_ping_msg ping_msg = {0};
+
+		ping_msg.hdr.domain = pwr_domain;
+		ping_msg.hdr.srvgrp = UPWR_SG_EXCEPT;
+		ping_msg.hdr.function = UPWR_XCP_PING;
+
+		if (mu->RSR.B.RF0 != 0U) { /* first clean any Rx message left over */
+			(void)upwr_rx((char *)msg, &size);
+		}
+
+		/* wait any TX left over to be sent */
+		while (mu->TSR.R != UPWR_MU_TSR_EMPTY) {
+		}
+
+		/*
+		 * now send the ping message;
+		 * do not use upwr_tx, which needs API initialized;
+		 * just write to the MU TR register(s)
+		 */
+		mu->FCR.B.F0 = 1U; /* flag urgency status */
+		upwr_copy2tr(mu, (uint32_t *)&ping_msg, sizeof(ping_msg) / 4U);
+	}
+
+	do {
+		/*
+		 * poll for the MU Rx status: wait for an init message, either
+		 * 1st sent from uPower after reset or as a response to a ping
+		 */
+		while (mu->RSR.B.RF0 == 0U) {
+		}
+
+		/* urgency status off, in case it was set */
+		mu->FCR.B.F0 = 0U;
+
+		if (upwr_rx((char *)msg, &size) < 0) {
+			return -4;
+		}
+
+		if (size != (sizeof(upwr_init_msg) / 4U)) {
+			if (mu->FSR.B.F0 != 0U) {
+				continue; /* discard left over msg */
+			} else {
+				return -4;
+			}
+		}
+
+		sg = (upwr_sg_t)msg->hdr.srvgrp;
+		if (sg != UPWR_SG_EXCEPT) {
+			if (mu->FSR.B.F0 != 0U) {
+				continue; /* discard left over msg */
+			} else {
+				return -4;
+			}
+		}
+
+		if ((upwr_xcp_f_t)msg->hdr.function != UPWR_XCP_INIT) {
+			if (mu->FSR.B.F0 != 0U) {
+				continue; /* discard left over msg */
+			} else {
+				return -4;
+			}
+		}
+
+		break;
+	} while (true);
+
+	fw_rom_version.soc_id = msg->args.soc;
+	fw_rom_version.vmajor = msg->args.vmajor;
+	fw_rom_version.vminor = msg->args.vminor;
+	fw_rom_version.vfixes = msg->args.vfixes;
+
+	if (upwr_rx_callback(upwr_mu_int_callback) < 0) {
+		/* catastrophic error, but is it possible to happen? */
+		return -1;
+	}
+
+	mu_tx_callb = NULL; /* assigned on upwr_tx */
+
+	/* install the ISRs and enable the interrupts */
+	isrinstptr(upwr_txrx_isr, upwr_exp_isr);
+
+	/* enable only RR[0] receive interrupt */
+	mu->RCR.R = 1U;
+
+	api_state = UPWR_API_INITLZED;
+
+	return 0;
+}
+
+/**
+ * upwr_start() - Starts the uPower services.
+ * @launchopt: a number to select between multiple launch options,
+ * that may define, among other things, which services will be started,
+ * or which services implementations, features etc.
+ * launchopt = 0 selects a subset of services implemented in ROM;
+ * any other number selects service sets implemented in RAM, launched
+ * by the firmware function ram_launch; if an invalid launchopt value is passed,
+ * no services are started, and the callback returns error (see below).
+ * @rdycallb: pointer to the callback to be called when the uPower is ready
+ * to receive service requests. NULL if no callback needed.
+ * The callback receives as arguments the RAM firmware version numbers.
+ * If all 3 numbers (vmajor, vminor, vfixes) are 0, that means the
+ * service launching failed.
+ * Firmware version numbers will be the same as ROM if launchopt = 0,
+ * selecting the ROM services.
+ *
+ * upwr_start can be called by any domain even if the services are already
+ * started: it has no effect, returning success, if the launch option is the
+ * same as the one that actually started the service, and returns error if
+ * called with a different option.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if a resource failed,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+int upwr_start(uint32_t launchopt, const upwr_rdy_callb rdycallb)
+{
+	upwr_start_msg txmsg = {0};
+
+	if (api_state != UPWR_API_INITLZED) {
+		return -3;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, (upwr_callb)rdycallb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_START);
+
+	txmsg.hdr.arg = fw_launch_option = launchopt;
+
+	if (upwr_tx((uint32_t *)&txmsg, sizeof(txmsg) / 4U, NULL) < 0) {
+		/* catastrophic error, but is it possible to happen? */
+		return -1;
+	}
+
+	api_state = UPWR_API_START_WAIT;
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * EXCEPTION SERVICE GROUP
+ */
+
+/**
+ * upwr_xcp_config() - Applies general uPower configurations.
+ * @config: pointer to the uPower SoC-dependent configuration struct
+ * upwr_xcp_config_t defined in upower_soc_defs.h. NULL may be passed, meaning
+ * a request to read the configuration, in which case it appears in the callback
+ * argument ret, or can be pointed by argument retptr in the upwr_req_status and
+ * upwr_poll_req_status calls, casted to upwr_xcp_config_t.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the configuration, or NULL if no callback needed (polling used instead).
+ *
+ * Some configurations are targeted for a specific domain (see the struct
+ * upwr_xcp_config_t definition in upower_soc_defs.h); this call has implicit
+ * domain target (the same domain from which is called).
+ *
+ * The return value is always the current configuration value, either in a
+ * read-only request (config = NULL) or after setting a new configuration
+ * (non-NULL config).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_config(const upwr_xcp_config_t *config, const upwr_callb callb)
+{
+	upwr_xcp_config_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	if (config == NULL) {
+		txmsg.hdr.arg = 1U;         /* 1= read, txmsg.word2 ignored */
+	} else {
+		txmsg.hdr.arg = 0U;         /* 1= write */
+		txmsg.word2   = config->R;
+	}
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_CONFIG);
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_sw_alarm() - Makes uPower issue an alarm interrupt to given domain.
+ * @domain: identifier of the domain to alarm. Defined by SoC-dependent type
+ * soc_domain_t found in upower_soc_defs.h.
+ * @code: alarm code. Defined by SoC-dependent type upwr_alarm_t found in
+ * upower_soc_defs.h.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the alarm, or NULL if no callback needed (polling used instead).
+ *
+ * The function requests the uPower to issue an alarm of the given code as if
+ * it had originated internally. This service is useful mainly to test the
+ * system response to such alarms, or to make the system handle a similar alarm
+ * situation detected externally to uPower.
+ *
+ * The system ISR/code handling the alarm may retrieve the alarm code by calling
+ * the auxiliary function upwr_alarm_code.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_sw_alarm(soc_domain_t domain,
+		      upwr_alarm_t code,
+		      const upwr_callb callb)
+{
+	upwr_xcp_swalarm_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SW_ALARM);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)code;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_set_ddr_retention() - M33/A35 can use this API to set/clear ddr retention
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set ddr retention, false clear ddr retention.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_ddr_retention(soc_domain_t domain,
+			       uint32_t enable,
+			       const upwr_callb callb)
+{
+	upwr_xcp_ddr_retn_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_DDR_RETN);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)enable;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_set_mipi_dsi_ena() - M33/A35 can use this API to set/clear mipi dsi ena
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set ddr retention, false clear ddr retention.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_mipi_dsi_ena(soc_domain_t domain,
+			      uint32_t enable,
+			      const upwr_callb callb)
+{
+	upwr_xcp_set_mipi_dsi_ena_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_MIPI_DSI_ENA);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)enable;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_get_mipi_dsi_ena() - M33/A35 can use this API to get mipi dsi ena status
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_get_mipi_dsi_ena(soc_domain_t domain, const upwr_callb callb)
+{
+	upwr_xcp_get_mipi_dsi_ena_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_GET_MIPI_DSI_ENA);
+	txmsg.hdr.domain = (uint32_t)domain;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_set_osc_mode() - M33/A35 can use this API to set uPower OSC mode
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @osc_mode, 0 means low frequency, not 0 means high frequency.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_osc_mode(soc_domain_t domain,
+			  uint32_t osc_mode,
+			  const upwr_callb callb)
+{
+	upwr_xcp_set_osc_mode_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_OSC_MODE);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)osc_mode;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_set_rtd_use_ddr() - M33 call this API to inform uPower, M33 is using ddr
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @is_use_ddr: not 0, true, means that RTD is using ddr. 0, false, means that, RTD
+ * is not using ddr.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_rtd_use_ddr(soc_domain_t domain,
+			     uint32_t is_use_ddr,
+			     const upwr_callb callb)
+{
+	upwr_xcp_rtd_use_ddr_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_RTD_USE_DDR);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)is_use_ddr;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_set_rtd_apd_llwu() - M33/A35 can use this API to set/clear rtd_llwu apd_llwu
+ * @domain: set which domain (RTD_DOMAIN, APD_DOMAIN) LLWU.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set rtd_llwu or apd_llwu, false clear rtd_llwu or apd_llwu.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_rtd_apd_llwu(soc_domain_t domain,
+			      uint32_t enable,
+			      const upwr_callb callb)
+{
+	upwr_xcp_rtd_apd_llwu_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_RTD_APD_LLWU);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = (uint32_t)enable;
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_shutdown() - Shuts down all uPower services and power mode tasks.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the shutdown, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * At the callback the uPower/API is back to initialization/start-up phase,
+ * so service request calls return error.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_shutdown(const upwr_callb callb)
+{
+	upwr_xcp_shutdown_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SHUTDOWN);
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	api_state = UPWR_API_SHUTDOWN_WAIT;
+
+	return 0;
+}
+
+/**
+ * upwr_xcp_i2c_access() - Performs an access through the uPower I2C interface.
+ * @addr: I2C slave address, up to 10 bits.
+ * @data_size: determines the access direction and data size in bytes, up to 4;
+ * negetive data_size determines a read  access with size -data_size;
+ * positive data_size determines a write access with size  data_size;
+ * data_size=0 is invalid, making the service return error UPWR_RESP_BAD_REQ.
+ * @subaddr_size: size of the sub-address in bytes, up to 4; if subaddr_size=0,
+ * no subaddress is used.
+ * @subaddr: sub-address, only used if subaddr_size > 0.
+ * @wdata: write data, up to 4 bytes; ignored if data_size < 0 (read)
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the access, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * The service performs a read (data_size < 0) or a write (data_size > 0) of
+ * up to 4 bytes on the uPower I2C interface. The data read from I2C comes via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * Sub-addressing is supported, with sub-address size determined by the argument
+ * subaddr_size, up to 4 bytes. Sub-addressing is not used if subaddr_size=0.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_i2c_access(uint16_t addr,
+			int8_t data_size,
+			uint8_t subaddr_size,
+			uint32_t subaddr,
+			uint32_t wdata,
+			const upwr_callb callb)
+{
+	unsigned long ptrval = (unsigned long)sh_buffer[UPWR_SG_EXCEPT];
+	upwr_i2c_access *i2c_acc_ptr = (upwr_i2c_access *)ptrval;
+	upwr_pwm_pmiccfg_msg  txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_I2C);
+
+	i2c_acc_ptr->addr = addr;
+	i2c_acc_ptr->subaddr = subaddr;
+	i2c_acc_ptr->subaddr_size = subaddr_size;
+	i2c_acc_ptr->data = wdata;
+	i2c_acc_ptr->data_size = data_size;
+
+	txmsg.ptr = upwr_ptr2offset(ptrval,
+				    UPWR_SG_EXCEPT,
+				    (size_t)sizeof(upwr_i2c_access),
+				    0U,
+				    i2c_acc_ptr);
+
+	upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * VOLTAGE MANAGERMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_vtm_pmic_cold_reset() -request cold reset the pmic.
+ * pmic will power cycle all the regulators
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to cold reset the pmic.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_pmic_cold_reset(upwr_callb callb)
+{
+	upwr_volt_pmic_cold_reset_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMIC_COLD_RESET);
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_set_pmic_mode() -request uPower set pmic mode
+ * @pmic_mode: the target mode need to be set
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to set pmic mode
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_set_pmic_mode(uint32_t pmic_mode, upwr_callb callb)
+{
+	upwr_volt_pmic_set_mode_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_SET_PMIC_MODE);
+
+	txmsg.hdr.arg = pmic_mode;
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_chng_pmic_voltage() - Changes the voltage of a given rail.
+ * @rail: pmic rail id.
+ * @volt: the target voltage of the given rail, accurate to uV
+ * If pass volt value 0, means that power off this rail.
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to change the voltage of the given rail.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_chng_pmic_voltage(uint32_t rail, uint32_t volt, upwr_callb callb)
+{
+	upwr_volt_pmic_set_volt_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_CHNG_PMIC_RAIL_VOLT);
+
+	txmsg.args.rail = rail;
+
+	txmsg.args.volt = (volt + PMIC_VOLTAGE_MIN_STEP - 1U) / PMIC_VOLTAGE_MIN_STEP;
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_get_pmic_voltage() - Get the voltage of a given rail.
+ * @rail: pmic rail id.
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to get the voltage of the given rail.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The voltage data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_get_pmic_voltage(uint32_t rail, upwr_callb callb)
+{
+	upwr_volt_pmic_get_volt_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_GET_PMIC_RAIL_VOLT);
+
+	txmsg.args.rail = rail;
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_power_measure() - request uPower to measure power consumption
+ * @ssel: This field determines which power switches will have their currents
+ * sampled to be accounted for a
+ * current/power measurement. Support 0~7
+
+ * SSEL bit #	Power Switch
+ * 0	M33 core complex/platform/peripherals
+ * 1	Fusion Core and Peripherals
+ * 2	A35[0] core complex
+ * 3	A35[1] core complex
+ * 4	3DGPU
+ * 5	HiFi4
+ * 6	DDR Controller (PHY and PLL NOT included)
+ * 7	PXP, EPDC
+ *
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to measure power consumption
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The power consumption data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Accurate to uA
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_power_measure(uint32_t ssel, upwr_callb callb)
+{
+	upwr_volt_pmeter_meas_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMETER_MEAS);
+
+	txmsg.hdr.arg = ssel;
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_vmeter_measure() - request uPower to measure voltage
+ * @vdetsel: Voltage Detector Selector, support 0~3
+ * 00b - RTD sense point
+   01b - LDO output
+   10b - APD domain sense point
+   11b - AVD domain sense point
+   Refer to upower_defs.h
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to use vmeter to measure voltage
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The voltage data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Refer to RM COREREGVL (Core Regulator Voltage Level)
+ * uPower return VDETLVL to user, user can calculate the real voltage:
+ *
+0b000000(0x00) - 0.595833V
+0b100110(0x26) - 1.007498V
+<value> - 0.595833V + <value>x10.8333mV
+0b110010(0x32) - 1.138V
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_vmeter_measure(uint32_t vdetsel, upwr_callb callb)
+{
+	upwr_volt_vmeter_meas_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_VMETER_MEAS);
+
+	txmsg.hdr.arg = vdetsel;
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_vtm_pmic_config() - Configures the SoC PMIC (Power Management IC).
+ * @config: pointer to a PMIC-dependent struct defining the PMIC configuration.
+ * @size:   size of the struct pointed by config, in bytes.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change/define the PMIC configuration.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_pmic_config(const void *config, uint32_t size, upwr_callb callb)
+{
+	upwr_pwm_pmiccfg_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_VOLTM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMIC_CONFIG);
+
+	ptrval = (unsigned long)os_ptr2phy(config);
+	if (ptrval == 0UL) {
+		return -2; /* pointer conversion failed */
+	}
+
+	txmsg.ptr = upwr_ptr2offset(ptrval,
+				    UPWR_SG_VOLTM,
+				    (size_t)size,
+				    0U,
+				    config);
+
+	upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * TEMPERATURE MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_tpm_get_temperature() - request uPower to get temperature of one temperature sensor
+ * @sensor_id: temperature sensor ID, support 0~2
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to measure temperature
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_TEMPM as the service group argument.
+ *
+ * The temperature data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * uPower return TSEL to the caller (M33 or A35), caller calculate the real temperature
+ * Tsh = 0.000002673049*TSEL[7:0]^3 + 0.0003734262*TSEL[7:0]^2 +
+0.4487042*TSEL[7:0] - 46.98694
+ *
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_tpm_get_temperature(uint32_t sensor_id, upwr_callb callb)
+{
+	upwr_temp_get_cur_temp_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_TEMPM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_TEMPM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_TEMPM, UPWR_TEMP_GET_CUR_TEMP);
+
+	txmsg.args.sensor_id = sensor_id;
+
+	upwr_srv_req(UPWR_SG_TEMPM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * DELAY MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_dlm_get_delay_margin() - request uPower to get delay margin
+ * @path: The critical path
+ * @index: Use whitch delay meter
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to get delay margin
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The delay margin data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_get_delay_margin(uint32_t path, uint32_t index, upwr_callb callb)
+{
+	upwr_dmeter_get_delay_margin_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_DELAYM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_DMETER_GET_DELAY_MARGIN);
+
+	txmsg.args.path = path;
+	txmsg.args.index = index;
+
+	upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_dlm_set_delay_margin() - request uPower to set delay margin
+ * @path: The critical path
+ * @index: Use whitch delay meter
+ * @delay_margin: the value of delay margin
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to set delay margin
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The result of the corresponding critical path,  failed or not  read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_set_delay_margin(uint32_t path, uint32_t index, uint32_t delay_margin,
+			      upwr_callb callb)
+{
+	upwr_dmeter_set_delay_margin_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_DELAYM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_DMETER_SET_DELAY_MARGIN);
+
+	txmsg.args.path = path;
+	txmsg.args.index = index;
+	txmsg.args.dm = delay_margin;
+
+	upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_dlm_process_monitor() - request uPower to do process monitor
+ * @chain_sel: Chain Cell Type Selection
+ * Select the chain to be used for the clock signal generation.
+ * Support two types chain cell, 0~1
+0b - P4 type delay cells selected
+1b - P16 type delay cells selected
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to do process monitor
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The result of process monitor,  failed or not  read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_process_monitor(uint32_t chain_sel, upwr_callb callb)
+{
+	upwr_pmon_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_DELAYM, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_PMON_REQ);
+
+	txmsg.args.chain_sel = chain_sel;
+
+	upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * POWER MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_pwm_dom_power_on() - Commands uPower to power on the platform of other
+ * domain (not necessarily its core(s)); does not release the core reset.
+ * @domain: identifier of the domain to power on. Defined by SoC-dependent type
+ * soc_domain_t found in upower_soc_defs.h.
+ * @boot_start: must be 1 to start the domain core(s) boot(s), releasing
+ * its (their) resets, or 0 otherwise.
+ * @pwroncallb: pointer to the callback to be called when the uPower has
+ * finished the power on procedure, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_dom_power_on(soc_domain_t domain,
+			  int boot_start,
+			  const upwr_callb pwroncallb)
+{
+	upwr_pwm_dom_pwron_msg txmsg = {0};
+
+	if (pwr_domain == domain) {
+		return -2;
+	}
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, (upwr_callb)pwroncallb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_DOM_PWRON);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg    = (uint32_t)boot_start;
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_boot_start() - Commands uPower to release the reset of other CPU(s),
+ * starting their boots.
+ * @domain: identifier of the domain to release the reset. Defined by
+ * SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @bootcallb: pointer to the callback to be called when the uPower has finished
+ * the boot start procedure, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * The callback calling doesn't mean the CPUs boots have finished:
+ * it only indicates that uPower released the CPUs resets, and can receive
+ * other power management service group requests.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_boot_start(soc_domain_t domain, const upwr_callb  bootcallb)
+{
+	upwr_pwm_boot_start_msg txmsg = {0};
+
+	if (pwr_domain == domain) {
+		return -2;
+	}
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, (upwr_callb)bootcallb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_BOOT);
+	txmsg.hdr.domain = (uint32_t)domain;
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_param() - Changes Power Management parameters.
+ * @param: pointer to a parameter structure upwr_pwm_param_t, SoC-dependent,
+ * defined in upwr_soc_defines.h. NULL may be passed, meaning
+ * a request to read the parameter set, in which case it appears in the callback
+ * argument ret, or can be pointed by argument retptr in the upwr_req_status and
+ * upwr_poll_req_status calls, casted to upwr_pwm_param_t.
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The return value is always the current parameter set value, either in a
+ * read-only request (param = NULL) or after setting a new parameter
+ * (non-NULL param).
+ *
+ * Some parameters may be targeted for a specific domain (see the struct
+ * upwr_pwm_param_t definition in upower_soc_defs.h); this call has implicit
+ * domain target (the same domain from which is called).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_param(upwr_pwm_param_t *param, const upwr_callb callb)
+{
+	upwr_pwm_param_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PARAM);
+
+	if (param == NULL) {
+		txmsg.hdr.arg = 1U;        /* 1= read, txmsg.word2 ignored */
+	} else {
+		txmsg.hdr.arg = 0U;        /* 1= write */
+		txmsg.word2 = param->R; /* just 1 word, so that's ok */
+	}
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_chng_reg_voltage() - Changes the voltage at a given regulator.
+ * @reg: regulator id.
+ * @volt: voltage value; value unit is SoC-dependent, converted from mV by the
+ * macro UPWR_VTM_MILIV, or from micro-Volts by the macro UPWR_VTM_MICROV,
+ * both macros in upower_soc_defs.h
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to change the voltage of the given regulator.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_chng_reg_voltage(uint32_t reg, uint32_t volt, upwr_callb callb)
+{
+	upwr_pwm_volt_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_VOLT);
+
+	txmsg.args.reg = reg;
+	txmsg.args.volt = volt;
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_freq_setup() - Determines the next frequency target for a given
+ *                         domain and current frequency.
+ * @domain: identifier of the domain to change frequency. Defined by
+ * SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @rail: the pmic regulator number for the target domain.
+ * @stage: DVA adjust stage
+ * refer to upower_defs.h "DVA adjust stage"
+ * @target_freq: the target adjust frequency, accurate to MHz
+ *
+ * refer to upower_defs.h structure definition upwr_pwm_freq_msg
+ *
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The DVA algorithm is broken down into two phases.
+ * The first phase uses a look up table to get a safe operating voltage
+ * for the requested frequency.
+ * This voltage is guaranteed to work over process and temperature.
+ *
+ * The second step of the second phase is to measure the temperature
+ * using the uPower Temperature Sensor module.
+ * This is accomplished by doing a binary search of the TSEL bit field
+ * in the Temperature Measurement Register (TMR).
+ * The search is repeated until the THIGH bit fields in the same register change value.
+ * There are 3 temperature sensors in 8ULP (APD, AVD, and RTD).
+ *
+ *
+ * The second phase is the fine adjust of the voltage.
+ * This stage is entered only when the new frequency requested
+ * by application was already set as well as the voltage for that frequency.
+ * The first step of the fine adjust is to find what is the current margins
+ * for the monitored critical paths, or, in other words,
+ * how many delay cells will be necessary to generate a setup-timing violation.
+ * The function informs uPower that the given domain frequency has changed or
+ * will change to the given value. uPower firmware will then adjust voltage and
+ * bias to cope with the new frequency (if decreasing) or prepare for it
+ * (if increasing). The function must be called after decreasing the frequency,
+ * and before increasing it. The actual increase in frequency must not occur
+ * before the service returns its response.
+ *
+ * So, for increase clock frequency case, user need to call this API twice,
+ * the first stage gross adjust and the second stage fine adjust.
+ *
+ * for reduce clock frequency case, user can only call this API once,
+ * full stage (combine gross stage and fine adjust)
+ *
+ * The request is executed if arguments are within range.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_freq_setup(soc_domain_t domain, uint32_t rail, uint32_t stage, uint32_t target_freq,
+			upwr_callb   callb)
+{
+	upwr_pwm_freq_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_FREQ);
+
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.args.rail = rail;
+	txmsg.args.stage = stage;
+	txmsg.args.target_freq = target_freq;
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_power_on()- Powers on (not off) one or more switches and ROM/RAMs.
+ * @swton: pointer to an array of words that tells which power switches to
+ *  turn on. Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective switch must be turned on,
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no switch will be changed,
+ *  unless a memory that it feeds must be turned on.
+ *  WARNING: swton must not point to the first shared memory address.
+ * @memon: pointer to an array of words that tells which memories to turn on.
+ *  Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective memory must be turned on, both array and
+ *  periphery logic;
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no memory will be changed.
+ *  WARNING: memon must not point to the first shared memory address.
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn on the PMC and memory array/peripheral
+ * switches that control their power, as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate memory power state related to overall system state.
+ *
+ * If a memory is requested to turn on, but the power switch that feeds that
+ * memory is not, the power switch will be turned on anyway, if the pwron
+ * array is not provided (that is, if pwron is NULL).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+
+int upwr_pwm_power_on(const uint32_t swton[],
+		      const uint32_t memon[],
+		      upwr_callb     callb)
+{
+	upwr_pwm_pwron_msg txmsg = {0};
+	unsigned long  ptrval = 0UL; /* needed for X86, ARM64 */
+	size_t stsize = 0U;
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PWR_ON);
+
+	ptrval = (unsigned long)os_ptr2phy((void *)swton);
+	if (swton == NULL) {
+		txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  (stsize = UPWR_PMC_SWT_WORDS * 4U),
+						  0U,
+						  swton);
+	}
+
+	ptrval = (unsigned long)os_ptr2phy((void *)memon);
+	if (memon == NULL) {
+		txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */
+
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  UPWR_PMC_MEM_WORDS * 4U,
+						  stsize,
+						  memon);
+	}
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_power_off()- Powers off (not on) one or more switches and ROM/RAMs.
+ * @swtoff: pointer to an array of words that tells which power switches to
+ *  turn off. Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective switch must be turned off,
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no switch will be changed.
+ *  WARNING: swtoff must not point to the first shared memory address.
+ * @memoff: pointer to an array of words that tells which memories to turn off.
+ *  Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective memory must be turned off, both array and
+ *  periphery logic;
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no memory will be changed,
+ *  but notice it may be turned off if the switch that feeds it is powered off.
+ *  WARNING: memoff must not point to the first shared memory address.
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn off the PMC and memory array/peripheral
+ * switches that control their power, as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate memory power state related to overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_power_off(const uint32_t swtoff[],
+		       const uint32_t memoff[],
+		       upwr_callb     callb)
+{
+	upwr_pwm_pwroff_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+	size_t stsize = 0;
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PWR_OFF);
+
+	ptrval = (unsigned long)os_ptr2phy((void *)swtoff);
+	if (swtoff == NULL) {
+		txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  (stsize = UPWR_PMC_SWT_WORDS * 4U),
+						  0U,
+						  swtoff);
+	}
+
+	ptrval = (unsigned long)os_ptr2phy((void *)memoff);
+	if (memoff == NULL) {
+		txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  UPWR_PMC_MEM_WORDS * 4U,
+						  stsize,
+						  memoff);
+	}
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_mem_retain()- Configures one or more memory power switches to
+ * retain its contents, having the power array on, while its peripheral logic
+ * is turned off.
+ * @mem: pointer to an array of words that tells which memories to put in a
+ *  retention state. Each word in the array has 1 bit for each memory.
+ *  A bit=1 means the respective memory must be put in retention state,
+ *  bit = 0 means it will stay unchanged (retention, fully on or off).
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn off the memory peripheral and leave
+ * its array on, as specified above.
+ * The request is executed if arguments are within range.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_mem_retain(const uint32_t mem[], upwr_callb callb)
+{
+	upwr_pwm_retain_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_RETAIN);
+
+	ptrval = (unsigned long)os_ptr2phy((void *)mem);
+	if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	}
+
+	txmsg.ptr = upwr_ptr2offset(ptrval,
+				    UPWR_SG_PWRMGMT,
+				    UPWR_PMC_MEM_WORDS * 4U,
+				    0U,
+				    mem);
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_chng_switch_mem() - Turns on/off power on one or more PMC switches
+ * and memories, including their array and peripheral logic.
+ * @swt: pointer to a list of PMC switches to be opened/closed.
+ *  The list is structured as an array of struct upwr_switch_board_t
+ *  (see upower_defs.h), each one containing a word for up to 32 switches,
+ *  one per bit. A bit = 1 means switch closed, bit = 0 means switch open.
+ *  struct upwr_switch_board_t also specifies a mask with 1 bit for each
+ *  respective switch: mask bit = 1 means the open/close action is applied,
+ *  mask bit = 0 means the switch stays unchanged.
+ *  The pointer may be set to NULL, in which case no switch will be changed,
+ *  unless a memory that it feeds must be turned on.
+ *  WARNING: swt must not point to the first shared memory address.
+ * @mem: pointer to a list of switches to be turned on/off.
+ *  The list is structured as an array of struct upwr_mem_switches_t
+ *  (see upower_defs.h), each one containing 2 word for up to 32 switches,
+ *  one per bit, one word for the RAM array power switch, other for the
+ *  RAM peripheral logic power switch. A bit = 1 means switch closed,
+ *  bit = 0 means switch open.
+ *  struct upwr_mem_switches_t also specifies a mask with 1 bit for each
+ *  respective switch: mask bit = 1 means the open/close action is applied,
+ *  mask bit = 0 means the switch stays unchanged.
+ *  The pointer may be set to NULL, in which case no memory switch will be
+ *  changed, but notice it may be turned off if the switch that feeds it is
+ *  powered off.
+ *  WARNING: mem must not point to the first shared memory address.
+ * @callb: pointer to the callback called when the configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the PMC switches and/or memory power
+ * as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate switch combinations and overall system state.
+ *
+ * If a memory is requested to turn on, but the power switch that feeds that
+ * memory is not, the power switch will be turned on anyway, if the swt
+ * array is not provided (that is, if swt is NULL).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy.
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+
+int upwr_pwm_chng_switch_mem(const struct upwr_switch_board_t  swt[],
+			     const struct upwr_mem_switches_t  mem[],
+			     upwr_callb callb)
+{
+	upwr_pwm_switch_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+	size_t stsize = 0U;
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_SWITCH);
+
+	ptrval = (unsigned long)os_ptr2phy((void *)swt);
+	if (swt == NULL) {
+		txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  (stsize = UPWR_PMC_SWT_WORDS * sizeof(struct upwr_switch_board_t)),
+						  0U,
+						  swt);
+	}
+
+	ptrval = (unsigned long)os_ptr2phy((void *)mem);
+	if (mem == NULL) {
+		txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */
+	} else if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	} else {
+		txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval,
+						  UPWR_SG_PWRMGMT,
+						  UPWR_PMC_MEM_WORDS * sizeof(struct upwr_mem_switches_t),
+						  stsize,
+						  mem);
+	}
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_pmode_config() - Configures a given power mode in a given domain.
+ * @domain: identifier of the domain to which the power mode belongs.
+ * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @pmode: SoC-dependent power mode identifier defined by type abs_pwr_mode_t
+ * found in upower_soc_defs.h.
+ * @config: pointer to an SoC-dependent struct defining the power mode
+ * configuration, found in upower_soc_defs.h.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the power mode configuration as
+ * specified above. The request is executed if arguments are within range,
+ * and complies with SoC-dependent restrictions on value combinations.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_pmode_config(soc_domain_t domain,
+			  abs_pwr_mode_t pmode,
+			  const void *config,
+			  upwr_callb callb)
+{
+	upwr_pwm_pmode_cfg_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_CONFIG);
+	txmsg.hdr.domain = (uint32_t)domain;
+	txmsg.hdr.arg = pmode;
+
+	ptrval = (unsigned long)os_ptr2phy(config);
+	if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	}
+
+	/*
+	 * upwr_pwm_pmode_config is an exception: use the pointer
+	 * (physical addr) as is
+	 */
+
+	txmsg.ptr = (uint32_t)ptrval;
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_reg_config() - Configures the uPower internal regulators.
+ * @config: pointer to the struct defining the regulator configuration;
+ * the struct upwr_reg_config_t is defined in the file upower_defs.h.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change/define the configurations of the
+ * internal regulators.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * The service may fail with error UPWR_RESP_RESOURCE if a power mode transition
+ * or the same service (called from another domain) is executing simultaneously.
+ * This error should be interpreted as a "try later" response, as the service
+ * will succeed once those concurrent executions are done, and no other is
+ * started.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+
+int upwr_pwm_reg_config(const struct upwr_reg_config_t *config,
+			upwr_callb   callb)
+{
+	upwr_pwm_regcfg_msg txmsg = {0};
+	unsigned long ptrval = 0UL; /* needed for X86, ARM64 */
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_REGCFG);
+
+	ptrval = (unsigned long)os_ptr2phy(config);
+	if (ptrval == 0U) {
+		return -2; /* pointer conversion failed */
+	}
+
+	txmsg.ptr = upwr_ptr2offset(ptrval,
+				    UPWR_SG_PWRMGMT,
+				    sizeof(struct upwr_reg_config_t),
+				    0U,
+				    config);
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_chng_dom_bias() - Changes the domain bias.
+ * @bias: pointer to a domain bias configuration struct (see upower_soc_defs.h).
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the domain bias configuration as
+ * specified above. The request is executed if arguments are within range,
+ * with no protections regarding the adequate value combinations and
+ * overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_chng_dom_bias(const struct upwr_dom_bias_cfg_t *bias,
+			   upwr_callb callb)
+{
+	upwr_pwm_dom_bias_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_DOM_BIAS);
+
+	/* SoC-dependent argument filling, defined in upower_soc_defs.h */
+	UPWR_FILL_DOMBIAS_ARGS(txmsg.hdr.domain, bias, txmsg.args);
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**
+ * upwr_pwm_chng_mem_bias()- Changes a ROM/RAM power bias.
+ * @domain: identifier of the domain upon which the bias is applied.
+ * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @bias: pointer to a memory bias configuration struct (see upower_soc_defs.h).
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the memory bias configuration as
+ * specified above. The request is executed if arguments are within range,
+ * with no protections regarding the adequate value combinations and
+ * overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_chng_mem_bias(soc_domain_t domain,
+			   const struct upwr_mem_bias_cfg_t *bias,
+			   upwr_callb callb)
+{
+	upwr_pwm_mem_bias_msg txmsg = {0};
+
+	if (api_state != UPWR_API_READY) {
+		return -3;
+	}
+
+	if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_MEM_BIAS);
+
+	txmsg.hdr.domain = (uint32_t)domain;
+
+	/* SoC-dependent argument filling, defined in upower_soc_defs.h */
+	UPWR_FILL_MEMBIAS_ARGS(bias, txmsg.args);
+
+	upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * DIAGNOSE SERVICE GROUP
+ */
+
+/**
+ * upwr_dgn_mode() - Sets the diagnostic mode.
+ * @mode:  diagnostic mode, which can be:
+ *  - UPWR_DGN_NONE:   no diagnostic recorded
+ *  - UPWR_DGN_TRACE:  warnings, errors, service, internal activity recorded
+ *  - UPWR_DGN_SRVREQ: warnings, errors, service activity recorded
+ *  - UPWR_DGN_WARN:   warnings and errors recorded
+ *  - UPWR_DGN_ALL:    trace, service, warnings, errors, task state recorded
+ *  - UPWR_DGN_ERROR:  only errors recorded
+ *  - UPWR_DGN_ALL2ERR: record all until an error occurs,
+ *    freeze recording on error
+ *  - UPWR_DGN_ALL2HLT: record all until an error occurs,
+ *    executes an ebreak on error, which halts the core if enabled through
+ *    the debug interface
+ * @callb: pointer to the callback called when mode is changed.
+ * NULL if no callback is required.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_dgn_mode(upwr_dgn_mode_t mode, const upwr_callb callb)
+{
+	upwr_dgn_mode_msg txmsg = {0};
+
+	if (UPWR_SG_BUSY(UPWR_SG_DIAG)) {
+		return -1;
+	}
+
+	UPWR_USR_CALLB(UPWR_SG_DIAG, callb);
+
+	UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DIAG, UPWR_DGN_MODE);
+
+	txmsg.hdr.arg = mode;
+
+	upwr_srv_req(UPWR_SG_DIAG, (uint32_t *)&txmsg, sizeof(txmsg) / 4U);
+
+	return 0;
+}
+
+/**---------------------------------------------------------------
+ * AUXILIARY CALLS
+ */
+
+/**
+ * upwr_rom_version() - informs the ROM firwmware version.
+ * @vmajor: pointer to the variable to get the firmware major version number.
+ * @vminor: pointer to the variable to get the firmware minor version number.
+ * @vfixes: pointer to the variable to get the firmware fixes number.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: SoC id.
+ */
+uint32_t upwr_rom_version(uint32_t *vmajor, uint32_t *vminor, uint32_t *vfixes)
+{
+	uint32_t soc;
+
+	upwr_lock(1);
+	soc = fw_rom_version.soc_id;
+	*vmajor = fw_rom_version.vmajor;
+	*vminor = fw_rom_version.vminor;
+	*vfixes = fw_rom_version.vfixes;
+	upwr_lock(0);
+	return soc;
+}
+
+/**
+ * upwr_ram_version() - informs the RAM firwmware version.
+ * @vminor: pointer to the variable to get the firmware minor version number.
+ * @vfixes: pointer to the variable to get the firmware fixes number.
+ *
+ * The 3 values returned are 0 if no RAM firmwmare was loaded and initialized.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: firmware major version number.
+ */
+uint32_t upwr_ram_version(uint32_t *vminor, uint32_t *vfixes)
+{
+	uint32_t vmajor;
+
+	upwr_lock(1);
+	vmajor = fw_ram_version.vmajor;
+	*vminor = fw_ram_version.vminor;
+	*vfixes = fw_ram_version.vfixes;
+	upwr_lock(0);
+
+	return vmajor;
+}
+
+/**
+ * upwr_req_status() - tells the status of the service group request, and
+ *                     returns a request return value, if any.
+ * @sg: service group of the request
+ * @sgfptr: pointer to the variable that will hold the function id of
+ * the last request completed; can be NULL, in which case it is not used.
+ * @errptr: pointer to the variable that will hold the error code;
+ * can be NULL, in which case it is not used.
+ * @retptr: pointer to the variable that will hold the value returned
+ * by the last request completed (invalid if the last request completed didn't
+ * return any value); can be NULL, in which case it is not used.
+ * Note that a request may return a value even if service error is returned
+ * (*errptr != UPWR_RESP_OK): that is dependent on the specific service.
+ *
+ * This call can be used in a poll loop of a service request completion in case
+ * a callback was not registered.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: service request status: succeeded, failed, or ongoing (busy)
+ */
+upwr_req_status_t upwr_req_status(upwr_sg_t sg,
+				  uint32_t *sgfptr,
+				  upwr_resp_t *errptr,
+				  int *retptr)
+{
+	upwr_req_status_t status;
+
+	upwr_lock(1);
+	if (sgfptr != NULL) {
+		*sgfptr = (uint32_t)sg_rsp_msg[sg].hdr.function;
+	}
+
+	if (errptr != NULL) {
+		*errptr = (upwr_resp_t)sg_rsp_msg[sg].hdr.errcode;
+	}
+
+	if (retptr != NULL) {
+		*retptr = (int)((sg_rsp_siz[sg] == 2U) ?
+			  sg_rsp_msg[sg].word2 : sg_rsp_msg[sg].hdr.ret);
+	}
+
+	status = ((sg_busy & (1UL << sg)) == 1U) ? UPWR_REQ_BUSY :
+		 (sg_rsp_msg[sg].hdr.errcode == UPWR_RESP_OK) ? UPWR_REQ_OK :
+								UPWR_REQ_ERR;
+	upwr_lock(0);
+	return status;
+}
+
+/**
+ * upwr_poll_req_status() - polls the status of the service group request, and
+ *                          returns a request return value, if any.
+ * @sg: service group of the request
+ * @sgfptr: pointer to the variable that will hold the function id of
+ * the last request completed; can be NULL, in which case it is not used.
+ * @errptr: pointer to the variable that will hold the error code;
+ * can be NULL, in which case it is not used.
+ * @retptr: pointer to the variable that will hold the value returned
+ * by the last request completed (invalid if the last request completed didn't
+ * return any value); can be NULL, in which case it is not used.
+ * Note that a request may return a value even if service error is returned
+ * (*errptr != UPWR_RESP_OK): that is dependent on the specific service.
+ * @attempts: maximum number of polling attempts; if attempts > 0 and is
+ * reached with no service response received, upwr_poll_req_status returns
+ * UPWR_REQ_BUSY and variables pointed by sgfptr, retptr and errptr are not
+ * updated; if attempts = 0, upwr_poll_req_status waits "forever".
+ *
+ * This call can be used to poll a service request completion in case a
+ * callback was not registered.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: service request status: succeeded, failed, or ongoing (busy)
+ */
+upwr_req_status_t upwr_poll_req_status(upwr_sg_t sg,
+				       uint32_t *sgfptr,
+				       upwr_resp_t *errptr,
+				       int *retptr,
+				       uint32_t attempts)
+{
+	uint32_t i;
+	upwr_req_status_t ret;
+
+	if (attempts == 0U) {
+		while ((ret = upwr_req_status(sg, sgfptr, errptr, retptr)) == UPWR_REQ_BUSY) {
+		};
+
+		return ret;
+	}
+
+	for (i = 0U; i < attempts; i++) {
+		ret = upwr_req_status(sg, sgfptr, errptr, retptr);
+		if (ret != UPWR_REQ_BUSY) {
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * upwr_alarm_code() - returns the alarm code of the last alarm occurrence.
+ *
+ * The value returned is not meaningful if no alarm was issued by uPower.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: alarm code, as defined by the type upwr_alarm_t in upwr_soc_defines.h
+ */
+upwr_alarm_t upwr_alarm_code(void)
+{
+	return (upwr_alarm_t)(3U & (mu->FSR.R >> 1U)); /* FSR[2:1] */
+}
+
+/**---------------------------------------------------------------
+ * TRANSMIT/RECEIVE PRIMITIVES
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * upwr_copy2tr() - copies a message to the MU TR registers;
+ * fill the TR registers before writing TIEN to avoid early interrupts;
+ * also, fill them from the higher index to the lowest, so the receive
+ * interrupt flag RF[0] will be the last to set, regardless of message size;
+ */
+void upwr_copy2tr(struct MU_t *local_mu, const uint32_t *msg, unsigned int size)
+{
+	for (int i = (int)size - 1; i > -1; i--) {
+		local_mu->TR[i].R = msg[i];
+	}
+}
+
+/**
+ * upwr_tx() - queues a message for transmission.
+ * @msg : pointer to the message sent.
+ * @size: message size in 32-bit words
+ * @callback: pointer to a function to be called when transmission done;
+ *            can be NULL, in which case no callback is done.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: number of vacant positions left in the transmission queue, or
+ *         -1 if the queue was already full when upwr_tx was called, or
+ *         -2 if any argument is invalid (like size off-range)
+ */
+int upwr_tx(const uint32_t *msg,
+	    unsigned int size,
+	    UPWR_TX_CALLB_FUNC_T callback)
+{
+	if (size > UPWR_MU_MSG_SIZE) {
+		return -2;
+	}
+
+	if (size == 0U) {
+		return -2;
+	}
+
+	if (mu->TSR.R != UPWR_MU_TSR_EMPTY) {
+		return -1;  /* not all TE bits in 1: some data to send still */
+	}
+
+	mu_tx_callb = callback;
+
+	upwr_copy2tr(mu, msg, size);
+	mu->TCR.R = 1UL << (size - 1UL);
+
+	mu_tx_pend = 1UL;
+
+	return 0;
+}
+
+/**
+ * upwr_rx() - unqueues a received message from the reception queue.
+ * @msg: pointer to the message destination buffer.
+ * @size: pointer to variable to hold message size in 32-bit words.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: number of messages remaining in the reception queue, or
+ *         -1 if the queue was already empty when upwr_rx was called, or
+ *         -2 if any argument is invalid (like mu off-range)
+ */
+int upwr_rx(char *msg, unsigned int *size)
+{
+	unsigned int len = mu->RSR.R;
+
+	len = (len == 0x0U) ? 0U :
+	      (len == 0x1U) ? 1U :
+	      #if UPWR_MU_MSG_SIZE > 1
+	      (len == 0x3U) ? 2U :
+	      #if UPWR_MU_MSG_SIZE > 2
+	      (len == 0x7U) ? 3U :
+	      #if UPWR_MU_MSG_SIZE > 3
+	      (len == 0xFU) ? 4U :
+	      #endif
+	      #endif
+	      #endif
+	      0xFFFFFFFFU; /* something wrong */
+
+	if (len  == 0xFFFFFFFFU) {
+		return -3;
+	}
+
+	if (len == 0U) {
+		return -1;
+	}
+
+	*size = len;
+
+	/*
+	 * copy the received message to the rx queue,
+	 * so the interrupts are cleared.
+	 */
+	msg_copy(msg, (char *)&mu->RR[0], len);
+
+	mu->RCR.R = 1U; /* enable only RR[0] receive interrupt */
+
+	return 0;
+}
+
+/**
+ * upwr_rx_callback() - sets up a callback for a message receiving event.
+ * @callback: pointer to a function to be called when a message arrives;
+ *            can be NULL, in which case no callback is done.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok; -2 if any argument is invalid (mu off-range).
+ */
+int upwr_rx_callback(UPWR_RX_CALLB_FUNC_T callback)
+{
+	mu_rx_callb = callback;
+
+	return 0;
+}
+
+/**
+ * msg_copy() - copies a message.
+ * @dest: pointer to the destination message.
+ * @src : pointer to the source message.
+ * @size: message size in words.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void)
+ */
+void msg_copy(char *dest, char *src, unsigned int size)
+{
+	for (uint32_t i = 0U; i < size * sizeof(uint32_t); i++) {
+		dest[i] = src[i];
+	}
+}
diff --git a/plat/imx/imx8ulp/upower/upower_api.h b/plat/imx/imx8ulp/upower/upower_api.h
new file mode 100644
index 0000000..0069f5f
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upower_api.h
@@ -0,0 +1,1629 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/**
+ * Copyright 2019-2024 NXP
+ *
+ * KEYWORDS: micro-power uPower driver API
+ * -----------------------------------------------------------------------------
+ * PURPOSE: uPower driver API
+ * -----------------------------------------------------------------------------
+ * PARAMETERS:
+ * PARAM NAME RANGE:DESCRIPTION:       DEFAULTS:                           UNITS
+ * -----------------------------------------------------------------------------
+ * REUSE ISSUES: no reuse issues
+ */
+#ifndef UPWR_API_H
+#define UPWR_API_H
+
+#include "upmu.h"
+#include "upower_soc_defs.h"
+/******************************************************************************
+ * uPower API Overview and Concepts
+ *
+ * This API is intended to be used by the OS drivers (Linux, FreeRTOS etc)
+ * as well as bare metal drivers to command and use services from the uPower.
+ * It aims to be OS-independent.
+ *
+ * The API functions fall in 3 categories:
+ *  - initialization/start-up
+ *  - service requests
+ *  - auxiliary
+ *
+ * The communication with the uPower is mostly made through the Message Unit
+ * (MU) IP. uPower provides one MU for each CPU cluster in a different
+ * power domain. An API instance runs on each CPU cluster.
+ *
+ * The API assumes each SoC power domain/CPU cluster receives 2 interrupts
+ * from the uPower MU:
+ *  1. Tx/Rx, which is issued on both transmission and reception
+ *  2. Exception interrupt, to handle critical alams, catastrophic errors, etc.
+ *     This interrupt should have a high priority, preferably an NMI.
+ *
+ * The normal uPower operation is done by service requests. There is an API
+ * function for each service request, and all service requests send back a
+ * response, at least to indicate success/failure.
+ * The service request functions are non-blocking, and their completion can be
+ * tracked in two ways:
+ *  1. by a callback, registered when the service request call is made by
+ *     passing the callback function pointer; a NULL pointer may be passed,
+ *     in which case no callback is made.
+ *  2. by polling, using the auxiliary functions upwr_req_status or
+ *     upwr_poll_req_status;
+ *     polling must be used if no callback is registered, but callbacks and
+ *     polling are completely independent.
+ *
+ * Note: a service request must not be started from a callback.
+ *
+ * uPower service requests are classified in Service Groups.
+ * Each Service Group has a set of related functions, named upwr_XXX_,
+ * where XXX is a 3-letter service group mnemonic. The service groups are:
+ *  - Exception Service Group - upwr_xcp_*
+ *     ~ gathers functions that deal with errors and other processes outside
+ *       the functional scope.
+ *  - Power Management Service Group - upwr_pwm_*
+ *     ~ functions to control switches, configure power modes, set internal voltage etc
+ *  - Delay Measurement Service Group - upwr_dlm_*
+ *     ~ delay measurements function using the process monitor and delay meter
+ *  - Voltage Measurement Service Group - upwr_vtm_*
+ *     ~ functions for voltage measurements, comparisons, alarms, power meter, set PMIC rail voltage
+ *  - Temperature Measurement Service Group - upwr_tpm_*
+ *     ~ functions for temperature measurements, comparisons, alarms
+ *  - Current Measurement Service Group  - upwr_crm_*
+ *     ~ functions for current and charge measurement
+ *  - Diagnostic Service Group - upwr_dgn_*
+ *     ~ functions for log configuration and statistics collecting
+ *
+ * Service requests follow this "golden rule":
+ * *** No two requests run simultaneously for the same service group,
+ *     on the same domain ***
+ * They can run simultaneously on different domains (RTD/APD), and can also run
+ * simultaneously if belong to different service groups (even on same domain).
+ * Therefore, requests to the same service group on the same domain must be
+ * serialized. A service request call returns error if there is another request
+ * on the same service group pending, waiting a response (on the same domain).
+ *
+ * A request for continuous service does not block the service group.
+ * For instance, a request to "measure the temperature each 10 miliseconds"
+ * responds quickly, unlocks the service group, and the temperature
+ * continues to be measured as requested, every 10 miliseconds from then on.
+ *
+ * Service Groups have a fixed priority in the API, from higher to lower:
+ *  1. Exception
+ *  2. Power Management
+ *  3. Delay Measurement
+ *  4. Voltage Measurement
+ *  5. Current Measurement
+ *  6. Temperature Measurement
+ *  7. Diagnostics
+ *
+ * The priority above only affects the order in which requests are sent to the
+ * uPower firmware: request to the higher priority Service Group is sent first,
+ * even if the call was made later, if there is an MU transmission pending,
+ * blocking it. The service priorities in the firmware depend on other factors.
+ *
+ * Services are requested using API functions. A service function returns with
+ * no error if a request was successfully made, but it doesn't mean the service
+ * was completed. The service is executed asynchronously, and returns a result
+ * (at least success/fail) via a callback or polling for service status.
+ * The possible service response codes are:
+ * - UPWR_RESP_OK = 0,     : no error
+ * - UPWR_RESP_SG_BUSY     : service group is busy
+ * - UPWR_RESP_SHUTDOWN    : services not up or shutting down
+ * - UPWR_RESP_BAD_REQ     : invalid request (usually invalid argumnents)
+ * - UPWR_RESP_BAD_STATE   : system state doesn't allow perform the request
+ * - UPWR_RESP_UNINSTALLD  : service or function not installed
+ * - UPWR_RESP_UNINSTALLED : service or function not installed (alias)
+ * - UPWR_RESP_RESOURCE    : resource not available
+ * - UPWR_RESP_TIMEOUT     : service timeout
+ */
+
+/**
+ * upwr_callb()-generic function pointer for a request return callback;
+ * @sg: request service group
+ * @func: service request function id.
+ * @errcode: error code.
+ * @ret: return value, if any. Note that a request may return a value even if
+ * service error is returned (errcode != UPWR_RESP_OK); that is dependent on
+ * the specific service.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void)
+ */
+typedef void (*upwr_callb)(upwr_sg_t sg, uint32_t func,
+			   upwr_resp_t errcode, ...);
+
+/**---------------------------------------------------------------
+ * INITIALIZATION, CONFIGURATION
+ *
+ * A reference uPower initialization sequence goes as follows:
+ *
+ * 1. host CPU calls upwr_init.
+ * 2. (optional) host checks the ROM version and SoC code calling upwr_vers(...)
+ *    and optionally performs any configuration or workaround accordingly.
+ * 3. host CPU calls upwr_start to start the uPower services, passing a
+ *    service option number.
+ *    If no RAM code is loaded or it has no service options, the launch option
+ *    number passed must be 0, which will start the services available in ROM.
+ *    upwr_start also receives a pointer to a callback called by the API
+ *    when the firmware is ready to receive service requests.
+ *    The callback may be replaced by polling, calling upwr_req_status in a loop
+ *    or upwr_poll_req_status; in this case the callback pointer may be NULL.
+ *    A host may call upwr_start even if the services were already started by
+ *    any host: if the launch option is the same, the response will be ok,
+ *    but will indicate error if the services were already started with a
+ *    different launch option.
+ * 4. host waits for the callback calling, or polling finishing;
+ *    if no error is returned, it can start making service calls using the API.
+ *
+ * Variations on that reference sequence are possible:
+ *  - the uPower services can be started using the ROM code only, which includes
+ *    the basic Power Management services, among others, with launch option
+ *    number = 0.
+ *    The code RAM can be loaded while these services are running and,
+ *    when the loading is done, the services can be re-started with these 2
+ *    requests executed in order: upwr_xcp_shutdown and upwr_start,
+ *    using the newly loaded RAM code (launch option > 0).
+ *
+ * NOTE: the initialization call upwr_init is not effective and
+ *       returns error when called after the uPower services are started.
+ */
+
+/**
+ * upwr_init() - API initialization; must be the first API call after reset.
+ * @domain: SoC-dependent CPU domain id; identifier used by the firmware in
+ * many services. Defined by SoC-dependent type soc_domain_t found in
+ * upower_soc_defs.h.
+ * @muptr: pointer to the MU instance.
+ * @mallocptr: pointer to the memory allocation function
+ * @physaddrptr: pointer to the function to convert pointers to
+ * physical addresses. If NULL, no conversion is made (pointer=physical address)
+ * @isrinstptr: pointer to the function to install the uPower ISR callbacks;
+ * the function receives the pointers to the MU tx/rx and Exception ISRs
+ * callbacks, which must be called from the actual system ISRs.
+ * The function pointed by isrinstptr must also enable the interrupt at the
+ * core/interrupt controller, but must not enable the interrupt at the MU IP.
+ * The system ISRs are responsible for dealing with the interrupt controller,
+ * performing any other context save/restore, and any other housekeeping.
+ * @lockptr: pointer to a function that prevents MU interrupts (if argrument=1)
+ * or allows it (if argument=0). The API calls this function to make small
+ * specific code portions thread safe. Only MU interrupts must be avoided,
+ * the code may be suspended for other reasons.
+ * If no MU interrupts can happen during the execution of an API call or
+ * callback, even if enabled, for some other reason (e.g. interrupt priority),
+ * then this argument may be NULL.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if failed to allocate memory, or use some other resource.
+ *        -2 if any argument is invalid.
+ *        -3 if failed to send the ping message.
+ *        -4 if failed to receive the initialization message, or was invalid
+ */
+
+/* malloc function ptr */
+typedef void* (*upwr_malloc_ptr_t)(unsigned int size);
+
+/* pointer->physical address conversion function ptr */
+typedef void* (*upwr_phyadr_ptr_t)(const void *addr);
+
+typedef uint32_t upwr_api_state_t;
+
+extern volatile upwr_api_state_t api_state;
+
+/*
+ * upwr_lock_ptr_t: pointer to a function that prevents MU interrupts
+ * (if argrument lock=1) or allows it (if argument lock=0).
+ * The API calls this function to make small specific code portions thread safe.
+ * Only MU interrupts must be avoided, the code may be suspended for other
+ * reasons.
+ */
+typedef void  (*upwr_lock_ptr_t)(int lock);
+
+typedef void (*upwr_isr_callb)(void);
+
+typedef void (*upwr_inst_isr_ptr_t)(upwr_isr_callb txrx_isr,
+				    upwr_isr_callb excp_isr);
+void upwr_start_callb(void);
+
+int upwr_init(soc_domain_t domain, struct MU_t *muptr,
+	      const upwr_malloc_ptr_t mallocptr,
+	      const upwr_phyadr_ptr_t phyadrptr,
+	      const upwr_inst_isr_ptr_t isrinstptr,
+	      const upwr_lock_ptr_t lockptr);
+
+/**
+ * upwr_start() - Starts the uPower services.
+ * @launchopt: a number to select between multiple launch options,
+ * that may define, among other things, which services will be started,
+ * or which services implementations, features etc.
+ * launchopt = 0 selects a subset of services implemented in ROM;
+ * any other number selects service sets implemented in RAM, launched
+ * by the firmware function ram_launch; if an invalid launchopt value is passed,
+ * no services are started, and the callback returns error (see below).
+ * @rdycallb: pointer to the callback to be called when the uPower is ready
+ * to receive service requests. NULL if no callback needed.
+ * The callback receives as arguments the RAM firmware version numbers.
+ * If all 3 numbers (vmajor, vminor, vfixes) are 0, that means the
+ * service launching failed.
+ * Firmware version numbers will be the same as ROM if launchopt = 0,
+ * selecting the ROM services.
+ *
+ * upwr_start can be called by any domain even if the services are already
+ * started: it has no effect, returning success, if the launch option is the
+ * same as the one that actually started the service, and returns error if
+ * called with a different option.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if a resource failed,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+
+extern void upwr_txrx_isr(void);
+
+typedef void (*upwr_rdy_callb)(uint32_t vmajor, uint32_t vminor, uint32_t vfixes);
+
+int upwr_start(uint32_t launchopt, const upwr_rdy_callb rdycallb);
+
+
+/**---------------------------------------------------------------
+ * EXCEPTION SERVICE GROUP
+ */
+
+/**
+ * upwr_xcp_config() - Applies general uPower configurations.
+ * @config: pointer to the uPower SoC-dependent configuration struct
+ * upwr_xcp_config_t defined in upower_soc_defs.h. NULL may be passed, meaning
+ * a request to read the configuration, in which case it appears in the callback
+ * argument ret, or can be pointed by argument retptr in the upwr_req_status and
+ * upwr_poll_req_status calls, casted to upwr_xcp_config_t.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the configuration, or NULL if no callback needed (polling used instead).
+ *
+ * Some configurations are targeted for a specific domain (see the struct
+ * upwr_xcp_config_t definition in upower_soc_defs.h); this call has implicit
+ * domain target (the same domain from which is called).
+ *
+ * The return value is always the current configuration value, either in a
+ * read-only request (config = NULL) or after setting a new configuration
+ * (non-NULL config).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_config(const upwr_xcp_config_t *config, const upwr_callb callb);
+
+/**
+ * upwr_xcp_sw_alarm() - Makes uPower issue an alarm interrupt to given domain.
+ * @domain: identifier of the domain to alarm. Defined by SoC-dependent type
+ * soc_domain_t found in upower_soc_defs.h.
+ * @code: alarm code. Defined by SoC-dependent type upwr_alarm_t found in
+ * upower_soc_defs.h.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the alarm, or NULL if no callback needed (polling used instead).
+ *
+ * The function requests the uPower to issue an alarm of the given code as if
+ * it had originated internally. This service is useful mainly to test the
+ * system response to such alarms, or to make the system handle a similar alarm
+ * situation detected externally to uPower.
+ *
+ * The system ISR/code handling the alarm may retrieve the alarm code by calling
+ * the auxiliary function upwr_alarm_code.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_sw_alarm(soc_domain_t domain, upwr_alarm_t code,
+		      const upwr_callb callb);
+
+/**
+ * upwr_xcp_set_ddr_retention() - M33/A35 can use this API to set/clear ddr retention
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set ddr retention, false clear ddr retention.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_set_ddr_retention(soc_domain_t domain, uint32_t enable,
+			       const upwr_callb callb);
+
+/**
+ * upwr_xcp_set_mipi_dsi_ena() - M33/A35 can use this API to set/clear mipi dsi ena
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set ddr retention, false clear ddr retention.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_set_mipi_dsi_ena(soc_domain_t domain, uint32_t enable,
+			      const upwr_callb callb);
+
+/**
+ * upwr_xcp_get_mipi_dsi_ena() - M33/A35 can use this API to get mipi dsi ena status
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+
+int upwr_xcp_get_mipi_dsi_ena(soc_domain_t domain, const upwr_callb callb);
+
+/**
+ * upwr_xcp_set_osc_mode() - M33/A35 can use this API to set uPower OSC mode
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @osc_mode, 0 means low frequency, not 0 means high frequency.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_osc_mode(soc_domain_t domain, uint32_t osc_mode,
+			  const upwr_callb callb);
+
+/**
+ * upwr_xcp_set_rtd_use_ddr() - M33 call this API to inform uPower, M33 is using ddr
+ * @domain: identifier of the caller domain.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @is_use_ddr: not 0, true, means that RTD is using ddr. 0, false, means that, RTD
+ * is not using ddr.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_rtd_use_ddr(soc_domain_t domain, uint32_t is_use_ddr,
+			     const upwr_callb callb);
+
+/**
+ * upwr_xcp_set_rtd_apd_llwu() - M33/A35 can use this API to set/clear rtd_llwu apd_llwu
+ * @domain: set which domain (RTD_DOMAIN, APD_DOMAIN) LLWU.
+ * soc_domain_t found in upower_soc_defs.h.
+ * @enable: true, means that set rtd_llwu or apd_llwu, false clear rtd_llwu or apd_llwu.
+ * @callb: NULL
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_set_rtd_apd_llwu(soc_domain_t domain, uint32_t enable,
+			      const upwr_callb callb);
+/**
+ * upwr_xcp_shutdown() - Shuts down all uPower services and power mode tasks.
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the shutdown, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * At the callback the uPower/API is back to initialization/start-up phase,
+ * so service request calls return error.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_shutdown(const upwr_callb callb);
+
+/**
+ * upwr_xcp_i2c_access() - Performs an access through the uPower I2C interface.
+ * @addr: I2C slave address, up to 10 bits.
+ * @data_size: determines the access direction and data size in bytes, up to 4;
+ * negetive data_size determines a read  access with size -data_size;
+ * positive data_size determines a write access with size  data_size;
+ * data_size=0 is invalid, making the service return error UPWR_RESP_BAD_REQ.
+ * @subaddr_size: size of the sub-address in bytes, up to 4; if subaddr_size=0,
+ * no subaddress is used.
+ * @subaddr: sub-address, only used if subaddr_size > 0.
+ * @wdata: write data, up to 4 bytes; ignored if data_size < 0 (read)
+ * @callb: pointer to the callback to be called when the uPower has finished
+ * the access, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument.
+ *
+ * The service performs a read (data_size < 0) or a write (data_size > 0) of
+ * up to 4 bytes on the uPower I2C interface. The data read from I2C comes via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * Sub-addressing is supported, with sub-address size determined by the argument
+ * subaddr_size, up to 4 bytes. Sub-addressing is not used if subaddr_size=0.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_xcp_i2c_access(uint16_t addr, int8_t data_size, uint8_t subaddr_size,
+			uint32_t subaddr, uint32_t wdata,
+			const upwr_callb callb);
+
+
+/**---------------------------------------------------------------
+ * POWER MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_pwm_dom_power_on() - Commands uPower to power on the platform of other
+ * domain (not necessarily its core(s)); does not release the core reset.
+ * @domain: identifier of the domain to power on. Defined by SoC-dependent type
+ * soc_domain_t found in upower_soc_defs.h.
+ * @boot_start: must be 1 to start the domain core(s) boot(s), releasing
+ * its (their) resets, or 0 otherwise.
+ * @pwroncallb: pointer to the callback to be called when the uPower has
+ * finished the power on procedure, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_dom_power_on(soc_domain_t domain, int boot_start,
+			  const upwr_callb pwroncallb);
+
+/**
+ * upwr_pwm_boot_start() - Commands uPower to release the reset of other CPU(s),
+ * starting their boots.
+ * @domain: identifier of the domain to release the reset. Defined by
+ * SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @bootcallb: pointer to the callback to be called when the uPower has finished
+ * the boot start procedure, or NULL if no callback needed
+ * (polling used instead).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * The callback calling doesn't mean the CPUs boots have finished:
+ * it only indicates that uPower released the CPUs resets, and can receive
+ * other power management service group requests.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -2 if the domain passed is the same as the caller,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_boot_start(soc_domain_t domain, const upwr_callb  bootcallb);
+
+/**
+ * upwr_pwm_param() - Changes Power Management parameters.
+ * @param: pointer to a parameter structure upwr_pwm_param_t, SoC-dependent,
+ * defined in upwr_soc_defines.h. NULL may be passed, meaning
+ * a request to read the parameter set, in which case it appears in the callback
+ * argument ret, or can be pointed by argument retptr in the upwr_req_status and
+ * upwr_poll_req_status calls, casted to upwr_pwm_param_t.
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The return value is always the current parameter set value, either in a
+ * read-only request (param = NULL) or after setting a new parameter
+ * (non-NULL param).
+ *
+ * Some parameters may be targeted for a specific domain (see the struct
+ * upwr_pwm_param_t definition in upower_soc_defs.h); this call has implicit
+ * domain target (the same domain from which is called).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded or
+ * not.
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_pwm_param(upwr_pwm_param_t *param, const upwr_callb callb);
+
+/**
+ * upwr_pwm_chng_reg_voltage() - Changes the voltage at a given regulator.
+ * @reg: regulator id.
+ * @volt: voltage value; value unit is SoC-dependent, converted from mV by the
+ * macro UPWR_VOLT_MILIV, or from micro-Volts by the macro UPWR_VOLT_MICROV,
+ * both macros in upower_soc_defs.h
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to change the voltage of the given regulator.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_chng_reg_voltage(uint32_t reg, uint32_t volt, upwr_callb callb);
+
+/**
+ * upwr_pwm_freq_setup() - Determines the next frequency target for a given
+ *                         domain and current frequency.
+ * @domain: identifier of the domain to change frequency. Defined by
+ * SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @rail: the pmic regulator number for the target domain.
+ * @stage: DVA adjust stage
+ * refer to upower_defs.h "DVA adjust stage"
+ * @target_freq: the target adjust frequency, accurate to MHz
+ *
+ * refer to upower_defs.h structure definition upwr_pwm_freq_msg
+ *
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The DVA algorithm is broken down into two phases.
+ * The first phase uses a look up table to get a safe operating voltage
+ * for the requested frequency.
+ * This voltage is guaranteed to work over process and temperature.
+ *
+ * The second step of the second phase is to measure the temperature
+ * using the uPower Temperature Sensor module.
+ * This is accomplished by doing a binary search of the TSEL bit field
+ * in the Temperature Measurement Register (TMR).
+ * The search is repeated until the THIGH bit fields in the same register change value.
+ * There are 3 temperature sensors in 8ULP (APD, AVD, and RTD).
+ *
+ *
+ * The second phase is the fine adjust of the voltage.
+ * This stage is entered only when the new frequency requested
+ * by application was already set as well as the voltage for that frequency.
+ * The first step of the fine adjust is to find what is the current margins
+ * for the monitored critical paths, or, in other words,
+ * how many delay cells will be necessary to generate a setup-timing violation.
+ * The function informs uPower that the given domain frequency has changed or
+ * will change to the given value. uPower firmware will then adjust voltage and
+ * bias to cope with the new frequency (if decreasing) or prepare for it
+ * (if increasing). The function must be called after decreasing the frequency,
+ * and before increasing it. The actual increase in frequency must not occur
+ * before the service returns its response.
+ *
+ * So, for increase clock frequency case, user need to call this API twice,
+ * the first stage gross adjust and the second stage fine adjust.
+ *
+ * for reduce clock frequency case, user can only call this API once,
+ * full stage (combine gross stage and fine adjust)
+ *
+ * The request is executed if arguments are within range.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_freq_setup(soc_domain_t domain, uint32_t rail, uint32_t stage,
+			uint32_t target_freq, upwr_callb callb);
+
+/**
+ * upwr_pwm_power_on()- Powers on (not off) one or more switches and ROM/RAMs.
+ * @swton: pointer to an array of words that tells which power switches to
+ *  turn on. Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective switch must be turned on,
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no switch will be changed,
+ *  unless a memory that it feeds must be turned on.
+ *  WARNING: swton must not point to the first shared memory address.
+ * @memon: pointer to an array of words that tells which memories to turn on.
+ *  Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective memory must be turned on, both array and
+ *  periphery logic;
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no memory will be changed.
+ *  WARNING: memon must not point to the first shared memory address.
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn on the PMC and memory array/peripheral
+ * switches that control their power, as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate memory power state related to overall system state.
+ *
+ * If a memory is requested to turn on, but the power switch that feeds that
+ * memory is not, the power switch will be turned on anyway, if the pwron
+ * array is not provided (that is, if pwron is NULL).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_power_on(const uint32_t swton[], const uint32_t memon[],
+		      upwr_callb callb);
+
+/**
+ * upwr_pwm_power_off()- Powers off (not on) one or more switches and ROM/RAMs.
+ * @swtoff: pointer to an array of words that tells which power switches to
+ *  turn off. Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective switch must be turned off,
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no switch will be changed.
+ *  WARNING: swtoff must not point to the first shared memory address.
+ * @memoff: pointer to an array of words that tells which memories to turn off.
+ *  Each word in the array has 1 bit for each switch.
+ *  A bit=1 means the respective memory must be turned off, both array and
+ *  periphery logic;
+ *  bit = 0 means it will stay unchanged (on or off).
+ *  The pointer may be set to NULL, in which case no memory will be changed,
+ *  but notice it may be turned off if the switch that feeds it is powered off.
+ *  WARNING: memoff must not point to the first shared memory address.
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn off the PMC and memory array/peripheral
+ * switches that control their power, as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate memory power state related to overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_power_off(const uint32_t swtoff[], const uint32_t memoff[],
+		       upwr_callb callb);
+
+/**
+ * upwr_pwm_mem_retain()- Configures one or more memory power switches to
+ * retain its contents, having the power array on, while its peripheral logic
+ * is turned off.
+ * @mem: pointer to an array of words that tells which memories to put in a
+ *  retention state. Each word in the array has 1 bit for each memory.
+ *  A bit=1 means the respective memory must be put in retention state,
+ *  bit = 0 means it will stay unchanged (retention, fully on or off).
+ * @callb: pointer to the callback called when configurations are applyed.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to turn off the memory peripheral and leave
+ * its array on, as specified above.
+ * The request is executed if arguments are within range.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_mem_retain(const uint32_t mem[], upwr_callb callb);
+
+/**
+ * upwr_pwm_chng_switch_mem() - Turns on/off power on one or more PMC switches
+ * and memories, including their array and peripheral logic.
+ * @swt: pointer to a list of PMC switches to be opened/closed.
+ *  The list is structured as an array of struct upwr_switch_board_t
+ *  (see upower_defs.h), each one containing a word for up to 32 switches,
+ *  one per bit. A bit = 1 means switch closed, bit = 0 means switch open.
+ *  struct upwr_switch_board_t also specifies a mask with 1 bit for each
+ *  respective switch: mask bit = 1 means the open/close action is applied,
+ *  mask bit = 0 means the switch stays unchanged.
+ *  The pointer may be set to NULL, in which case no switch will be changed,
+ *  unless a memory that it feeds must be turned on.
+ *  WARNING: swt must not point to the first shared memory address.
+ * @mem: pointer to a list of switches to be turned on/off.
+ *  The list is structured as an array of struct upwr_mem_switches_t
+ *  (see upower_defs.h), each one containing 2 word for up to 32 switches,
+ *  one per bit, one word for the RAM array power switch, other for the
+ *  RAM peripheral logic power switch. A bit = 1 means switch closed,
+ *  bit = 0 means switch open.
+ *  struct upwr_mem_switches_t also specifies a mask with 1 bit for each
+ *  respective switch: mask bit = 1 means the open/close action is applied,
+ *  mask bit = 0 means the switch stays unchanged.
+ *  The pointer may be set to NULL, in which case no memory switch will be
+ *  changed, but notice it may be turned off if the switch that feeds it is
+ *  powered off.
+ *  WARNING: mem must not point to the first shared memory address.
+ * @callb: pointer to the callback called when the configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the PMC switches and/or memory power
+ * as specified above.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate switch combinations and overall system state.
+ *
+ * If a memory is requested to turn on, but the power switch that feeds that
+ * memory is not, the power switch will be turned on anyway, if the swt
+ * array is not provided (that is, if swt is NULL).
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Callback or polling may return error if the service contends for a resource
+ * already being used by a power mode transition or an ongoing service in
+ * another domain.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy.
+ *        -2 if a pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_chng_switch_mem(const struct upwr_switch_board_t swt[],
+			     const struct upwr_mem_switches_t mem[],
+			     upwr_callb callb);
+
+/**
+ * upwr_pwm_pmode_config() - Configures a given power mode in a given domain.
+ * @domain: identifier of the domain to which the power mode belongs.
+ * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @pmode: SoC-dependent power mode identifier defined by type abs_pwr_mode_t
+ * found in upower_soc_defs.h.
+ * @config: pointer to an SoC-dependent struct defining the power mode
+ * configuration, found in upower_soc_defs.h.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the power mode configuration as
+ * specified above. The request is executed if arguments are within range,
+ * and complies with SoC-dependent restrictions on value combinations.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_pmode_config(soc_domain_t domain, abs_pwr_mode_t pmode,
+			  const void *config, upwr_callb callb);
+
+
+
+/**
+ * upwr_pwm_reg_config() - Configures the uPower internal regulators.
+ * @config: pointer to the struct defining the regulator configuration;
+ * the struct upwr_reg_config_t is defined in the file upower_defs.h.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change/define the configurations of the
+ * internal regulators.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * The service may fail with error UPWR_RESP_RESOURCE if a power mode transition
+ * or the same service (called from another domain) is executing simultaneously.
+ * This error should be interpreted as a "try later" response, as the service
+ * will succeed once those concurrent executions are done, and no other is
+ * started.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_pwm_reg_config(const struct upwr_reg_config_t *config,
+			upwr_callb callb);
+
+/**
+ * upwr_pwm_chng_dom_bias() - Changes the domain bias.
+ * @bias: pointer to a domain bias configuration struct (see upower_soc_defs.h).
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the domain bias configuration as
+ * specified above. The request is executed if arguments are within range,
+ * with no protections regarding the adequate value combinations and
+ * overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+
+int upwr_pwm_chng_dom_bias(const struct upwr_dom_bias_cfg_t *bias,
+			   upwr_callb callb);
+
+/**
+ * upwr_pwm_chng_mem_bias()- Changes a ROM/RAM power bias.
+ * @domain: identifier of the domain upon which the bias is applied.
+ * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h.
+ * @bias: pointer to a memory bias configuration struct (see upower_soc_defs.h).
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change the memory bias configuration as
+ * specified above. The request is executed if arguments are within range,
+ * with no protections regarding the adequate value combinations and
+ * overall system state.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+
+int upwr_pwm_chng_mem_bias(soc_domain_t domain,
+			   const struct upwr_mem_bias_cfg_t *bias,
+			   upwr_callb callb);
+
+/**---------------------------------------------------------------
+ * VOLTAGE MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_vtm_pmic_cold_reset() -request cold reset the pmic.
+ * pmic will power cycle all the regulators
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to cold reset the pmic.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_pmic_cold_reset(upwr_callb callb);
+
+/**
+ * upwr_vtm_set_pmic_mode() -request uPower set pmic mode
+ * @pmic_mode: the target mode need to be set
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to set pmic mode
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_set_pmic_mode(uint32_t pmic_mode, upwr_callb callb);
+
+/**
+ * upwr_vtm_chng_pmic_voltage() - Changes the voltage of a given rail.
+ * @rail: pmic rail id.
+ * @volt: the target voltage of the given rail, accurate to uV
+ * If pass volt value 0, means that power off this rail.
+ * @callb: response callback pointer; NULL if no callback needed.
+ *
+ * The function requests uPower to change the voltage of the given rail.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_chng_pmic_voltage(uint32_t rail, uint32_t volt, upwr_callb callb);
+
+/**
+ * upwr_vtm_get_pmic_voltage() - Get the voltage of a given ral.
+ * @rail: pmic rail id.
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to get the voltage of the given rail.
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The voltage data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_get_pmic_voltage(uint32_t rail, upwr_callb callb);
+
+
+/**
+ * upwr_vtm_power_measure() - request uPower to measure power consumption
+ * @ssel: This field determines which power switches will have their currents
+ * sampled to be accounted for a
+ * current/power measurement. Support 0~7
+
+ * SSEL bit #	Power Switch
+ * 0	M33 core complex/platform/peripherals
+ * 1	Fusion Core and Peripherals
+ * 2	A35[0] core complex
+ * 3	A35[1] core complex
+ * 4	3DGPU
+ * 5	HiFi4
+ * 6	DDR Controller (PHY and PLL NOT included)
+ * 7	PXP, EPDC
+ *
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to measure power consumption
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The power consumption data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Accurate to uA
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_power_measure(uint32_t ssel, upwr_callb callb);
+
+/**
+ * upwr_vtm_vmeter_measure() - request uPower to measure voltage
+ * @vdetsel: Voltage Detector Selector, support 0~3
+ * 00b - RTD sense point
+ * 01b - LDO output
+ * 10b - APD domain sense point
+ * 11b - AVD domain sense point
+ * Refer to upower_defs.h
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to use vmeter to measure voltage
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument.
+ *
+ * The voltage data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Refer to RM COREREGVL (Core Regulator Voltage Level)
+ * uPower return VDETLVL to user, user can calculate the real voltage:
+ *
+ * 0b000000(0x00) - 0.595833V
+ * 0b100110(0x26) - 1.007498V
+ * <value> - 0.595833V + <value>x10.8333mV
+ * 0b110010(0x32) - 1.138V
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_vmeter_measure(uint32_t vdetsel, upwr_callb callb);
+
+/**
+ * upwr_vtm_pmic_config() - Configures the SoC PMIC (Power Management IC).
+ * @config: pointer to a PMIC-dependent struct defining the PMIC configuration.
+ * @size:   size of the struct pointed by config, in bytes.
+ * @callb: pointer to the callback called when configurations are applied.
+ * NULL if no callback is required.
+ *
+ * The function requests uPower to change/define the PMIC configuration.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok, -1 if service group is busy,
+ *        -2 if the pointer conversion to physical address failed,
+ *        -3 if called in an invalid API state.
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_vtm_pmic_config(const void *config, uint32_t size, upwr_callb callb);
+
+/**---------------------------------------------------------------
+ * TEMPERATURE MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_tpm_get_temperature() - request uPower to get temperature of one temperature sensor
+ * @sensor_id: temperature sensor ID, support 0~2
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to measure temperature
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_TEMPM as the service group argument.
+ *
+ * The temperature data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ *
+ * uPower return TSEL to the caller (M33 or A35), caller calculate the real temperature
+ * Tsh = 0.000002673049*TSEL[7:0]^3 + 0.0003734262*TSEL[7:0]^2 +
+0.4487042*TSEL[7:0] - 46.98694
+ *
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_tpm_get_temperature(uint32_t sensor_id, upwr_callb callb);
+
+/**---------------------------------------------------------------
+ * DELAY MANAGEMENT SERVICE GROUP
+ */
+
+/**
+ * upwr_dlm_get_delay_margin() - request uPower to get delay margin
+ * @path: The critical path
+ * @index: Use whitch delay meter
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to get delay margin
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The delay margin data read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_get_delay_margin(uint32_t path, uint32_t index, upwr_callb callb);
+
+/**
+ * upwr_dlm_set_delay_margin() - request uPower to set delay margin
+ * @path: The critical path
+ * @index: Use whitch delay meter
+ * @delay_margin: the value of delay margin
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to set delay margin
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The result of the corresponding critical path,  failed or not  read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_set_delay_margin(uint32_t path, uint32_t index, uint32_t delay_margin, upwr_callb callb);
+
+/**
+ * upwr_dlm_process_monitor() - request uPower to do process monitor
+ * @chain_sel: Chain Cell Type Selection
+ * Select the chain to be used for the clock signal generation.
+ * Support two types chain cell, 0~1
+0b - P4 type delay cells selected
+1b - P16 type delay cells selected
+ * @callb: response callback pointer; NULL if no callback needed.
+ * (polling used instead)
+ *
+ * The function requests uPower to do process monitor
+ * The request is executed if arguments are within range, with no protections
+ * regarding the adequate voltage value for the given domain process,
+ * temperature and frequency.
+ *
+ * A callback can be optionally registered, and will be called upon the arrival
+ * of the request response from the uPower firmware, telling if it succeeded
+ * or not.
+ *
+ * A callback may not be registered (NULL pointer), in which case polling has
+ * to be used to check the response, by calling upwr_req_status or
+ * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument.
+ *
+ * The result of process monitor,  failed or not  read from uPower via
+ * the callback argument ret, or written to the variable pointed by retptr,
+ * if polling is used (calls upwr_req_status or upwr_poll_req_status).
+ * ret (or *retptr) also returns the data written on writes.
+ * upower fw needs support cocurrent request from M33 and A35.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ * Note that this is not the error response from the request itself:
+ * it only tells if the request was successfully sent to the uPower.
+ */
+int upwr_dlm_process_monitor(uint32_t chain_sel, upwr_callb callb);
+
+/**---------------------------------------------------------------
+ * DIAGNOSE SERVICE GROUP
+ */
+
+/**
+ * upwr_dgn_mode() - Sets the diagnostic mode.
+ * @mode:  diagnostic mode, which can be:
+ *  - UPWR_DGN_NONE:   no diagnostic recorded
+ *  - UPWR_DGN_TRACE:  warnings, errors, service, internal activity recorded
+ *  - UPWR_DGN_SRVREQ: warnings, errors, service activity recorded
+ *  - UPWR_DGN_WARN:   warnings and errors recorded
+ *  - UPWR_DGN_ALL:    trace, service, warnings, errors, task state recorded
+ *  - UPWR_DGN_ERROR:  only errors recorded
+ *  - UPWR_DGN_ALL2ERR: record all until an error occurs,
+ *    freeze recording on error
+ *  - UPWR_DGN_ALL2HLT: record all until an error occurs,
+ *    executes an ebreak on error, which halts the core if enabled through
+ *    the debug interface
+ * @callb: pointer to the callback called when mode is changed.
+ * NULL if no callback is required.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok,
+ *        -1 if service group is busy,
+ *        -3 if called in an invalid API state
+ */
+int upwr_dgn_mode(upwr_dgn_mode_t mode, const upwr_callb callb);
+
+/**---------------------------------------------------------------
+ * AUXILIARY CALLS
+ */
+
+/**
+ * upwr_rom_version() - informs the ROM firwmware version.
+ * @vmajor: pointer to the variable to get the firmware major version number.
+ * @vminor: pointer to the variable to get the firmware minor version number.
+ * @vfixes: pointer to the variable to get the firmware fixes number.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: SoC id.
+ */
+uint32_t upwr_rom_version(uint32_t *vmajor, uint32_t *vminor, uint32_t *vfixes);
+
+/**
+ * upwr_ram_version() - informs the RAM firwmware version.
+ * @vminor: pointer to the variable to get the firmware minor version number.
+ * @vfixes: pointer to the variable to get the firmware fixes number.
+ *
+ * The 3 values returned are 0 if no RAM firmwmare was loaded and initialized.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: firmware major version number.
+ */
+uint32_t upwr_ram_version(uint32_t *vminor, uint32_t *vfixes);
+
+/**
+ * upwr_req_status() - tells the status of the service group request, and
+ *                     returns a request return value, if any.
+ * @sg: service group of the request
+ * @sgfptr: pointer to the variable that will hold the function id of
+ * the last request completed; can be NULL, in which case it is not used.
+ * @errptr: pointer to the variable that will hold the error code;
+ * can be NULL, in which case it is not used.
+ * @retptr: pointer to the variable that will hold the value returned
+ * by the last request completed (invalid if the last request completed didn't
+ * return any value); can be NULL, in which case it is not used.
+ * Note that a request may return a value even if service error is returned
+ * (*errptr != UPWR_RESP_OK): that is dependent on the specific service.
+ *
+ * This call can be used in a poll loop of a service request completion in case
+ * a callback was not registered.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: service request status: succeeded, failed, or ongoing (busy)
+ */
+
+/* service request status */
+typedef enum {
+	UPWR_REQ_OK,     /* request succeeded */
+	UPWR_REQ_ERR,    /* request failed */
+	UPWR_REQ_BUSY    /* request execution ongoing */
+} upwr_req_status_t;
+
+upwr_req_status_t upwr_req_status(upwr_sg_t sg,
+				  uint32_t *sgfptr,
+				  upwr_resp_t *errptr,
+				  int *retptr);
+
+/**
+ * upwr_poll_req_status() - polls the status of the service group request, and
+ *                          returns a request return value, if any.
+ * @sg: service group of the request
+ * @sgfptr: pointer to the variable that will hold the function id of
+ * the last request completed; can be NULL, in which case it is not used.
+ * @errptr: pointer to the variable that will hold the error code;
+ * can be NULL, in which case it is not used.
+ * @retptr: pointer to the variable that will hold the value returned
+ * by the last request completed (invalid if the last request completed didn't
+ * return any value); can be NULL, in which case it is not used.
+ * Note that a request may return a value even if service error is returned
+ * (*errptr != UPWR_RESP_OK): that is dependent on the specific service.
+ * @attempts: maximum number of polling attempts; if attempts > 0 and is
+ * reached with no service response received, upwr_poll_req_status returns
+ * UPWR_REQ_BUSY and variables pointed by sgfptr, retptr and errptr are not
+ * updated; if attempts = 0, upwr_poll_req_status waits "forever".
+ *
+ * This call can be used to poll a service request completion in case a
+ * callback was not registered.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: service request status: succeeded, failed, or ongoing (busy)
+ */
+upwr_req_status_t upwr_poll_req_status(upwr_sg_t sg,
+				       uint32_t *sgfptr,
+				       upwr_resp_t *errptr,
+				       int *retptr,
+				       uint32_t attempts);
+
+/**
+ * upwr_alarm_code() - returns the alarm code of the last alarm occurrence.
+ *
+ * The value returned is not meaningful if no alarm was issued by uPower.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: alarm code, as defined by the type upwr_alarm_t in upwr_soc_defines.h
+ */
+upwr_alarm_t upwr_alarm_code(void);
+
+/**---------------------------------------------------------------
+ * TRANSMIT/RECEIVE PRIMITIVES
+ * ---------------------------------------------------------------
+ */
+
+typedef void (*UPWR_TX_CALLB_FUNC_T)(void);
+typedef void (*UPWR_RX_CALLB_FUNC_T)(void);
+
+/**
+ * upwr_tx() - queues a message for transmission.
+ * @msg : pointer to the message sent.
+ * @size: message size in 32-bit words
+ * @callback: pointer to a function to be called when transmission done;
+ *            can be NULL, in which case no callback is done.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: number of vacant positions left in the transmission queue, or
+ *         -1 if the queue was already full when upwr_tx was called, or
+ *         -2 if any argument is invalid (like size off-range)
+ */
+int upwr_tx(const uint32_t *msg, unsigned int size,
+	    UPWR_TX_CALLB_FUNC_T callback);
+
+/**
+ * upwr_rx() - unqueues a received message from the reception queue.
+ * @msg: pointer to the message destination buffer.
+ * @size: pointer to variable to hold message size in 32-bit words.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: number of messages remaining in the reception queue, or
+ *         -1 if the queue was already empty when upwr_rx was called, or
+ *         -2 if any argument is invalid (like mu off-range)
+ */
+int upwr_rx(char *msg, unsigned int *size);
+
+/**
+ * upwr_rx_callback() - sets up a callback for a message receiving event.
+ * @callback: pointer to a function to be called when a message arrives;
+ *            can be NULL, in which case no callback is done.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: 0 if ok; -2 if any argument is invalid (mu off-range).
+ */
+int upwr_rx_callback(UPWR_RX_CALLB_FUNC_T callback);
+
+/**
+ * msg_copy() - copies a message.
+ * @dest: pointer to the destination message.
+ * @src : pointer to the source message.
+ * @size: message size in words.
+ *
+ * This is an auxiliary function used by the rest of the API calls.
+ * It is normally not called by the driver code, unless maybe for test purposes.
+ *
+ * Context: no sleep, no locks taken/released.
+ * Return: none (void)
+ */
+void msg_copy(char *dest, char *src, unsigned int size);
+
+#endif /* UPWR_API_H */
diff --git a/plat/imx/imx8ulp/upower/upower_defs.h b/plat/imx/imx8ulp/upower/upower_defs.h
new file mode 100644
index 0000000..118d7e0
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upower_defs.h
@@ -0,0 +1,742 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/**
+ * Copyright 2019-2024 NXP
+ *
+ * KEYWORDS: micro-power uPower driver API
+ * -----------------------------------------------------------------------------
+ * PURPOSE: uPower driver API #defines and typedefs shared with the firmware
+ * -----------------------------------------------------------------------------
+ * PARAMETERS:
+ * PARAM NAME RANGE:DESCRIPTION:       DEFAULTS:                           UNITS
+ * -----------------------------------------------------------------------------
+ * REUSE ISSUES: no reuse issues
+ */
+
+#ifndef UPWR_DEFS_H
+#define UPWR_DEFS_H
+
+#include <stdint.h>
+
+#ifndef UPWR_PMC_SWT_WORDS
+#define UPWR_PMC_SWT_WORDS              (1U)
+#endif
+
+#ifndef UPWR_PMC_MEM_WORDS
+#define UPWR_PMC_MEM_WORDS              (2U)
+#endif
+
+/* ****************************************************************************
+ * DOWNSTREAM MESSAGES - COMMANDS/FUNCTIONS
+ * ****************************************************************************
+ */
+#define UPWR_SRVGROUP_BITS  (4U)
+#define UPWR_FUNCTION_BITS  (4U)
+#define UPWR_PWDOMAIN_BITS  (4U)
+#define UPWR_HEADER_BITS   \
+		(UPWR_SRVGROUP_BITS + UPWR_FUNCTION_BITS + UPWR_PWDOMAIN_BITS)
+#define UPWR_ARG_BITS      (32U - UPWR_HEADER_BITS)
+#if   ((UPWR_ARG_BITS & 1U) > 0U)
+#error "UPWR_ARG_BITS must be an even number"
+#endif
+#define UPWR_ARG64_BITS          (64U - UPWR_HEADER_BITS)
+#define UPWR_HALF_ARG_BITS       (UPWR_ARG_BITS >> 1U)
+#define UPWR_DUAL_OFFSET_BITS    ((UPWR_ARG_BITS + 32U) >> 1U)
+
+/*
+ * message header: header fields common to all downstream messages.
+ */
+struct upwr_msg_hdr {
+	uint32_t domain   : UPWR_PWDOMAIN_BITS; /* power domain */
+	uint32_t srvgrp   : UPWR_SRVGROUP_BITS; /* service group */
+	uint32_t function : UPWR_FUNCTION_BITS; /* function */
+	uint32_t arg      : UPWR_ARG_BITS; /* function-specific argument */
+};
+
+/* generic 1-word downstream message format */
+typedef union {
+	struct upwr_msg_hdr  hdr;
+	uint32_t             word;  /* message first word */
+} upwr_down_1w_msg;
+
+/* generic 2-word downstream message format */
+typedef struct {
+	struct upwr_msg_hdr  hdr;
+	uint32_t             word2;  /* message second word */
+} upwr_down_2w_msg;
+
+/* message format for functions that receive a pointer/offset */
+typedef struct {
+	struct upwr_msg_hdr  hdr;
+	uint32_t             ptr; /* config struct offset */
+} upwr_pointer_msg;
+
+/* message format for functions that receive 2 pointers/offsets */
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint64_t rsv : UPWR_HEADER_BITS;
+		uint64_t ptr0 : UPWR_DUAL_OFFSET_BITS;
+		uint64_t ptr1 : UPWR_DUAL_OFFSET_BITS;
+	} ptrs;
+} upwr_2pointer_msg;
+
+#define UPWR_SG_EXCEPT   (0U) /* 0 = exception           */
+#define UPWR_SG_PWRMGMT  (1U) /* 1 = power management    */
+#define UPWR_SG_DELAYM   (2U) /* 2 = delay   measurement */
+#define	UPWR_SG_VOLTM    (3U) /* 3 = voltage measurement */
+#define UPWR_SG_CURRM    (4U) /* 4 = current measurement */
+#define	UPWR_SG_TEMPM    (5U) /* 5 = temperature measurement */
+#define	UPWR_SG_DIAG     (6U) /* 6 = diagnostic  */
+#define	UPWR_SG_COUNT    (7U)
+
+typedef uint32_t upwr_sg_t;
+
+/* *************************************************************************
+ * Initialization - downstream
+ ***************************************************************************/
+typedef upwr_down_1w_msg upwr_start_msg; /* start command message */
+typedef upwr_down_1w_msg upwr_power_on_msg;   /* power on   command message */
+typedef upwr_down_1w_msg upwr_boot_start_msg; /* boot start command message */
+typedef union {
+	struct upwr_msg_hdr hdr;
+	upwr_power_on_msg   power_on;
+	upwr_boot_start_msg boot_start;
+	upwr_start_msg      start;
+} upwr_startup_down_msg;
+
+/* *************************************************************************
+ * Service Group EXCEPTION - downstream
+ ***************************************************************************/
+
+#define	UPWR_XCP_INIT			(0U) /* 0 = init msg (not a service request itself) */
+#define	UPWR_XCP_PING			(0U) /* 0 = also ping request, since its response isan init msg */
+#define	UPWR_XCP_START			(1U) /* 1 = service start: upwr_start *(not a service request itself) */
+#define	UPWR_XCP_SHUTDOWN		(2U) /* 2 = service shutdown: upwr_xcp_shutdown */
+#define	UPWR_XCP_CONFIG			(3U) /* 3 = uPower configuration: upwr_xcp_config */
+#define	UPWR_XCP_SW_ALARM		(4U) /* 4 = uPower software alarm: upwr_xcp_sw_alarm */
+#define	UPWR_XCP_I2C			(5U) /* 5 = I2C access: upwr_xcp_i2c_access */
+#define	UPWR_XCP_SPARE_6		(6U) /* 6 = spare */
+#define	UPWR_XCP_SET_DDR_RETN		(7U) /* 7 = set/clear ddr retention */
+#define UPWR_XCP_SET_RTD_APD_LLWU	(8U) /* 8 = set/clear rtd/apd llwu */
+#define	UPWR_XCP_SPARE_8		(8U) /* 8 = spare */
+#define UPWR_XCP_SET_RTD_USE_DDR	(9U) /* 9 = M33 core set it is using DDR or not */
+#define	UPWR_XCP_SPARE_9		(9U)  /*  9 = spare */
+#define	UPWR_XCP_SPARE_10		(10U) /* 10 = spare */
+#define	UPWR_XCP_SET_MIPI_DSI_ENA	(10U) /* 10 = set/clear mipi dsi ena */
+#define	UPWR_XCP_SPARE_11		(11U) /* 11 = spare */
+#define	UPWR_XCP_GET_MIPI_DSI_ENA	(11U) /* 11 = get mipi dsi ena status */
+#define	UPWR_XCP_SPARE_12		(12U) /* 12 = spare */
+#define	UPWR_XCP_SET_OSC_MODE		(12U) /* 12 = set uPower OSC mode, high or low */
+#define	UPWR_XCP_SPARE_13		(13U) /* 13 = spare */
+#define	UPWR_XCP_SPARE_14		(14U) /* 14 = spare */
+#define	UPWR_XCP_SPARE_15		(15U) /* 15 = spare */
+#define	UPWR_XCP_F_COUNT		(16U)
+
+typedef uint32_t upwr_xcp_f_t;
+typedef upwr_down_1w_msg    upwr_xcp_ping_msg;
+typedef upwr_down_1w_msg    upwr_xcp_shutdown_msg;
+typedef upwr_power_on_msg   upwr_xcp_power_on_msg;
+typedef upwr_boot_start_msg upwr_xcp_boot_start_msg;
+typedef upwr_start_msg      upwr_xcp_start_msg;
+typedef upwr_down_2w_msg    upwr_xcp_config_msg;
+typedef upwr_down_1w_msg    upwr_xcp_swalarm_msg;
+typedef upwr_down_1w_msg    upwr_xcp_ddr_retn_msg;
+typedef upwr_down_1w_msg    upwr_xcp_set_mipi_dsi_ena_msg;
+typedef upwr_down_1w_msg    upwr_xcp_get_mipi_dsi_ena_msg;
+typedef upwr_down_1w_msg    upwr_xcp_rtd_use_ddr_msg;
+typedef upwr_down_1w_msg    upwr_xcp_rtd_apd_llwu_msg;
+typedef upwr_down_1w_msg    upwr_xcp_set_osc_mode_msg;
+typedef upwr_pointer_msg    upwr_xcp_i2c_msg;
+
+ /* structure pointed by message upwr_xcp_i2c_msg */
+typedef struct {
+	uint16_t addr;
+	int8_t data_size;
+	uint8_t subaddr_size;
+	uint32_t subaddr;
+	uint32_t data;
+} upwr_i2c_access;
+
+/* Exception all messages */
+typedef union {
+	struct upwr_msg_hdr       hdr;       /* message header */
+	upwr_xcp_ping_msg         ping;      /* ping */
+	upwr_xcp_start_msg        start;     /* service start */
+	upwr_xcp_shutdown_msg     shutdown;  /* shutdown */
+	upwr_xcp_boot_start_msg   bootstart; /* boot start */
+	upwr_xcp_config_msg       config;    /* uPower configuration */
+	upwr_xcp_swalarm_msg      swalarm;   /* software alarm */
+	upwr_xcp_i2c_msg          i2c;       /* I2C access */
+	upwr_xcp_ddr_retn_msg     set_ddr_retn;       /* set ddr retention msg */
+	upwr_xcp_set_mipi_dsi_ena_msg     set_mipi_dsi_ena; /* set mipi dsi ena msg */
+	upwr_xcp_get_mipi_dsi_ena_msg     get_mipi_dsi_ena; /* get mipi dsi ena msg */
+	upwr_xcp_rtd_use_ddr_msg     set_rtd_use_ddr; /* set rtd is using ddr msg */
+	upwr_xcp_rtd_apd_llwu_msg     set_llwu; /* set rtd/apd llwu msg */
+	upwr_xcp_set_osc_mode_msg     set_osc_mode; /* set osc_mode msg */
+} upwr_xcp_msg;
+
+/* structure pointed by message upwr_volt_dva_req_id_msg */
+typedef struct {
+	uint32_t id_word0;
+	uint32_t id_word1;
+	uint32_t mode;
+} upwr_dva_id_struct;
+
+/**
+ * PMIC voltage accuracy is 12.5 mV, 12500 uV
+ */
+#define PMIC_VOLTAGE_MIN_STEP 12500U
+
+/* *************************************************************************
+ * Service Group POWER MANAGEMENT - downstream
+ ***************************************************************************/
+
+#define	UPWR_PWM_REGCFG    (0U)     /* 0 = regulator config: upwr_pwm_reg_config */
+#define UPWR_PWM_DEVMODE   (0U)     /* deprecated, for old compile */
+#define	UPWR_PWM_VOLT      (1U)     /* 1 = voltage change: upwr_pwm_chng_reg_voltage */
+#define	UPWR_PWM_SWITCH    (2U)     /* 2 = switch control: upwr_pwm_chng_switch_mem */
+#define UPWR_PWM_PWR_ON    (3U)     /* 3 = switch/RAM/ROM power on: upwr_pwm_power_on  */
+#define	UPWR_PWM_PWR_OFF   (4U)     /* 4 = switch/RAM/ROM power off: upwr_pwm_power_off */
+#define	UPWR_PWM_RETAIN    (5U)     /* 5 = retain memory array: upwr_pwm_mem_retain */
+#define UPWR_PWM_DOM_BIAS  (6U)     /* 6 = Domain bias control: upwr_pwm_chng_dom_bias */
+#define	UPWR_PWM_MEM_BIAS  (7U)     /* 7 = Memory bias control: upwr_pwm_chng_mem_bias */
+#define	UPWR_PWM_PMICCFG   (8U)     /* 8 = PMIC configuration:  upwr_pwm_pmic_config */
+#define	UPWR_PWM_PMICMOD   (8U)     /* deprecated, for old compile */
+#define	UPWR_PWM_PES       (9U)     /* 9 so far, no use */
+#define	UPWR_PWM_CONFIG    (10U)    /* 10= apply power mode defined configuration */
+#define	UPWR_PWM_CFGPTR    (11U)    /* 11= configuration pointer */
+#define	UPWR_PWM_DOM_PWRON (12U)    /* 12 = domain power on: upwr_pwm_dom_power_on */
+#define	UPWR_PWM_BOOT      (13U)    /* 13 = boot start: upwr_pwm_boot_start */
+#define UPWR_PWM_FREQ      (14U)    /* 14 = domain frequency setup */
+#define	UPWR_PWM_PARAM     (15U)    /* 15 = power management parameters */
+#define	UPWR_PWM_F_COUNT (16U)
+
+typedef uint32_t upwr_pwm_f_t;
+
+#define MAX_PMETER_SSEL 7U
+
+#define	UPWR_VTM_CHNG_PMIC_RAIL_VOLT    (0U)      /* 0 = change pmic rail voltage */
+#define	UPWR_VTM_GET_PMIC_RAIL_VOLT     (1U)      /* 1 = get pmic rail voltage */
+#define UPWR_VTM_PMIC_CONFIG            (2U)      /* 2 = configure PMIC IC */
+#define UPWR_VTM_DVA_DUMP_INFO          (3U)      /* 3 = dump dva information */
+#define UPWR_VTM_DVA_REQ_ID             (4U)      /* 4 = dva request ID array */
+#define UPWR_VTM_DVA_REQ_DOMAIN         (5U)      /* 5 = dva request domain */
+#define UPWR_VTM_DVA_REQ_SOC            (6U)      /* 6 = dva request the whole SOC */
+#define UPWR_VTM_PMETER_MEAS            (7U)      /* 7 = pmeter measure */
+#define UPWR_VTM_VMETER_MEAS            (8U)      /* 8 = vmeter measure */
+#define UPWR_VTM_PMIC_COLD_RESET        (9U)      /* 9 = pmic cold reset */
+#define UPWR_VTM_SET_DVFS_PMIC_RAIL     (10U)     /* 10 = set which domain use which pmic rail, for DVFS use */
+#define UPWR_VTM_SET_PMIC_MODE          (11U)     /* 11 = set pmic mode */
+#define UPWR_VTM_F_COUNT                (16U)
+
+typedef uint32_t upwr_volt_f_t;
+
+#define VMETER_SEL_RTD 0U
+#define VMETER_SEL_LDO 1U
+#define VMETER_SEL_APD 2U
+#define VMETER_SEL_AVD 3U
+#define VMETER_SEL_MAX 3U
+
+/**
+ * The total TSEL count is 256
+ */
+#define MAX_TEMP_TSEL 256U
+
+/**
+ * Support 3 temperature sensor, sensor 0, 1, 2
+ */
+#define MAX_TEMP_SENSOR 2U
+
+#define UPWR_TEMP_GET_CUR_TEMP (0U)  /* 0 = get current temperature */
+#define UPWR_TEMP_F_COUNT      (1U)
+typedef uint32_t upwr_temp_f_t;
+
+#define UPWR_DMETER_GET_DELAY_MARGIN (0U)  /* 0 = get delay margin */
+#define UPWR_DMETER_SET_DELAY_MARGIN (1U) /* 1 = set delay margin */
+#define UPWR_PMON_REQ                (2U) /* 2 = process monitor service */
+#define UPWR_DMETER_F_COUNT          (3U)
+
+typedef uint32_t upwr_dmeter_f_t;
+
+typedef upwr_down_1w_msg upwr_volt_pmeter_meas_msg;
+typedef upwr_down_1w_msg upwr_volt_pmic_set_mode_msg;
+typedef upwr_down_1w_msg upwr_volt_vmeter_meas_msg;
+
+struct upwr_reg_config_t {
+	uint32_t reg;
+};
+
+ /* set of 32 switches */
+struct upwr_switch_board_t {
+	uint32_t on;   /* Switch on state,1 bit per instance */
+	uint32_t mask; /* actuation mask, 1 bit per instance */
+};
+
+ /* set of 32 RAM/ROM switches */
+struct upwr_mem_switches_t {
+	uint32_t array;   /* RAM/ROM array state, 1 bit per instance */
+	uint32_t perif;   /* RAM/ROM peripheral state, 1 bit per instance */
+	uint32_t mask;    /* actuation mask, 1 bit per instance */
+};
+
+typedef upwr_down_1w_msg upwr_pwm_dom_pwron_msg;  /* domain power on message */
+typedef upwr_down_1w_msg upwr_pwm_boot_start_msg; /* boot start message */
+
+/* functions with complex arguments use the pointer message formats: */
+typedef upwr_pointer_msg upwr_pwm_retain_msg;
+typedef upwr_pointer_msg upwr_pwm_pmode_cfg_msg;
+
+#if (UPWR_ARG_BITS < UPWR_DOMBIAS_ARG_BITS)
+#if ((UPWR_ARG_BITS + 32) < UPWR_DOMBIAS_ARG_BITS)
+#error "too few message bits for domain bias argument"
+#endif
+#endif
+
+/* service upwr_pwm_chng_dom_bias message argument fields */
+#define UPWR_DOMBIAS_MODE_BITS    (2U)
+#define UPWR_DOMBIAS_RBB_BITS     (8U)
+#define UPWR_DOMBIAS_RSV_BITS     (14U)
+#define UPWR_DOMBIAS_ARG_BITS     (UPWR_DOMBIAS_RSV_BITS + \
+				  (2U * UPWR_DOMBIAS_MODE_BITS) + \
+				  (4U * UPWR_DOMBIAS_RBB_BITS) + 2U)
+/*
+ * upwr_pwm_dom_bias_args is an SoC-dependent message,
+ */
+typedef struct {
+	uint32_t: 12U; /* TODO: find a way to use UPWR_HEADER_BITS */
+	uint32_t dommode : UPWR_DOMBIAS_MODE_BITS;
+	uint32_t avdmode : UPWR_DOMBIAS_MODE_BITS;
+	uint32_t domapply : 1U;
+	uint32_t avdapply : 1U;
+	uint32_t rsv : UPWR_DOMBIAS_RSV_BITS;
+	uint32_t domrbbn : UPWR_DOMBIAS_RBB_BITS; /* RTD/APD back bias N-well */
+	uint32_t domrbbp : UPWR_DOMBIAS_RBB_BITS; /* RTD/APD back bias P-well */
+	uint32_t avdrbbn : UPWR_DOMBIAS_RBB_BITS; /* AVD back bias N-well */
+	uint32_t avdrbbp : UPWR_DOMBIAS_RBB_BITS; /* AVD back bias P-well */
+} upwr_pwm_dom_bias_args;
+
+
+typedef union {
+	struct upwr_msg_hdr hdr; /* message header */
+	struct {
+		upwr_pwm_dom_bias_args B;
+	} args;
+} upwr_pwm_dom_bias_msg;
+
+/* service upwr_pwm_chng_mem_bias message argument fields */
+/*
+ * upwr_pwm_mem_bias_args is an SoC-dependent message,
+ * defined in upower_soc_defs.h
+ */
+typedef struct {
+	uint32_t: 12U; /* TODO: find a way to use UPWR_HEADER_BITS */
+	uint32_t en : 1U;
+	uint32_t rsv : 19U;
+} upwr_pwm_mem_bias_args;
+
+typedef union {
+	struct upwr_msg_hdr hdr; /* message header */
+	struct {
+		upwr_pwm_mem_bias_args B;
+	} args;
+} upwr_pwm_mem_bias_msg;
+
+typedef upwr_pointer_msg upwr_pwm_pes_seq_msg;
+
+/* upwr_pwm_reg_config-specific message format */
+typedef upwr_pointer_msg upwr_pwm_regcfg_msg;
+
+/* upwr_volt_pmic_volt-specific message format */
+typedef union {
+	struct upwr_msg_hdr hdr; /* message header */
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t domain : 8U;
+		uint32_t rail : 8U;
+	} args;
+} upwr_volt_dom_pmic_rail_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t rail : 4U;  /* pmic rail id  */
+		uint32_t volt : 12U; /* voltage value, accurate to mV, support 0~3.3V */
+	} args;
+} upwr_volt_pmic_set_volt_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t rail : 16U;  /* pmic rail id  */
+	} args;
+} upwr_volt_pmic_get_volt_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv :UPWR_HEADER_BITS;
+		uint32_t domain : 8U;
+		uint32_t mode : 8U; /* work mode */
+	} args;
+} upwr_volt_dva_req_domain_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t mode : 16U;  /* work mode  */
+	} args;
+} upwr_volt_dva_req_soc_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t addr_offset : 16U;  /* addr_offset to 0x28330000  */
+	} args;
+} upwr_volt_dva_dump_info_msg;
+
+typedef upwr_pointer_msg upwr_volt_pmiccfg_msg;
+typedef upwr_pointer_msg upwr_volt_dva_req_id_msg;
+typedef upwr_down_1w_msg upwr_volt_pmic_cold_reset_msg;
+
+/* upwr_pwm_volt-specific message format */
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t reg : UPWR_HALF_ARG_BITS;  /* regulator id  */
+		uint32_t volt : UPWR_HALF_ARG_BITS; /* voltage value */
+	} args;
+} upwr_pwm_volt_msg;
+
+/* upwr_pwm_freq_setup-specific message format */
+/**
+ * DVA adjust stage
+ */
+#define DVA_ADJUST_STAGE_INVALID 0U
+/* first stage, gross adjust, for increase frequency use */
+#define DVA_ADJUST_STAGE_ONE 1U
+/* second stage, fine adjust for increase frequency use */
+#define DVA_ADJUST_STAGE_TWO 2U
+/* combine first + second stage, for descrese frequency use */
+#define DVA_ADJUST_STAGE_FULL 3U
+
+/**
+ * This message structure is used for DVFS feature
+ * 1. Because user may use different PMIC or different board,
+ * the pmic regulator of RTD/APD may change,
+ * so, user need to tell uPower the regulator number.
+ * The number must be matched with PMIC IC and board.
+ * use 4 bits for pmic regulator, support to 16 regulator.
+ *
+ * use 2 bits for DVA stage
+ *
+ * use 10 bits for target frequency, accurate to MHz, support to 1024 MHz
+ */
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t rail : 4; /* pmic regulator  */
+		uint32_t stage : 2; /* DVA stage */
+		uint32_t target_freq : 10; /* target frequency */
+	} args;
+} upwr_pwm_freq_msg;
+
+typedef upwr_down_2w_msg upwr_pwm_param_msg;
+
+/* upwr_pwm_pmiccfg-specific message format */
+typedef upwr_pointer_msg upwr_pwm_pmiccfg_msg;
+
+/* functions that pass a pointer use message format upwr_pointer_msg */
+typedef upwr_pointer_msg upwr_pwm_cfgptr_msg;
+
+/* functions that pass 2 pointers use message format upwr_2pointer_msg
+ */
+typedef upwr_2pointer_msg upwr_pwm_switch_msg;
+typedef upwr_2pointer_msg upwr_pwm_pwron_msg;
+typedef upwr_2pointer_msg upwr_pwm_pwroff_msg;
+
+/* Power Management all messages */
+typedef union {
+	struct upwr_msg_hdr     hdr;      /* message header */
+	upwr_pwm_param_msg      param;    /* power management parameters */
+	upwr_pwm_dom_bias_msg   dom_bias; /* domain bias message */
+	upwr_pwm_mem_bias_msg   mem_bias; /* memory bias message */
+	upwr_pwm_pes_seq_msg    pes;      /* PE seq. message */
+	upwr_pwm_pmode_cfg_msg  pmode;    /* power mode config message */
+	upwr_pwm_regcfg_msg     regcfg;   /* regulator config message */
+	upwr_pwm_volt_msg       volt;     /* set voltage message */
+	upwr_pwm_freq_msg       freq;     /* set frequency message */
+	upwr_pwm_switch_msg     switches; /* switch control message */
+	upwr_pwm_pwron_msg      pwron;    /* switch/RAM/ROM power on  message */
+	upwr_pwm_pwroff_msg     pwroff;   /* switch/RAM/ROM power off message */
+	upwr_pwm_retain_msg     retain;   /* memory retain message */
+	upwr_pwm_cfgptr_msg     cfgptr;   /* configuration pointer message*/
+	upwr_pwm_dom_pwron_msg  dompwron; /* domain power on message */
+	upwr_pwm_boot_start_msg boot;     /* boot start      message */
+} upwr_pwm_msg;
+
+typedef union {
+	struct upwr_msg_hdr     hdr;      /* message header */
+	upwr_volt_pmic_set_volt_msg  set_pmic_volt;     /* set pmic voltage message */
+	upwr_volt_pmic_get_volt_msg  get_pmic_volt;     /* set pmic voltage message */
+	upwr_volt_pmic_set_mode_msg  set_pmic_mode;     /* set pmic mode message */
+	upwr_volt_pmiccfg_msg    pmiccfg;  /* PMIC configuration message */
+	upwr_volt_dom_pmic_rail_msg   dom_pmic_rail; /* domain bias message */
+	upwr_volt_dva_dump_info_msg    dva_dump_info;  /* dump dva info message */
+	upwr_volt_dva_req_id_msg    dva_req_id;  /* dump dva request id array message */
+	upwr_volt_dva_req_domain_msg    dva_req_domain;  /* dump dva request domain message */
+	upwr_volt_dva_req_soc_msg    dva_req_soc;  /* dump dva request whole soc message */
+	upwr_volt_pmeter_meas_msg    pmeter_meas_msg;  /* pmeter measure message */
+	upwr_volt_vmeter_meas_msg    vmeter_meas_msg;  /* vmeter measure message */
+	upwr_volt_pmic_cold_reset_msg    cold_reset_msg;  /* pmic cold reset message */
+} upwr_volt_msg;
+
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t sensor_id : 16U; /* temperature sensor id  */
+	} args;
+} upwr_temp_get_cur_temp_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t index : 8U; /* the delay meter index  */
+		uint32_t path : 8U; /* the critical path number  */
+	} args;
+} upwr_dmeter_get_delay_margin_msg;
+
+#define MAX_DELAY_MARGIN 63U
+#define MAX_DELAY_CRITICAL_PATH 7U
+#define MAX_DELAY_METER_NUM 1U
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t index: 4U;  /* the delay meter index  */
+		uint32_t path: 4U;  /* the critical path number  */
+		uint32_t dm: 8U;  /* the delay margin value of delay meter  */
+	} args;
+} upwr_dmeter_set_delay_margin_msg;
+
+#define MAX_PMON_CHAIN_SEL 1U
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_HEADER_BITS;
+		uint32_t chain_sel : 16U;  /* the process monitor delay chain sel  */
+	} args;
+} upwr_pmon_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr; /* message header */
+	upwr_temp_get_cur_temp_msg get_temp_msg; /* get current temperature message */
+} upwr_temp_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr; /* message header */
+	upwr_dmeter_get_delay_margin_msg  get_margin_msg; /* get delay margin message */
+	upwr_dmeter_set_delay_margin_msg  set_margin_msg; /* set delay margin message */
+	upwr_pmon_msg pmon_msg; /* process monitor message */
+} upwr_dmeter_msg;
+
+typedef upwr_down_2w_msg upwr_down_max_msg; /* longest downstream msg */
+
+/*
+ * upwr_dom_bias_cfg_t and upwr_mem_bias_cfg_t are SoC-dependent structs,
+ * defined in upower_soc_defs.h
+ */
+/* Power and mem switches */
+typedef struct {
+	volatile struct upwr_switch_board_t swt_board[UPWR_PMC_SWT_WORDS];
+	volatile struct upwr_mem_switches_t swt_mem[UPWR_PMC_MEM_WORDS];
+} swt_config_t;
+
+/* *************************************************************************
+ * Service Group DIAGNOSE - downstream
+ ***************************************************************************/
+/* Diagnose Functions */
+#define	UPWR_DGN_MODE              (0U) /* 0 = diagnose mode: upwr_dgn_mode */
+#define	UPWR_DGN_F_COUNT           (1U)
+#define UPWR_DGN_BUFFER_EN         (2U)
+typedef uint32_t upwr_dgn_f_t;
+
+#define UPWR_DGN_ALL2ERR            (0U) /* record all until an error occurs, freeze recording on error */
+#define UPWR_DGN_ALL2HLT            (1U) /* record all until an error occurs, halt core on error */
+#define UPWR_DGN_ALL                (2U) /* trace, warnings, errors, task state recorded */
+#define UPWR_DGN_MAX                UPWR_DGN_ALL
+#define UPWR_DGN_TRACE              (3U) /* trace, warnings, errors recorded */
+#define UPWR_DGN_SRVREQ             (4U) /* service request activity recorded */
+#define UPWR_DGN_WARN               (5U) /* warnings and errors recorded */
+#define UPWR_DGN_ERROR              (6U) /* only errors recorded */
+#define UPWR_DGN_NONE               (7U) /* no diagnostic recorded */
+#define UPWR_DGN_COUNT              (8U)
+typedef uint32_t upwr_dgn_mode_t;
+
+typedef upwr_down_1w_msg upwr_dgn_mode_msg;
+
+typedef union {
+	struct upwr_msg_hdr hdr;
+	upwr_dgn_mode_msg mode_msg;
+} upwr_dgn_msg;
+
+typedef struct {
+	struct upwr_msg_hdr hdr;
+	uint32_t buf_addr;
+} upwr_dgn_v2_msg;
+
+/* diagnostics log types in the shared RAM log buffer */
+
+typedef enum {
+	DGN_LOG_NONE       = 0x00000000,
+	DGN_LOG_INFO       = 0x10000000,
+	DGN_LOG_ERROR      = 0x20000000,
+	DGN_LOG_ASSERT     = 0x30000000,
+	DGN_LOG_EXCEPT     = 0x40000000,
+	DGN_LOG_EVENT      = 0x50000000, // old event trace
+	DGN_LOG_EVENTNEW   = 0x60000000, // new event trace
+	DGN_LOG_SERVICE    = 0x70000000,
+	DGN_LOG_TASKDEF    = 0x80000000,
+	DGN_LOG_TASKEXE    = 0x90000000,
+	DGN_LOG_MUTEX      = 0xA0000000,
+	DGN_LOG_SEMAPH     = 0xB0000000,
+	DGN_LOG_TIMER      = 0xC0000000,
+	DGN_LOG_CALLTRACE  = 0xD0000000,
+	DGN_LOG_DATA       = 0xE0000000,
+	DGN_LOG_PCTRACE    = 0xF0000000
+} upwr_dgn_log_t;
+
+/* ****************************************************************************
+ * UPSTREAM MESSAGES - RESPONSES
+ * ****************************************************************************
+ */
+/* generic ok/ko response message */
+#define UPWR_RESP_ERR_BITS (4U)
+#define UPWR_RESP_HDR_BITS (UPWR_RESP_ERR_BITS+\
+			    UPWR_SRVGROUP_BITS+UPWR_FUNCTION_BITS)
+#define UPWR_RESP_RET_BITS (32U - UPWR_RESP_HDR_BITS)
+
+#define UPWR_RESP_OK                (0U) /* no error */
+#define UPWR_RESP_SG_BUSY           (1U) /* service group is busy */
+#define UPWR_RESP_SHUTDOWN          (2U) /* services not up or shutting down */
+#define UPWR_RESP_BAD_REQ           (3U) /* invalid request */
+#define UPWR_RESP_BAD_STATE         (4U) /* system state doesn't allow perform the request */
+#define UPWR_RESP_UNINSTALLD        (5U) /* service or function not installed */
+#define UPWR_RESP_UNINSTALLED       (5U) /* service or function not installed (alias) */
+#define UPWR_RESP_RESOURCE          (6U) /* resource not available */
+#define UPWR_RESP_TIMEOUT           (7U) /* service timeout */
+#define UPWR_RESP_COUNT             (8U)
+
+typedef uint32_t upwr_resp_t;
+
+struct upwr_resp_hdr {
+	uint32_t errcode : UPWR_RESP_ERR_BITS;
+	uint32_t srvgrp  : UPWR_SRVGROUP_BITS;      /* service group */
+	uint32_t function: UPWR_FUNCTION_BITS;
+	uint32_t ret     : UPWR_RESP_RET_BITS;      /* return value, if any */
+};
+
+/* generic 1-word upstream message format */
+typedef union {
+	struct upwr_resp_hdr hdr;
+	uint32_t word;
+} upwr_resp_msg;
+
+/* generic 2-word upstream message format */
+typedef struct {
+	struct upwr_resp_hdr hdr;
+	uint32_t word2;  /* message second word */
+} upwr_up_2w_msg;
+
+typedef upwr_up_2w_msg upwr_up_max_msg;
+
+/* *************************************************************************
+ * Exception/Initialization - upstream
+ ***************************************************************************/
+#define UPWR_SOC_BITS    (7U)
+#define UPWR_VMINOR_BITS (4U)
+#define UPWR_VFIXES_BITS (4U)
+#define UPWR_VMAJOR_BITS \
+		(32U - UPWR_HEADER_BITS - UPWR_SOC_BITS - UPWR_VMINOR_BITS - UPWR_VFIXES_BITS)
+
+typedef struct {
+	uint32_t soc_id;
+	uint32_t vmajor;
+	uint32_t vminor;
+	uint32_t vfixes;
+} upwr_code_vers_t;
+
+/* message sent by firmware initialization, received by upwr_init */
+typedef union {
+	struct upwr_resp_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_RESP_HDR_BITS;
+		uint32_t soc : UPWR_SOC_BITS;        /* SoC identification */
+		uint32_t vmajor : UPWR_VMAJOR_BITS;  /* firmware major version */
+		uint32_t vminor : UPWR_VMINOR_BITS;  /* firmware minor version */
+		uint32_t vfixes : UPWR_VFIXES_BITS;  /* firmware fixes version */
+	} args;
+} upwr_init_msg;
+
+/* message sent by firmware when the core platform is powered up */
+typedef upwr_resp_msg upwr_power_up_msg;
+
+/* message sent by firmware when the core reset is released for boot */
+typedef upwr_resp_msg upwr_boot_up_msg;
+
+/* message sent by firmware when ready for service requests */
+#define UPWR_RAM_VMINOR_BITS (7)
+#define UPWR_RAM_VFIXES_BITS (6)
+#define UPWR_RAM_VMAJOR_BITS (32 - UPWR_HEADER_BITS \
+		- UPWR_RAM_VFIXES_BITS - UPWR_RAM_VMINOR_BITS)
+typedef union {
+	struct upwr_resp_hdr hdr;
+	struct {
+		uint32_t rsv : UPWR_RESP_HDR_BITS;
+		uint32_t vmajor : UPWR_RAM_VMAJOR_BITS; /* RAM fw major version */
+		uint32_t vminor : UPWR_RAM_VMINOR_BITS; /* RAM fw minor version */
+		uint32_t vfixes : UPWR_RAM_VFIXES_BITS; /* RAM fw fixes version */
+	} args;
+} upwr_ready_msg;
+
+/* message sent by firmware when shutdown finishes */
+typedef upwr_resp_msg upwr_shutdown_msg;
+
+typedef union {
+	struct upwr_resp_hdr hdr;
+	upwr_init_msg        init;
+	upwr_power_up_msg    pwrup;
+	upwr_boot_up_msg     booted;
+	upwr_ready_msg       ready;
+} upwr_startup_up_msg;
+
+/* message sent by firmware for uPower config setting */
+typedef upwr_resp_msg upwr_config_resp_msg;
+
+/* message sent by firmware for uPower alarm */
+typedef upwr_resp_msg upwr_alarm_resp_msg;
+
+/* *************************************************************************
+ * Power Management - upstream
+ ***************************************************************************/
+typedef upwr_resp_msg upwr_param_resp_msg;
+
+enum work_mode {
+	OVER_DRIVE,
+	NORMAL_DRIVE,
+	LOW_DRIVE
+};
+
+#define UTIMER3_MAX_COUNT 0xFFFFU
+
+#endif /* UPWR_DEFS_H */
diff --git a/plat/imx/imx8ulp/upower/upower_hal.c b/plat/imx/imx8ulp/upower/upower_hal.c
new file mode 100644
index 0000000..337857b
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upower_hal.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2020-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "upower_api.h"
+#include "upower_defs.h"
+
+#define UPOWER_AP_MU1_ADDR	U(0x29280000)
+
+struct MU_t *muptr = (struct MU_t *)UPOWER_AP_MU1_ADDR;
+
+void upower_apd_inst_isr(upwr_isr_callb txrx_isr,
+			 upwr_isr_callb excp_isr)
+{
+	/* Do nothing */
+}
+
+int upower_status(int status)
+{
+	int ret = -1;
+
+	switch (status) {
+	case 0:
+		VERBOSE("finished successfully!\n");
+		ret = 0;
+		break;
+	case -1:
+		VERBOSE("memory allocation or resource failed!\n");
+		break;
+	case -2:
+		VERBOSE("invalid argument!\n");
+		break;
+	case -3:
+		VERBOSE("called in an invalid API state!\n");
+		break;
+	default:
+		VERBOSE("invalid return status\n");
+		break;
+	}
+
+	return ret;
+}
+
+
+void upower_wait_resp(void)
+{
+	while (muptr->RSR.B.RF0 == 0) {
+		udelay(100);
+	}
+	upwr_txrx_isr();
+}
+
+static void user_upwr_rdy_callb(uint32_t soc, uint32_t vmajor, uint32_t vminor)
+{
+	NOTICE("%s: soc=%x\n", __func__, soc);
+	NOTICE("%s: RAM version:%d.%d\n", __func__, vmajor, vminor);
+}
+
+int upower_init(void)
+{
+	int status;
+
+	status = upwr_init(APD_DOMAIN, muptr, NULL, NULL, upower_apd_inst_isr, NULL);
+	if (upower_status(status)) {
+		ERROR("%s: upower init failure\n", __func__);
+		return -EINVAL;
+	}
+
+	NOTICE("%s: start uPower RAM service\n", __func__);
+	status = upwr_start(1, user_upwr_rdy_callb);
+	upower_wait_resp();
+	/* poll status */
+	if (upower_status(status)) {
+		NOTICE("%s: upower init failure\n", __func__);
+		return status;
+	}
+
+	return 0;
+}
+
+int upower_pwm(int domain_id, bool pwr_on)
+{
+	int ret, ret_val;
+	uint32_t swt;
+
+	if (domain_id == 9U || domain_id == 11U || domain_id == 12U) {
+		swt = BIT_32(12) | BIT_32(11) | BIT_32(10) | BIT_32(9);
+	} else {
+		swt = BIT_32(domain_id);
+	}
+
+	if (pwr_on) {
+		ret = upwr_pwm_power_on(&swt, NULL, NULL);
+	} else {
+		ret = upwr_pwm_power_off(&swt, NULL, NULL);
+	}
+
+	if (ret) {
+		NOTICE("%s failed: ret: %d, pwr_on: %d\n", __func__, ret, pwr_on);
+		return ret;
+	}
+	upower_wait_resp();
+
+	ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
+	if (ret != UPWR_REQ_OK) {
+		NOTICE("Failure %d, %s\n", ret, __func__);
+		if (ret == UPWR_REQ_BUSY) {
+			return -EBUSY;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int upower_read_temperature(uint32_t sensor_id, int32_t *temperature)
+{
+	int ret, ret_val;
+	upwr_resp_t err_code;
+	int64_t t;
+
+	ret = upwr_tpm_get_temperature(sensor_id, NULL);
+	if (ret) {
+		return ret;
+	}
+
+	upower_wait_resp();
+	ret = upwr_poll_req_status(UPWR_SG_TEMPM, NULL, &err_code, &ret_val, 1000);
+	if (ret > UPWR_REQ_OK) {
+		return ret;
+	}
+
+	t = ret_val & 0xff;
+	*temperature = (2673049 * t * t * t / 10000000 + 3734262 * t * t / 100000 +
+			4487042 * t / 100 - 4698694) / 100000;
+
+	return 0;
+}
+
+int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val)
+{
+	int ret, ret_val;
+	upwr_resp_t err_code;
+
+	ret = upwr_xcp_i2c_access(0x32, 1, 1, reg_addr, reg_val, NULL);
+	if (ret) {
+		WARN("pmic i2c read failed ret %d\n", ret);
+		return ret;
+	}
+
+	upower_wait_resp();
+	ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000);
+	if (ret != UPWR_REQ_OK) {
+		WARN("i2c poll Failure %d, err_code %d, ret_val 0x%x\n",
+		     ret, err_code, ret_val);
+		return ret;
+	}
+
+	VERBOSE("PMIC write reg[0x%x], val[0x%x]\n", reg_addr, reg_val);
+
+	return 0;
+}
+
+int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val)
+{
+	int ret, ret_val;
+	upwr_resp_t err_code;
+
+	if (reg_val == NULL) {
+		return -1;
+	}
+
+	ret = upwr_xcp_i2c_access(0x32, -1, 1, reg_addr, 0, NULL);
+	if (ret) {
+		WARN("pmic i2c read failed ret %d\n", ret);
+		return ret;
+	}
+
+	upower_wait_resp();
+	ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000);
+	if (ret != UPWR_REQ_OK) {
+		WARN("i2c poll Failure %d, err_code %d, ret_val 0x%x\n",
+			ret, err_code, ret_val);
+		return ret;
+	}
+
+	*reg_val = ret_val;
+
+	VERBOSE("PMIC read reg[0x%x], val[0x%x]\n", reg_addr, *reg_val);
+
+	return 0;
+}
diff --git a/plat/imx/imx8ulp/upower/upower_soc_defs.h b/plat/imx/imx8ulp/upower/upower_soc_defs.h
new file mode 100644
index 0000000..111be14
--- /dev/null
+++ b/plat/imx/imx8ulp/upower/upower_soc_defs.h
@@ -0,0 +1,1154 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/**
+ * Copyright 2019-2024 NXP
+ *
+ * KEYWORDS: micro-power uPower driver API
+ * -----------------------------------------------------------------------------
+ * PURPOSE: SoC-dependent uPower driver API #defines and typedefs shared
+ *          with the firmware
+ * -----------------------------------------------------------------------------
+ * PARAMETERS:
+ * PARAM NAME RANGE:DESCRIPTION:       DEFAULTS:                           UNITS
+ * -----------------------------------------------------------------------------
+ * REUSE ISSUES: no reuse issues
+ */
+
+#ifndef UPWR_SOC_DEFS_H
+#define UPWR_SOC_DEFS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "upower_defs.h"
+
+#define UPWR_MU_MSG_SIZE            (2U) /* words */
+
+#ifdef NUM_PMC_SWT_WORDS
+#define UPWR_PMC_SWT_WORDS          NUM_PMC_SWT_WORDS
+#endif
+
+#ifdef NUM_PMC_RAM_WORDS
+#define UPWR_PMC_MEM_WORDS          NUM_PMC_RAM_WORDS
+#endif
+
+#ifndef UPWR_DRAM_SHARED_BASE_ADDR
+#define UPWR_DRAM_SHARED_BASE_ADDR      (0x28330000U)
+#endif
+
+#ifndef UPWR_DRAM_SHARED_SIZE
+#define UPWR_DRAM_SHARED_SIZE           (2048U)
+#endif
+
+#define UPWR_DRAM_SHARED_ENDPLUS        (UPWR_DRAM_SHARED_BASE_ADDR+\
+					 UPWR_DRAM_SHARED_SIZE)
+
+#ifndef UPWR_API_BUFFER_BASE
+#define UPWR_API_BUFFER_BASE            (0x28330600U)
+#endif
+
+#ifndef UPWR_API_BUFFER_ENDPLUS
+#define UPWR_API_BUFFER_ENDPLUS         (UPWR_DRAM_SHARED_ENDPLUS - 64U)
+#endif
+
+#ifndef UPWR_PMC_SWT_WORDS
+#define UPWR_PMC_SWT_WORDS              (1U)
+#endif
+
+#ifndef UPWR_PMC_MEM_WORDS
+#define UPWR_PMC_MEM_WORDS              (2U)
+#endif
+
+#define UPWR_OSC_HI_FREQ               (64U) // MHz
+#define UPWR_OSC_LO_FREQ               (16U) // MHz
+
+#ifndef UPWR_I2C_FREQ
+#define UPWR_I2C_FREQ                  (UPWR_OSC_HI_FREQ * 1000000U)
+#endif
+
+/*
+ * i.MX8ULP-dependent uPower API Definition
+ *
+ * This chapter documents the API definitions that are specific to the
+ * i.MX8ULP SoC.
+ *
+ */
+
+/**---------------------------------------------------------------
+ * INITIALIZATION, CONFIGURATION
+ *
+ * i.MX8ULP provides only one Message Unit (MU) for each core domain:
+ * Real Time Domain (RTD) and Application Domain (APD), which has two A35 cores.
+ * Both A35 cores in APD must share the same API instance, meaning upwr_init
+ * must be called only once for each domain. The API does not provide any
+ * mutually exclusion or locking mechanism for concurrent accesses from both
+ * APD cores, so any API arbitration, if needed, must be implemented by the
+ * API user code.
+ *
+ * A domain must not go to Power Down (PD) or Deep Power Down (DPD) power modes
+ * with any service still pending (response not received).
+ *
+ * Next sections describe the i.MX8ULP particularities of service calls.
+ *
+ */
+
+/**+
+ * upwr_start()
+ *
+ * i.MX8ULP ROM firmware provides only the launch option 0, which has no
+ * power mode transition support and provides the following services:
+ * - upwr_xcp_config
+ * - upwr_xcp_sw_alarm
+ * - upwr_pwm_param
+ * - upwr_pwm_power_on
+ * - upwr_pwm_power-off
+ * - upwr_pwm_mem_retain
+ * - upwr_pwm_chng_dom_bias
+ * - upwr_pwm_chng_mem_bias
+ *
+ * i.MX8ULP RAM firmware provides 2 launch options:
+ *
+ * 1. starts all tasks, services and power mode ones;
+ *    this is the full-featured firmware option.
+ * 2. starts only the power mode tasks; services are not available with
+ *    this option, and futher calls to upwr_start (from either domain)
+ *    have no response; this option is mostly used to accelerate power mode
+ *    mixed-signal simulations, and not intended to be used with silicon.
+ *
+ * Note: option 0 is also available if the RAM firmware is loaded.
+ */
+
+/* service upwr_pwm_set_domain_pmic_rail message argument fields*/
+typedef struct {
+	uint32_t domain : 16U;
+	uint32_t rail : 16U;
+} upwr_pwm_dom_pmic_rail_args;
+
+#define UPWR_FILL_DOMBIAS_ARGS(dom, bias, args)           \
+do {                                                      \
+	(args).B.domapply = (args).B.avdapply = 0U;            \
+	switch ((bias)->apply) {                            \
+	case BIAS_APPLY_RTD_AVD:                  \
+		(args).B.avdapply = 1U;              \
+	/* fall through */                        \
+	case BIAS_APPLY_RTD:                      \
+		(dom) = (uint32_t)RTD_DOMAIN;       \
+		(args).B.domapply = 1U;              \
+		break;                            \
+	case BIAS_APPLY_APD_AVD:                  \
+		(args).B.avdapply = 1U;              \
+	/* fall through */                      \
+	case BIAS_APPLY_APD:                      \
+		(dom) = (uint32_t)APD_DOMAIN;       \
+		(args).B.domapply = 1U;              \
+		break;                            \
+	case BIAS_APPLY_AVD:                      \
+		(args).B.avdapply = 1U;              \
+		break;                            \
+	default:                              \
+		break;                            \
+	}                                                 \
+	(args).B.dommode = (uint32_t)((bias)->dommode);         \
+	(args).B.avdmode = (uint32_t)((bias)->avdmode);         \
+	uint32_t sat = UPWR_BIAS2MILIV((1UL << UPWR_DOMBIAS_RBB_BITS) - 1UL);\
+	(args).B.domrbbn = ((bias)->dombias.rbbn > sat) ? sat : \
+			   UPWR_BIAS_MILIV((bias)->dombias.rbbn); \
+	(args).B.domrbbp = ((bias)->dombias.rbbp > sat) ? sat : \
+			   UPWR_BIAS_MILIV((bias)->dombias.rbbp); \
+	(args).B.avdrbbn = ((bias)->avdbias.rbbn > sat) ? sat : \
+			   UPWR_BIAS_MILIV((bias)->avdbias.rbbn); \
+	(args).B.avdrbbp = ((bias)->avdbias.rbbp > sat) ? sat : \
+			   UPWR_BIAS_MILIV((bias)->avdbias.rbbp); \
+} while (false)
+
+#define UPWR_FILL_MEMBIAS_ARGS(bias, args)		\
+do {							\
+	(args).B.en = (bias)->en;			\
+} while (false)
+
+
+#define UPWR_APD_CORES      (2U)
+#define UPWR_RTD_CORES      (1U)
+
+#define RTD_DOMAIN (0U)
+#define APD_DOMAIN (1U)
+#define UPWR_MAIN_DOMAINS (2U)
+#define AVD_DOMAIN (2U)
+#define UPWR_DOMAIN_COUNT (3U)
+#define PSD_DOMAIN (3U)
+#define UPWR_ALL_DOMAINS (4U)
+
+typedef uint32_t soc_domain_t;
+
+/*=========================================================================
+ * UNIT CONVERSION MACROS
+ *   These macros convert physical units to the values passed as arguments
+ *   in API functions.
+ *=========================================================================
+ */
+
+#define UPWR_VOLT_MILIV(v) (v)        /* voltage in mV    to argument value */
+#define UPWR_VOLT_MICROV(v)((v) / 1000U) /* voltage in uV    to argument value */
+#define UPWR_BIAS_MILIV(v) (((v) + 49UL) / 50UL)   /* bias voltage(mV) to argument value */
+#define UPWR_BIAS2MILIV(v) ((v) * 50UL)   /* inverse of UPWR_BIAS_MILIV         */
+#define UPWR_FREQ_KHZ(f)   (f)        /* frequency (kHz)  to argument value */
+
+#define UPWR_DOMBIAS_MAX_MV      (UPWR_BIAS2MILIV((1U << UPWR_DOMBIAS_RBB_BITS) - 1U))
+
+/**---------------------------------------------------------------
+ * EXCEPTION SERVICE GROUP
+ */
+
+/**+
+ * upwr_xcp_config()
+ *
+ * The i.MX8ULP uPower configuration struct contains the following bitfields:
+ *
+ *  - ALARM_INT (1 bit): tells which RTD MU interrupt should be used for alarms;
+ *    1= MU GPI1; 0= MU GPI0; APD alarms always use GPI0.
+ *  - CFG_IOMUX (1 bit): determintes if uPower configures i.MX8ULP IOMUX for
+ *    I2C and mode pins used to control an external PMIC;
+ *    1= uPower firmware or PMIC driver configures i.MX8ULP IOMUX and mode pins;
+ *    0= i.MX8ULP IOMUX and mode pins not configured by uPower;
+ *  - DGNBUFBITS (4 bits): determines the diagnostic buffer size according to
+ *    the formula: size = 2^(DGNBUFBITS+3) bytes;
+ *
+ *  Defaults are all zeroes; all other bits are reserved, and must be written 0.
+ */
+
+typedef union {
+	uint32_t R;
+	struct {
+		uint32_t ALARM_INT : 1U;
+		uint32_t CFG_IOMUX : 1U;
+		uint32_t DGNBUFBITS : 4U;
+		uint32_t RSV : 26U;
+	} B;
+} upwr_xcp_config_t;
+
+/**+
+ * upwr_xcp_sw_alarm()
+ *
+ * Argument code is defined by the enum upwr_alarm_t, with the values:
+ *  - UPWR_ALARM_INTERNAL: internal software error
+ *  - UPWR_ALARM_EXCEPTION: uPower core exception, either illegal instruction or
+ *    bus error
+ *  - UPWR_ALARM_SLACK: delay path too slow, meaning a timing violation occurred
+ *    or is iminent.
+ *  - UPWR_ALARM_VOLTAGE: one of the measured voltages is below safety margins.
+ *
+ * Note that this service emulates an alarm that would normally be issued by
+ * uPower when it detects one of the causes above. A request to alarm the APD
+ * domain when it is powered off returns success, but is ineffective.
+ *
+ */
+
+#define	UPWR_ALARM_INTERNAL   (0U) /* internal error */
+#define	UPWR_ALARM_EXCEPTION  (1U) /* core exception */
+#define	UPWR_ALARM_SLACK      (2U) /* delay path too slow */
+#define	UPWR_ALARM_VOLTAGE    (3U) /* voltage drop */
+#define	UPWR_ALARM_LAST       UPWR_ALARM_VOLTAGE
+
+typedef uint32_t upwr_alarm_t;
+
+/**---------------------------------------------------------------
+ * POWER MANAGEMENT SERVICE GROUP
+ */
+
+/* values in mV: */
+#define UPWR_RTD_RBBN_MAX     (1300U) /* max. RTD Reverse Back Bias N-Well */
+#define UPWR_RTD_RBBN_MIN      (100U) /* min. RTD Reverse Back Bias N-Well */
+
+#define UPWR_RTD_RBBP_MAX     (1300U) /* max. RTD Reverse Back Bias P-Well */
+#define UPWR_RTD_RBBP_MIN      (100U) /* min. RTD Reverse Back Bias P-Well */
+
+/* APD bias can only two values (mV): */
+#define UPWR_APD_RBBN_LO      (1000U) /* low  APD Reverse Back Bias N-Well */
+#define UPWR_APD_RBBN_HI      (1300U) /* high APD Reverse Back Bias N-Well */
+
+#define UPWR_APD_RBBP_LO      (1000U) /* low  APD Reverse Back Bias P-Well */
+#define UPWR_APD_RBBP_HI      (1300U) /* high APD Reverse Back Bias P-Well */
+
+/* AVD bias can only two values (mV): */
+#define UPWR_AVD_RBBN_LO      (1000U) /* low  AVD Reverse Back Bias N-Well */
+#define UPWR_AVD_RBBN_HI      (1300U) /* high AVD Reverse Back Bias N-Well */
+
+#define UPWR_AVD_RBBP_LO      (1000U) /* low  AVD Reverse Back Bias P-Well */
+#define UPWR_AVD_RBBP_HI      (1300U) /* high AVD Reverse Back Bias P-Well */
+
+/**+
+ * upwr_pwm_param()
+ *
+ * Argument param is defined by the struct/union upwr_pwm_param_t with the
+ * following i.MX8ULP-specific bitfields:
+ * - DPD_ALLOW (1 bit): 1= allows uPower power mode to go Deep Power Down (DPD);
+ *   uPower DPD also depends on other conditions, but if this bit is 0 uPower
+ *   won't go DPD even if those conditions are met; it can go either Sleep or
+ *   Deep Sleep (DSL) depending on the other configurations.
+ * - DSL_DIS (1 bit): if this bit is 1, uPower power mode won't go Deep Sleep
+ *   (DSL) even if the other conditions for that are met;
+ *   it may go Sleep instead.
+ * - SLP_ALLOW (1 bit): if this bit is 1, uPower power mode will go Sleep if
+ *   the conditions for Partial Active are met; it may also go Deep Sleep if bit
+ *   DSL_DIS=1.
+ * - DSL_BGAP_OFF (1 bit): 1= turns bandgap off when uPower goes Deep Sleep;
+ *   0= leaves bandgap on when uPower goes Deep Sleep (DSL).
+ * - DPD_BGAP_ON (1 bit): 1= leaves bandgap on when uPower goes Deep Power Down
+ *   (DPD); 0= powers off bandgap when uPower goes Deep Power Down (DPD).
+ *
+ *  Defaults are all zeroes; all other bits are reserved, and must be written 0.
+ */
+
+typedef union {
+	uint32_t R;
+	struct {
+		uint32_t DPD_ALLOW : 1U;
+		uint32_t DSL_DIS : 1U;
+		uint32_t SLP_ALLOW : 1U;
+		uint32_t DSL_BGAP_OFF : 1U;
+		uint32_t DPD_BGAP_ON : 1U;
+		uint32_t RSV : 27U;
+	} B;
+} upwr_pwm_param_t;
+
+/**+
+ * upwr_pwm_chng_reg_voltage()
+ *
+ * Argument reg is defined by the enum upwr_pmc_reg_t, with regulator ids:
+ *  - RTD_PMC_REG: RTD regulator
+ *  - APD_PMC_REG: APD regulator
+ *  - RTD_BIAS_PMC_REG: RTD bias regulator
+ *  - APD_BIAS_PMC_REG: APD bias regulator
+ *  - RTD_LVD_PMC_MON: RTD LVD regulator
+ *  - APD_LVD_PMC_MON: APD LVD regulator
+ *  - AVD_LVD_PMC_MON: AVD LVD regulator
+ *
+ * Argument volt is defined by the formula:
+ *
+ * argument = 92.30797633*V - 55.000138, rounded to the nearest integer,
+ * where V is the value in Volts, with a minimum of 0.595833 V (argument = 0).
+ *
+ */
+
+/* Regulator ids */
+typedef enum {
+	RTD_PMC_REG,
+	APD_PMC_REG,
+	RTD_BIAS_PMC_REG,
+	APD_BIAS_PMC_REG,
+	RTD_LVD_PMC_MON,
+	APD_LVD_PMC_MON,
+	AVD_LVD_PMC_MON
+} upwr_pmc_reg_t;
+
+/**+
+ * upwr_pwm_freq_setup()
+ *
+ * Argument domain is either RTD_DOMAIN or APD_DOMAIN.
+ * Arguments nextfq and currfq are to be defined (TBD).
+ */
+
+/**+
+ * upwr_pwm_dom_power_on()
+ *
+ * The arguments must comply with the restrictions below, otherwise the service
+ * is not executed and returns error UPWR_RESP_BAD_REQ:
+ * - argument domain can only be APD_DOMAIN, because in i.MX8ULP it is not
+ *   possible APD powered on (calling the service) with RTD completely
+ *   powered off.
+ * - the call can only be made from the RTD domain, for the same reason.
+ * - argument boot can only be 1, because in i.MX8ULP it is not possible to
+ *   power on the APD domain without starting the core boot.
+ *
+ * If APD is already powered on and booting/booted when the service is called,
+ * it returns success without doing anything.
+ */
+
+/**+
+ * upwr_pwm_boot_start()
+ *
+ * The arguments must comply with the restrictions below, otherwise the service
+ * is not executed and returns error UPWR_RESP_BAD_REQ:
+ * - argument domain can only be APD_DOMAIN, because in i.MX8ULP it is not
+ *   possible APD powered on (calling the service) with RTD completely
+ *   powered off.
+ * - the call can only be made from the RTD domain, for the same reason.
+ *
+ * If APD is already booted when the service is called, it returns success
+ * without doing anything. Otherwise, it returns the error UPWR_RESP_BAD_STATE,
+ * because in i.MX8ULP APD cannot be booted separately from power on.
+ */
+
+/**+
+ * upwr_pwm_power_on(),
+ * upwr_pwm_power_off(),
+ * upwr_pwm_mem_retain()
+ *
+ * These three service functions use the same arguments:
+ *
+ * argument swt is an array of one 32-bit word: uint32_t swt[1];
+ * naturally the pointer to a single uint32_t variable may be passed.
+ * Each bit of the word corresponds to a switch, according to the i.MX8ULP
+ * Reference Manual Rev B draft 2 table 64 Power switch reset state,
+ * and the following formula:
+ *
+ * if switch number < 10 bit number = switch number;
+ * if switch number >  9 bit number = switch number + 3;
+ *
+ * bits 9, 10, 11 and 12 must have the same value (corresponding to switch 9)
+ *
+ * Note: this argument is not used in upwr_pwm_mem_retain.
+ *
+ * argument mem is an array of two 32-bit words: uint32_t mem[2];
+ * naturally the pointer to a single uint64_t variable may be passed, since
+ * both ARM and RISC-V are little endian architectures.
+ * Each bit of the words corresponds to a memory, according to the i.MX8ULP
+ * Reference Manual table "Memory Partitions".
+ *
+ * Turning a memory completely on (array and peripheral) will automatically
+ * turn on its power switch, even if not explicitly commanded.
+ * Turning a memory's power switch off will automatically turn off its array
+ * and peripheral beforehand, even if not explicitly commanded.
+ *
+ * Argument restrictions:
+ *
+ * The swt and mem arguments must comply with the restrictions below, otherwise
+ * the service is not executed (no switch/memory is changed) and returns error
+ * UPWR_RESP_BAD_REQ:
+ *  1. one must not put a memory in retention coming from an off state.
+ *  2. switches 9, 10, 11 and 12 must be turned on/off simultaneously.
+ *  3. an AVD switch can only be turned off if all AVD switches belong to the
+ *     domain requesting the service (as defined by registers SYSCTRL0,
+ *     LPAV_MASTER_ALLOC_CTRL and LPAV_SLAVE_ALLOC_CTRL);
+ *     there is no such restriction to turn the switch on.
+ *  4. an AVD memory can only be turned off or put in retention if all
+ *     AVD memories belong to the domain requesting the service
+ *     (as defined by registers SYSCTRL0, LPAV_MASTER_ALLOC_CTRL and
+ *      LPAV_SLAVE_ALLOC_CTRL); there is no such restriction to turn on the
+ *     memories.
+ *  5. EdgeLock RAMs must not be turned off, unless RTD domain is in
+ *     Deep Power Down (DPD).
+ *  6. Power Switch 19 must be on to turn on switches 17 (MIPI/DSI),
+ *     18 (MIPI/CSI), and all AVD power switches.
+ *
+ * Service Errors:
+ *
+ * Besides the error UPWR_RESP_BAD_REQ caused by violations of the restrictions
+ * above, the services may fail with error UPWR_RESP_RESOURCE if a power mode
+ * transition or a similar service is executing at the same time.
+ * This error should be interpreted as a "try later" response, as the service
+ * will succeed once those concurrent executions are done, and no other is
+ * started.
+ */
+
+/**+
+ * upwr_pwm_chng_switch_mem()
+ *
+ * The bit numbers in the argument struct mask and on/off state fields
+ * are the same as for services upwr_pwm_power_on, upwr_pwm_power_off and
+ * upwr_pwm_mem_retain.
+ *
+ * Turning a memory completely on (array and peripheral) will automatically
+ * turn on its power switch, even if not explicitly commanded.
+ *
+ * Argument restrictions:
+ *
+ * Same argument restrictions as services upwr_pwm_power_on, upwr_pwm_power_off
+ * and upwr_pwm_mem_retain, plus the following:
+ *
+ *  1. one must not turn a memory peripheral on and a memory array off.
+ *  2. one must not put a memory in retention and switch its power switch off.
+ *
+ * Service Errors:
+ *
+ * Besides the error UPWR_RESP_BAD_REQ caused by violations of the restrictions
+ * above, the service may fail with error UPWR_RESP_RESOURCE if a power mode
+ * transition or a similar service is executing at the same time.
+ * This error should be interpreted as a "try later" response, as the service
+ * will succeed once those concurrent executions are done, and no other is
+ * started.
+ */
+
+/**+
+ * upwr_pwm_pmode_config()
+ *
+ * The same power switch and memory restrictions of service
+ * upwr_pwm_chng_switch_mem apply between power modes, however they are not
+ * enforced by this service, that is, it does not return service error.
+ *
+ * The default power mode configurations for RTD and APD are documented in the
+ * i.MX8ULP Reference Manual sections "Power mode details (real-time domain)"
+ * and "Power mode details (application domain)", respectively.
+ * If those configurations are satisfactory, this service does not have
+ * to be called.
+ *
+ * Power Mode Configuration Structure:
+ *
+ * Follows a description of the power mode configuration structure elements.
+ * - dom_swts: the same switch configuration structures used in service
+ *             upwr_pwm_chng_switch_mem argument swt.
+ * - mem_swts: the same memory configuration structures used in service
+ *             upwr_pwm_chng_switch_mem argument mem.
+ * - regs: an array of structs base_reg_cfg_t (see upower_soc_defs.h),
+ *         one element for each regulator; base_reg_cfg_t has fields
+ *         mode (regulator-dependent), lvl (voltage level in uV),
+ *         comp (regulator-dependent complamentary info).
+ * - pads: pad configuration in low power; see pad_cfg_t definition below.
+ * - mons: domain monitors (LVD and HVD) configuration;
+ *         see mon_cfg_t definition below.
+ * - avd_mons: same as mons for the AVD domain; see mon_cfg_t definition below.
+ * - dom_bbias: back-bias configuration for the domain;
+ *              see base_bbias_cfg_t definition below.
+ * - avd_bbias: back-bias configuration for the AVD domain;
+ *              see base_bbias_cfg_t definition below.
+ * - mem_bbias: back-bias configuration for the memory;
+ *              see base_bbias_cfg_t definition below.
+ * - mem_fbias: forward-bias configuration for the memory;
+ *              see base_fbias_cfg_t definition below.
+ * - pmic: PMIC-specific configuration
+ *
+ * Structure pad_cfg_t:
+ *
+ * Pad control for low power modes (power off, etc), 1 bit per pad segment.
+ * - rst  : put pad segment in reset.
+ * - iso  : put pad segment in isolation.
+ * - compl: specific pad segment information.
+ * - msk  : select which pads will be updated.
+ *
+ * Structure mon_cfg_t:
+ *
+ * Configures a voltage monitor and its actions.
+ * There are monitors for RTD, APD and AVD, monitoring LVD and HVD.
+ * - lvl  : Voltage level (in uV).
+ * - mode : Mode of monitor (ON, OFF, LP, etc).
+ * - compl: Extra info for the monitor.
+ *
+ * Structure base_bbias_cfg_t:
+ *
+ * Configures back-bias (for domain or memory).
+ * - mode : Back bias mode (OFF, RBB, ARBB, etc).
+ * - p_lvl: Voltage level of p-well (in mV).
+ * - n_lvl: Voltage level of n-well (in mV).
+ * - compl: Complementary bias-specific (enable reset, interrupt, clamp, etc).
+ *
+ * Structure base_fbias_cfg_t:
+ *
+ * Configure memory forward bias for a memory segment.
+ *
+ * - mode : Forward bias mode (OFF, ON).
+ * - msk  : Selects which memory will be updated
+ *
+ */
+
+/*=========================================================================
+ * Domain bias
+ *=========================================================================
+ */
+
+/**+
+ * upwr_pwm_chng_dom_bias()
+ *
+ * Argument bias is a pointer to a struct with fields:
+ *  - apply: tells to which domains the bias must be applied;
+ *    options are RTD only (BIAS_APPLY_RTD), RTD and AVD (BIAS_APPLY_RTD_AVD),
+ *    APD only (BIAS_APPLY_APD), APD and AVD (BIAS_APPLY_APD_AVD),
+ *    AVD only (BIAS_APPLY_AVD)
+ *  - dommode: bias mode of the main domain (RTD or APD, determined by apply);
+ *    options are disabled (NBB_BIAS_MODE), reverse back bias (RBB_BIAS_MODE),
+ *    asymmetrical forward bias (AFBB_BIAS_MODE), asymmetrical reverse bias
+ *    (ARBB_BIAS_MODE).
+ *  - avdmode: bias mode of Audio-Video Domain (AVD);
+ *    options are the same as dommode.
+ *  - dombias: bias voltage level(s) for the main domain (RTD or APD,
+ *    determined by apply); it is a structure with 2 fields, rbbn and rbbp,
+ *    for the N-well and P-well voltages, respectively; values are in mV.
+ *  - avdbias: bias voltage level(s) for the Audio-Video Domain (AVD);
+ *    same fields as dombias;
+ *
+ * Argument restrictions:
+ *
+ * Voltage levels must comply with the #define-determined limits/options:
+ * between UPWR_RTD_RBBN_MIN and UPWR_RTD_RBBN_MAX (inclusive) for RTD N-well;
+ * between UPWR_RTD_RBBP_MIN and UPWR_RTD_RBBP_MAX (inclusive) for RTD P-well;
+ * either UPWR_APD_RBBN_LO or UPWR_APD_RBBN_HI for APD N-well;
+ * either UPWR_APD_RBBP_LO or UPWR_APD_RBBP_HI for APD P-well;
+ * either UPWR_AVD_RBBN_LO or UPWR_AVD_RBBN_HI for AVD N-well;
+ * either UPWR_AVD_RBBP_LO or UPWR_AVD_RBBP_HI for AVD P-well;
+ *
+ * But note that the limits/options above do not apply to all bias modes:
+ * rbbn is used and checked only in mode RBB_BIAS_MODE;
+ * rbbp is used and checked only in modes RBB_BIAS_MODE and ARBB_BIAS_MODE;
+ * modes AFBB_BIAS_MODE and NBB_BIAS_MODE use or check neither rbbn nor rbbp;
+ *
+ * Service error UPWR_RESP_BAD_REQ is returned if the voltage limits/options
+ * above are violated.
+ */
+
+/* argument struct for service upwr_pwm_chng_dom_bias:
+ */
+
+typedef enum {               /* bias modes (both domain and memory): */
+	NBB_BIAS_MODE  = 0,  /* bias disabled */
+	RBB_BIAS_MODE  = 1,  /* reverse back bias enabled */
+	AFBB_BIAS_MODE = 2,  /* asymmetrical forward bias */
+	ARBB_BIAS_MODE = 3   /* asymmetrical reverse bias */
+} upwr_bias_mode_t;
+
+/* Domain Bias config (one per domain) */
+
+typedef enum {
+	BIAS_APPLY_RTD,      /* apply to RTD only    */
+	BIAS_APPLY_RTD_AVD,  /* apply to RTD and AVD */
+	BIAS_APPLY_APD,      /* apply to APD only    */
+	BIAS_APPLY_APD_AVD,  /* apply to APD and AVD */
+	BIAS_APPLY_AVD,      /* apply to AVD only    */
+	BIAS_APPLY_COUNT     /* number of apply options */
+} upwr_bias_apply_t;
+
+typedef struct {
+	uint16_t rbbn;    /* reverse back bias N well (mV) */
+	uint16_t rbbp;    /* reverse back bias P well (mV) */
+} upwr_rbb_t;
+
+struct upwr_dom_bias_cfg_t {
+	upwr_bias_apply_t apply;   /* bias application option  */
+	upwr_bias_mode_t  dommode; /* RTD/APD bias mode config */
+	upwr_bias_mode_t  avdmode; /* AVD     bias mode config */
+	upwr_rbb_t        dombias; /* RTD/APD reverse back bias */
+	upwr_rbb_t        avdbias; /* AVD     reverse back bias */
+};
+
+/* bias struct used in power mode config definitions */
+
+/**
+ * When write power mode transition program, please read below comments carefully.
+ * The structure and logic is complex, There is a lot of extension and reuse.
+ *
+ * First, for mode, extend "uint32_t mode" to a union struct, add support for AVD:
+ * typedef union {
+ *    uint32_t R;
+ *    struct {
+ *        uint32_t mode : 8;
+ *        uint32_t rsrv_1 : 8;
+ *        uint32_t avd_mode : 8;
+ *        uint32_t rsrv_2 : 8;
+ *    } B;
+ * } dom_bias_mode_cfg_t;
+
+  Second, if mode is AFBB mode, no need to configure rbbn and rbbp, uPower firmware
+  will configure all SRAM_AFBB_0 or SRAM_AFBB_1 for corresponding domain.
+
+  Third, if mode is RBB mode, extend "uint32_t rbbn" and "uint32_t rbbp" to a union
+  struct, add support for AVD:
+  typedef union {
+  uint32_t                  R;
+  struct {
+    uint32_t                  lvl       : 8;
+    uint32_t                  rsrv_1    : 8;
+    uint32_t                  avd_lvl   : 8;
+    uint32_t                  rsrv_2    : 8;
+  }                         B;
+} dom_bias_lvl_cfg_t;
+
+ *
+ */
+typedef struct {
+	uint32_t mode; /* Domain bias mode config, extend to dom_bias_mode_cfg_t to support RTD, APD, AVD */
+	uint32_t rbbn; /* reverse back bias N well */
+	uint32_t rbbp; /* reverse back bias P well */
+} UPWR_DOM_BIAS_CFG_T;
+
+/*=========================================================================
+ * Memory bias
+ *=========================================================================
+ */
+/**+
+ * upwr_pwm_chng_mem_bias()
+ *
+ * Argument struct contains only the field en, which can be either 1 (bias
+ * enabled) or 0 (bias disabled).
+ *
+ * Argument domain must be either RTD_DOMAIN (Real Time Domain) or APD_DOMAIN
+ * (Application Domain).
+ */
+
+/* Memory Bias config */
+struct upwr_mem_bias_cfg_t {
+	uint32_t en; /* Memory bias enable config */
+};
+
+/* bias struct used in power mode config definitions */
+typedef struct {
+	uint32_t en; /* Memory bias enable config */
+} UPWR_MEM_BIAS_CFG_T;
+
+/* Split different Bias */
+struct upwr_pmc_bias_cfg_t {
+	UPWR_DOM_BIAS_CFG_T dombias_cfg; /* Domain Bias config */
+	UPWR_MEM_BIAS_CFG_T membias_cfg; /* Memory Bias config */
+};
+
+/*=========================================================================
+ * Power modes
+ *=========================================================================
+ */
+
+/* from msb->lsb: Azure bit, dual boot bit, low power boot bit */
+typedef enum {
+	SOC_BOOT_SINGLE   = 0,
+	SOC_BOOT_LOW_PWR  = 1,
+	SOC_BOOT_DUAL     = 2,
+	SOC_BOOT_AZURE    = 4
+} SOC_BOOT_TYPE_T;
+
+#ifdef UPWR_COMP_RAM
+/* Power modes for RTD domain  */
+typedef enum {
+	DPD_RTD_PWR_MODE, /* Real Time Deep Power Down mode */
+	PD_RTD_PWR_MODE,  /* Real Time Power Down mode */
+	DSL_RTD_PWR_MODE, /* Real Time Domain Deep Sleep Mode */
+	HLD_RTD_PWR_MODE, /* Real Time Domain Hold Mode */
+	SLP_RTD_PWR_MODE, /* Sleep Mode */
+	ADMA_RTD_PWR_MODE,/* Active DMA Mode */
+	ACT_RTD_PWR_MODE, /* Active Domain Mode */
+	NUM_RTD_PWR_MODES
+} upwr_ps_rtd_pwr_mode_t;
+
+/* Abstract power modes */
+typedef enum {
+	DPD_PWR_MODE,
+	PD_PWR_MODE,
+	PACT_PWR_MODE,
+	DSL_PWR_MODE,
+	HLD_PWR_MODE,
+	SLP_PWR_MODE,
+	ADMA_PWR_MODE,
+	ACT_PWR_MODE,
+	NUM_PWR_MODES,
+	NUM_APD_PWR_MODES = NUM_PWR_MODES,
+	TRANS_PWR_MODE    = NUM_PWR_MODES,
+	INVALID_PWR_MODE  = TRANS_PWR_MODE + 1
+} abs_pwr_mode_t;
+#else /* UPWR_COMP_RAM */
+/* Power modes for RTD domain  */
+#define	DPD_RTD_PWR_MODE   (0U)  /* Real Time Deep Power Down mode */
+#define	PD_RTD_PWR_MODE    (1U)  /* Real Time Power Down mode */
+#define	DSL_RTD_PWR_MODE   (2U)  /* Real Time Domain Deep Sleep Mode */
+#define	HLD_RTD_PWR_MODE   (3U)  /* Real Time Domain Hold Mode */
+#define	SLP_RTD_PWR_MODE   (4U)  /* Sleep Mode */
+#define	ADMA_RTD_PWR_MODE  (5U)  /* Active DMA Mode */
+#define	ACT_RTD_PWR_MODE   (6U)  /* Active Domain Mode */
+#define	NUM_RTD_PWR_MODES  (7U)
+
+typedef uint32_t upwr_ps_rtd_pwr_mode_t;
+
+/* Abstract power modes */
+#define	DPD_PWR_MODE       (0U)
+#define	PD_PWR_MODE        (1U)
+#define	PACT_PWR_MODE      (2U)
+#define	DSL_PWR_MODE       (3U)
+#define	HLD_PWR_MODE       (4U)
+#define	SLP_PWR_MODE       (5U)
+#define	ADMA_PWR_MODE      (6U)
+#define	ACT_PWR_MODE       (7U)
+#define	NUM_PWR_MODES      (8U)
+#define	NUM_APD_PWR_MODES NUM_PWR_MODES
+#define	TRANS_PWR_MODE    NUM_PWR_MODES
+#define	INVALID_PWR_MODE  (TRANS_PWR_MODE + 1U)
+
+typedef uint32_t abs_pwr_mode_t;
+#endif /* UPWR_COMP_RAM */
+
+typedef struct {
+	abs_pwr_mode_t mode;
+	bool ok;
+} pch_trans_t;
+
+typedef pch_trans_t rtd_trans_t;
+
+typedef struct {
+	abs_pwr_mode_t mode;
+	pch_trans_t core[UPWR_APD_CORES];
+} apd_trans_t;
+
+/* Codes for APD pwr mode as programmed in LPMODE reg */
+typedef enum {
+	ACT_APD_LPM,
+	SLP_APD_LPM = 1,
+	DSL_APD_LPM = 3,
+	PACT_APD_LPM = 7,
+	PD_APD_LPM = 15,
+	DPD_APD_LPM = 31,
+	HLD_APD_LPM = 63
+} upwr_apd_lpm_t;
+
+/* PowerSys low power config */
+struct upwr_powersys_cfg_t {
+	uint32_t lpm_mode; /* Powersys low power mode */
+};
+
+/*=*************************************************************************
+ * RTD
+ *=*************************************************************************/
+/* Config pmc PADs */
+struct upwr_pmc_pad_cfg_t {
+	uint32_t pad_close;   /* PMC PAD close config */
+	uint32_t pad_reset;   /* PMC PAD reset config */
+	uint32_t pad_tqsleep; /* PMC PAD TQ Sleep config */
+};
+
+/* Config regulator (internal and external) */
+struct upwr_reg_cfg_t {
+	uint32_t volt;  /* Regulator voltage config */
+	uint32_t mode;  /* Regulator mode config */
+};
+
+/* Config pmc monitors */
+struct  upwr_pmc_mon_cfg_t {
+	uint32_t mon_hvd_en; /* PMC mon HVD */
+	uint32_t mon_lvd_en; /* PMC mon LVD */
+	uint32_t mon_lvdlvl; /* PMC mon LVDLVL */
+};
+
+/* Same monitor config for RTD (for compatibility) */
+#define upwr_pmc_mon_rtd_cfg_t upwr_pmc_mon_cfg_t
+
+typedef swt_config_t ps_rtd_swt_cfgs_t[NUM_RTD_PWR_MODES];
+typedef swt_config_t ps_apd_swt_cfgs_t[NUM_APD_PWR_MODES];
+
+/*=*************************************************************************
+ * APD
+ *=*************************************************************************/
+
+/* PowerSys PMIC config */
+struct upwr_pmic_cfg_t {
+	uint32_t volt;
+	uint32_t mode;
+	uint32_t mode_msk;
+};
+
+typedef uint32_t offs_t;
+
+struct ps_apd_pwr_mode_cfg_t {
+	#ifdef UPWR_SIMULATOR_ONLY
+	struct upwr_switch_board_t *swt_board_offs;
+	struct upwr_mem_switches_t *swt_mem_offs;
+	#else
+	offs_t swt_board_offs;
+	offs_t swt_mem_offs;
+	#endif
+	struct upwr_pmic_cfg_t pmic_cfg;
+	struct upwr_pmc_pad_cfg_t pad_cfg;
+	struct upwr_pmc_bias_cfg_t bias_cfg;
+};
+
+/* Get the pointer to swt config */
+static inline struct upwr_switch_board_t*
+get_apd_swt_cfg(volatile struct ps_apd_pwr_mode_cfg_t *cfg)
+{
+	char *ptr;
+
+	ptr = (char *)cfg;
+	ptr += (uint64_t)cfg->swt_board_offs;
+	return (struct upwr_switch_board_t *)ptr;
+}
+
+/* Get the pointer to mem config */
+static inline struct upwr_mem_switches_t*
+get_apd_mem_cfg(volatile struct ps_apd_pwr_mode_cfg_t *cfg)
+{
+	char *ptr;
+
+	ptr = (char *)cfg;
+	ptr += (uint64_t)cfg->swt_mem_offs;
+	return (struct upwr_mem_switches_t *)ptr;
+}
+
+/* Power Mode configuration */
+
+#define ps_rtd_pwr_mode_cfg_t upwr_power_mode_cfg_t
+
+/* these typedefs are just for RISC-V sizeof purpose */
+typedef uint32_t swt_board_ptr_t;
+typedef uint32_t swt_mem_ptr_t;
+
+struct upwr_power_mode_cfg_t {
+	#ifdef UPWR_SIMULATOR_ONLY
+	struct upwr_switch_board_t *swt_board; /* Swt board for mem. */
+	struct upwr_mem_switches_t *swt_mem;   /* Swt to mem. arrays, perif */
+	#else
+	#ifdef __LP64__
+	uint32_t swt_board;
+	uint32_t swt_mem;
+	#else
+	struct upwr_switch_board_t *swt_board; /* Swt board for mem. */
+	struct upwr_mem_switches_t *swt_mem;   /* Swt to mem. arrays, perif */
+	#endif
+	#endif
+	struct upwr_reg_cfg_t in_reg_cfg; /* internal regulator config*/
+	struct upwr_reg_cfg_t pmic_cfg;  /* external regulator - pmic*/
+	struct upwr_pmc_pad_cfg_t pad_cfg;  /* Pad conf for power trans*/
+	struct upwr_pmc_mon_rtd_cfg_t mon_cfg; /*monitor configuration */
+	struct upwr_pmc_bias_cfg_t bias_cfg; /* Memory/Domain Bias conf */
+	struct upwr_powersys_cfg_t pwrsys_lpm_cfg; /* pwrsys low power config*/
+};
+
+static inline unsigned int upwr_sizeof_pmode_cfg(uint32_t domain)
+{
+	switch (domain) {
+	case RTD_DOMAIN:
+		return sizeof(struct upwr_power_mode_cfg_t) +
+					(sizeof(struct upwr_switch_board_t)*
+					 UPWR_PMC_SWT_WORDS) +
+					(sizeof(struct upwr_mem_switches_t)*
+					 UPWR_PMC_MEM_WORDS) -
+					2U * (sizeof(void *) - sizeof(swt_board_ptr_t));
+
+		/* fall through */
+	case APD_DOMAIN:
+		return sizeof(struct ps_apd_pwr_mode_cfg_t) +
+					(sizeof(struct upwr_switch_board_t)*
+					 UPWR_PMC_SWT_WORDS) +
+					(sizeof(struct upwr_mem_switches_t)*
+					 UPWR_PMC_MEM_WORDS);
+
+		/* fall through */
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*=*************************************************************************
+ * All configs
+ *=*************************************************************************/
+
+/* LVD/HVD monitor config for a single domain */
+
+/* Domain + AVD monitor config
+ * For RTD, mapped in mon_cfg.mon_hvd_en
+ * For APD, mapped temporarily in pad_cfg.pad_tqsleep
+ */
+typedef union upwr_mon_cfg_union_t {
+	volatile uint32_t R;
+	struct {
+		/* Original config, not change */
+		volatile uint32_t rsrv_1          : 8;
+		/* DOM */
+		volatile uint32_t dom_lvd_irq_ena : 1;
+		volatile uint32_t dom_lvd_rst_ena : 1;
+		volatile uint32_t dom_hvd_irq_ena : 1;
+		volatile uint32_t dom_hvd_rst_ena : 1;
+		volatile uint32_t dom_lvd_lvl     : 4;
+		volatile uint32_t dom_lvd_ena     : 1;
+		volatile uint32_t dom_hvd_ena     : 1;
+		/* AVD */
+		volatile uint32_t avd_lvd_irq_ena : 1;
+		volatile uint32_t avd_lvd_rst_ena : 1;
+		volatile uint32_t avd_hvd_irq_ena : 1;
+		volatile uint32_t avd_hvd_rst_ena : 1;
+		volatile uint32_t avd_lvd_lvl     : 4;
+		volatile uint32_t avd_lvd_ena     : 1;
+		volatile uint32_t avd_hvd_ena     : 1;
+	}                         B;
+} upwr_mon_cfg_t;
+
+/* Get the monitor config word from RAM (domaind and AVD) */
+static inline uint32_t get_mon_cfg(uint8_t dom, void *mode_cfg)
+{
+	if (dom == RTD_DOMAIN) {
+		return ((struct ps_rtd_pwr_mode_cfg_t *)mode_cfg)->mon_cfg.mon_hvd_en;
+	} else {
+		return ((struct ps_apd_pwr_mode_cfg_t *)mode_cfg)->pad_cfg.pad_tqsleep;
+	}
+}
+
+/* Set the monitor config word in RAM (domaind and AVD) */
+static inline void set_mon_cfg(uint8_t dom, void *mode_cfg,
+				upwr_mon_cfg_t mon_cfg)
+{
+	uint32_t *cfg;
+
+	if (dom == RTD_DOMAIN) {
+		cfg = (uint32_t *)&((struct ps_rtd_pwr_mode_cfg_t *)mode_cfg)->mon_cfg.mon_hvd_en;
+	} else {
+		cfg = (uint32_t *)&((struct ps_apd_pwr_mode_cfg_t *)mode_cfg)->pad_cfg.pad_tqsleep;
+	}
+
+	*cfg = mon_cfg.R;
+}
+
+#define PMIC_REG_VALID_TAG 0xAAU
+
+/**
+ * limit the max pmic register->value count to 8
+ * each data cost 4 Bytes, totally 32 Bytes
+ */
+#define MAX_PMIC_REG_COUNT 0x8U
+
+/**
+ * the configuration structure for PMIC register setting
+ *
+ * @ tag: The TAG number to judge if the data is valid or not, valid tag is PMIC_REG_VALID_TAG
+ * @ power_mode : corresponding to each domain's power mode
+ * RTD refer to upwr_ps_rtd_pwr_mode_t
+ * APD refer to abs_pwr_mode_t
+ * @ i2c_addr : i2c address
+ * @ i2c_data : i2c data value
+ */
+struct ps_pmic_reg_data_cfg_t {
+	uint32_t tag : 8;
+	uint32_t power_mode : 8;
+	uint32_t i2c_addr : 8;
+	uint32_t i2c_data : 8;
+};
+
+/* Uniformize access to PMIC cfg for RTD and APD */
+
+typedef union {
+	struct upwr_reg_cfg_t RTD;
+	struct upwr_pmic_cfg_t APD;
+} pmic_cfg_t;
+
+/* Access to PMIC mode mask and AVD mode */
+
+typedef union {
+	uint32_t R;
+	struct {
+		uint8_t mode;     /* Domain PMIC mode */
+		uint8_t msk;      /* Domain PMIC mode mask */
+		uint8_t avd_mode; /* AVD PMIC mode */
+		uint8_t avd_msk;  /* AVD PMIC mode mask */
+	} B;
+} pmic_mode_cfg_t;
+
+/* Access RTD, APD and AVD modes and masks */
+static inline pmic_mode_cfg_t *get_pmic_mode_cfg(uint8_t dom, pmic_cfg_t *cfg)
+{
+	uint32_t *mode_cfg;
+
+	if (dom == RTD_DOMAIN) {
+		mode_cfg = &cfg->RTD.mode;
+	} else {
+		mode_cfg = &cfg->APD.mode;
+	}
+
+	return (pmic_mode_cfg_t *)mode_cfg;
+}
+
+static inline uint8_t get_pmic_mode(uint8_t dom, pmic_cfg_t *cfg)
+{
+	return get_pmic_mode_cfg(dom, cfg)->B.mode;
+}
+
+static inline void set_pmic_mode(uint8_t dom, pmic_cfg_t *cfg, uint8_t mode)
+{
+	get_pmic_mode_cfg(dom, cfg)->B.mode = mode;
+}
+
+static inline uint32_t get_pmic_mode_msk(uint8_t dom, pmic_cfg_t *cfg)
+{
+	pmic_mode_cfg_t   *mode_cfg;
+
+	if (dom == RTD_DOMAIN) {
+		mode_cfg = (pmic_mode_cfg_t *)&cfg->RTD.mode;
+		return mode_cfg->B.msk;
+	} else {
+		return cfg->APD.mode_msk;
+	}
+}
+
+/* Getters and setters for AVD mode and mask */
+static inline uint8_t get_avd_pmic_mode(uint8_t dom, pmic_cfg_t *cfg)
+{
+	return get_pmic_mode_cfg(dom, cfg)->B.avd_mode;
+}
+
+static inline void set_avd_pmic_mode(uint8_t dom, pmic_cfg_t *cfg, uint8_t mode)
+{
+	get_pmic_mode_cfg(dom, cfg)->B.avd_mode = mode;
+}
+
+static inline uint8_t get_avd_pmic_mode_msk(uint8_t dom, pmic_cfg_t *cfg)
+{
+	return get_pmic_mode_cfg(dom, cfg)->B.avd_msk;
+}
+
+static inline void set_avd_pmic_mode_msk(uint8_t dom,
+					 pmic_cfg_t *cfg,
+					 uint8_t msk)
+{
+	get_pmic_mode_cfg(dom, cfg)->B.avd_msk = msk;
+}
+
+struct ps_delay_cfg_t {
+	uint32_t tag : 8U;
+	uint32_t rsv : 8U;
+	uint32_t exitdelay : 16U;   // exit delay in us
+};
+
+#define PS_DELAY_TAG 0xA5U
+
+/* max exit delay = 0xffff = 65535 us = 65.5 ms (it is enough...) */
+/* with 8 bits, 256 -> not enough */
+
+typedef struct ps_delay_cfg_t ps_rtd_delay_cfgs_t[NUM_RTD_PWR_MODES];
+typedef struct ps_delay_cfg_t ps_apd_delay_cfgs_t[NUM_APD_PWR_MODES];
+
+typedef struct ps_rtd_pwr_mode_cfg_t ps_rtd_pwr_mode_cfgs_t[NUM_RTD_PWR_MODES];
+typedef struct ps_apd_pwr_mode_cfg_t ps_apd_pwr_mode_cfgs_t[NUM_APD_PWR_MODES];
+typedef struct ps_pmic_reg_data_cfg_t ps_rtd_pmic_reg_data_cfgs_t[MAX_PMIC_REG_COUNT];
+typedef struct ps_pmic_reg_data_cfg_t ps_apd_pmic_reg_data_cfgs_t[MAX_PMIC_REG_COUNT];
+
+struct ps_pwr_mode_cfg_t {
+	ps_rtd_pwr_mode_cfgs_t  ps_rtd_pwr_mode_cfg;
+	ps_rtd_swt_cfgs_t       ps_rtd_swt_cfg;
+	ps_apd_pwr_mode_cfgs_t  ps_apd_pwr_mode_cfg;
+	ps_apd_swt_cfgs_t       ps_apd_swt_cfg;
+	ps_rtd_pmic_reg_data_cfgs_t ps_rtd_pmic_reg_data_cfg;
+	ps_apd_pmic_reg_data_cfgs_t ps_apd_pmic_reg_data_cfg;
+	ps_rtd_delay_cfgs_t    ps_rtd_delay_cfg;
+	ps_apd_delay_cfgs_t    ps_apd_delay_cfg;
+
+};
+
+#define UPWR_XCP_MIN_ADDR   (0x28350000U)
+#define UPWR_XCP_MAX_ADDR   (0x2836FFFCU)
+
+struct upwr_reg_access_t {
+	uint32_t addr;
+	uint32_t data;
+	uint32_t mask; /* mask=0 commands read */
+};
+
+typedef upwr_pointer_msg upwr_xcp_access_msg;
+
+/* unions for the shared memory buffer */
+
+typedef union {
+	struct upwr_reg_access_t reg_access;
+} upwr_xcp_union_t;
+
+typedef union {
+	struct {
+		struct ps_rtd_pwr_mode_cfg_t rtd_struct;
+		struct upwr_switch_board_t   rtd_switch;
+		struct upwr_mem_switches_t   rtd_memory;
+	} rtd_pwr_mode;
+	struct {
+		struct ps_apd_pwr_mode_cfg_t apd_struct;
+		struct upwr_switch_board_t   apd_switch;
+		struct upwr_mem_switches_t   apd_memory;
+	} apd_pwr_mode;
+} upwr_pwm_union_t;
+
+#define MAX_SG_EXCEPT_MEM_SIZE sizeof(upwr_xcp_union_t)
+#define MAX_SG_PWRMGMT_MEM_SIZE sizeof(upwr_pwm_union_t)
+
+/**
+ * VOLTM group need shared memory for PMIC IC configuration
+ * 256 Bytes is enough for PMIC register array
+ */
+#define MAX_SG_VOLTM_MEM_SIZE 256U
+
+#endif /* UPWR_SOC_DEFS_H */
diff --git a/plat/imx/imx8ulp/xrdc/xrdc_config.h b/plat/imx/imx8ulp/xrdc/xrdc_config.h
new file mode 100644
index 0000000..25edd37
--- /dev/null
+++ b/plat/imx/imx8ulp/xrdc/xrdc_config.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2020-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <xrdc.h>
+
+#define SP(X)		((X) << 9)
+#define SU(X)		((X) << 6)
+#define NP(X)		((X) << 3)
+#define NU(X)		((X) << 0)
+
+#define RWX		7
+#define RW		6
+#define R		4
+#define X		1
+
+struct xrdc_mda_config imx8ulp_mda[] = {
+	{ 0, 7, MDA_SA_PT }, /* A core */
+	{ 1, 1, MDA_SA_NS }, /* DMA1 */
+	{ 2, 1, MDA_SA_NS }, /* USB */
+	{ 3, 1, MDA_SA_NS }, /* PXP-> .M10 */
+	{ 4, 1, MDA_SA_NS }, /* ENET */
+	{ 5, 1, MDA_SA_PT }, /* CAAM */
+	{ 6, 1, MDA_SA_NS }, /* USDHC0 */
+	{ 7, 1, MDA_SA_NS }, /* USDHC1 */
+	{ 8, 1, MDA_SA_NS }, /* USDHC2 */
+	{ 9, 2, MDA_SA_NS }, /* HIFI4 */
+	{ 10, 3, MDA_SA_NS }, /* GPU3D */
+	{ 11, 3, MDA_SA_NS }, /* GPU2D */
+	{ 12, 3, MDA_SA_NS }, /* EPDC */
+	{ 13, 3, MDA_SA_NS }, /* DCNano */
+	{ 14, 3, MDA_SA_NS }, /* ISI */
+	{ 15, 3, MDA_SA_NS }, /* PXP->NIC_LPAV.M0 */
+	{ 16, 3, MDA_SA_NS }, /* DMA2 */
+};
+
+#ifdef SPD_opteed
+#define TEE_SHM_SIZE 0x400000
+#else
+#define TEE_SHM_SIZE 0x0
+#endif
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+#define DRAM_MEM_0_START (0x80000000)
+#define DRAM_MEM_0_SIZE (BL32_BASE - 0x80000000)
+
+#define DRAM_MEM_1_START (BL32_BASE)
+#define DRAM_MEM_1_SIZE (BL32_SIZE - TEE_SHM_SIZE)
+
+#ifndef SPD_trusty
+#define DRAM_MEM_2_START (DRAM_MEM_1_START + DRAM_MEM_1_SIZE)
+#define DRAM_MEM_2_SIZE (0x80000000 - DRAM_MEM_1_SIZE - DRAM_MEM_0_SIZE)
+#else
+#define SECURE_HEAP_START   (0xA9600000)
+#define SECURE_HEAP_SIZE    (0x6000000)
+#define DRAM_MEM_END        (0x100000000)
+
+#define DRAM_MEM_2_START (DRAM_MEM_1_START + DRAM_MEM_1_SIZE)
+#define DRAM_MEM_2_SIZE  (SECURE_HEAP_START - DRAM_MEM_2_START)
+#define DRAM_MEM_3_START (DRAM_MEM_2_START + DRAM_MEM_2_SIZE)
+#define DRAM_MEM_3_SIZE  (SECURE_HEAP_SIZE)
+#define DRAM_MEM_4_START (DRAM_MEM_3_START + DRAM_MEM_3_SIZE)
+#define DRAM_MEM_4_SIZE  (DRAM_MEM_END - DRAM_MEM_4_START)
+#endif
+#endif
+
+struct xrdc_mrc_config imx8ulp_mrc[] = {
+	{ 0, 0, 0x0,        0x30000,    {0, 0, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* ROM1 */
+	{ 1, 0, 0x60000000, 0x10000000, {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* Flexspi2 */
+	{ 2, 0, 0x22020000, 0x40000,    {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM2 */
+	{ 3, 0, 0x22010000, 0x10000,    {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM0 */
+#if defined(SPD_opteed) || defined(SPD_trusty)
+	{ 4, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
+	{ 4, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfc0, 0} }, /* TEE DRAM for A35, DMA1, USDHC0*/
+	{ 4, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
+#ifdef SPD_trusty
+	{ 4, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfc0, 0} }, /* DRAM for A35, DMA1, USDHC0*/
+	{ 4, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
+#endif
+
+	{ 5, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
+	{ 5, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfc0, 0} }, /* TEE DRAM for NIC_PER */
+	{ 5, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
+#ifdef SPD_trusty
+	{ 5, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfc0, 0} }, /* DRAM for NIC_PER */
+	{ 5, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
+#endif
+
+#ifdef SPD_trusty
+	{ 6, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
+	{ 6, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* TEE DRAM for LPAV and RTD*/
+	{ 6, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
+	{ 6, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* DRAM for LPAV and RTD*/
+	{ 6, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
+#else
+	{ 6, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
+	{ 6, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* TEE DRAM for LPAV and RTD*/
+	{ 6, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
+#endif
+#else
+	{ 4, 0, 0x80000000, 0x80000000, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
+	{ 5, 0, 0x80000000, 0x80000000, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
+	{ 6, 0, 0x80000000, 0x80000000, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
+#endif
+	{ 7, 0, 0x80000000, 0x10000000, {0, 0, 1, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for HIFI4 */
+	{ 7, 1, 0x90000000, 0x10000000, {0, 0, 1, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for HIFI4 */
+	{ 8, 0, 0x21000000, 0x10000,    {1, 1, 1, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM1 */
+	{ 9, 0, 0x1ffc0000, 0xc0000,    {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0} }, /* SSRAM for HIFI4 */
+	{ 10, 0, 0x1ffc0000, 0xc0000,   {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0} }, /* SSRAM for LPAV */
+	{ 11, 0, 0x21170000, 0x10000,   {0, 0, 1, 0, 0, 0, 0, 2}, {0xfff, SP(RW) | SU(RW) | NP(RW)} }, /* HIFI4 TCM */
+	{ 11, 1, 0x21180000, 0x10000,   {0, 0, 1, 0, 0, 0, 0, 2}, {SP(RW) | SU(RW) | NP(RW) | NU(RW), SP(RW) | SU(RW) | NP(RW)} }, /* HIFI4 TCM */
+	{ 12, 0, 0x2d400000, 0x100000,  {0, 0, 0, 0, 0, 0, 0, 1}, {SP(RW) | SU(RW) | NP(RW) | NU(RW), 0} }, /* GIC500 */
+};
+
+struct xrdc_pac_msc_config imx8ulp_pdac[] = {
+	{ 0, PAC_SLOT_ALL, {0, 7, 0, 0, 0, 0, 0, 7} }, /* PAC0 */
+	{ 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, 6, {0, 7, 7, 0, 0, 0, 0, 7} }, /* PAC1 slot 6 for LPUART6 */
+	{ 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 */
+	{ 2, PAC_SLOT_ALL, {7, 7, 7, 7, 0, 0, 7, 7} }, /* PAC2 */
+};
+
+struct xrdc_pac_msc_config imx8ulp_msc[] = {
+	{ 0, 0, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC0 GPIOE */
+	{ 0, 1, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC0 GPIOF */
+	{ 1, MSC_SLOT_ALL, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC1 GPIOD */
+	{ 2, MSC_SLOT_ALL, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC2 GPU3D/2D/DCNANO/DDR registers */
+};
diff --git a/plat/imx/imx8ulp/xrdc/xrdc_core.c b/plat/imx/imx8ulp/xrdc/xrdc_core.c
new file mode 100644
index 0000000..d022e4c
--- /dev/null
+++ b/plat/imx/imx8ulp/xrdc/xrdc_core.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2020-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "xrdc_config.h"
+
+#define XRDC_ADDR	0x292f0000
+#define MRC_OFFSET	0x2000
+#define MRC_STEP	0x200
+
+#define XRDC_MGR_PAC_ID	  U(0)
+#define XRDC_MGR_PAC_SLOT U(47)
+
+enum xrdc_comp_type {
+	MDA_TYPE = (1 << 16),
+	MRC_TYPE = (2 << 16),
+	PAC_TYPE = (3 << 16),
+	MSC_TYPE = (4 << 16),
+};
+
+enum xrdc_pd_type {
+	XRDC_AD_PD,
+	XRDC_HIFI_PD,
+	XRDC_AV_PD,
+};
+
+#define XRDC_TYPE_MASK (0x7 << 16)
+#define XRDC_ID_MASK 0xFFFF
+#define XRDC_ID(id) ((id) & XRDC_ID_MASK)
+
+typedef bool (*xrdc_check_func)(enum xrdc_comp_type type, uint16_t id);
+
+/* Access below XRDC needs enable PS 8
+ * and HIFI clocks and release HIFI firstly
+ */
+uint32_t hifi_xrdc_list[] = {
+	(MDA_TYPE | XRDC_ID(9)),
+	(MRC_TYPE | XRDC_ID(7)),
+	(MRC_TYPE | XRDC_ID(9)),
+	(MRC_TYPE | XRDC_ID(11)),
+};
+
+/* Access below XRDC needs enable PS 16 firstly */
+uint32_t av_periph_xrdc_list[] = {
+	(MDA_TYPE | XRDC_ID(10)),
+	(MDA_TYPE | XRDC_ID(11)),
+	(MDA_TYPE | XRDC_ID(12)),
+	(MDA_TYPE | XRDC_ID(13)),
+	(MDA_TYPE | XRDC_ID(14)),
+	(MDA_TYPE | XRDC_ID(15)),
+	(MDA_TYPE | XRDC_ID(16)),
+
+	(PAC_TYPE | XRDC_ID(2)),
+
+	(MRC_TYPE | XRDC_ID(6)),
+	(MRC_TYPE | XRDC_ID(8)),
+	(MRC_TYPE | XRDC_ID(10)),
+
+	(MSC_TYPE | XRDC_ID(1)),
+	(MSC_TYPE | XRDC_ID(2)),
+};
+
+uint32_t imx8ulp_pac_slots[] = {
+	61, 23, 53
+};
+
+uint32_t imx8ulp_msc_slots[] = {
+	2, 1, 7
+};
+
+static int xrdc_config_mrc_w0_w1(uint32_t mrc_con, uint32_t region, uint32_t w0, uint32_t size)
+{
+
+	uint32_t w0_addr, w1_addr;
+
+	w0_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20;
+	w1_addr = w0_addr + 4;
+
+	if ((size % 32) != 0) {
+		return -EINVAL;
+	}
+
+	mmio_write_32(w0_addr, w0 & ~0x1f);
+	mmio_write_32(w1_addr, w0 + size - 1);
+
+	return 0;
+}
+
+static int xrdc_config_mrc_w2(uint32_t mrc_con, uint32_t region, uint32_t dxsel_all)
+{
+	uint32_t w2_addr;
+
+	w2_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0x8;
+
+	mmio_write_32(w2_addr, dxsel_all);
+
+	return 0;
+}
+
+static int xrdc_config_mrc_w3_w4(uint32_t mrc_con, uint32_t region, uint32_t w3, uint32_t w4)
+{
+	uint32_t w3_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0xC;
+	uint32_t w4_addr = w3_addr + 4;
+
+	mmio_write_32(w3_addr, w3);
+	mmio_write_32(w4_addr, w4);
+
+	return 0;
+}
+
+static int xrdc_config_pac(uint32_t pac, uint32_t index, uint32_t dxacp)
+{
+	uint32_t w0_addr;
+	uint32_t val;
+
+	if (pac > 2U) {
+		return -EINVAL;
+	}
+
+	/* Skip the PAC slot for XRDC MGR, use Sentinel configuration */
+	if (pac == XRDC_MGR_PAC_ID && index == XRDC_MGR_PAC_SLOT) {
+		return 0;
+	}
+
+	w0_addr = XRDC_ADDR + 0x1000 + 0x400 * pac + 0x8 * index;
+
+	mmio_write_32(w0_addr, dxacp);
+
+	val = mmio_read_32(w0_addr + 4);
+	mmio_write_32(w0_addr + 4, val | BIT_32(31));
+
+	return 0;
+}
+
+static int xrdc_config_msc(uint32_t msc, uint32_t index, uint32_t dxacp)
+{
+	uint32_t w0_addr;
+	uint32_t val;
+
+	if (msc > 2) {
+		return -EINVAL;
+	}
+
+	w0_addr = XRDC_ADDR + 0x4000 + 0x400 * msc + 0x8 * index;
+
+	mmio_write_32(w0_addr, dxacp);
+
+	val = mmio_read_32(w0_addr + 4);
+	mmio_write_32(w0_addr + 4, val | BIT_32(31));
+
+	return 0;
+}
+
+static int xrdc_config_mda(uint32_t mda_con, uint32_t dom, enum xrdc_mda_sa sa)
+{
+	uint32_t w0_addr;
+	uint32_t val;
+
+	w0_addr = XRDC_ADDR + 0x800 + mda_con * 0x20;
+
+	val = mmio_read_32(w0_addr);
+
+	if (val & BIT_32(29)) {
+		mmio_write_32(w0_addr, (val & (~0xFF)) | dom |
+			      BIT_32(31) | 0x20 | ((sa & 0x3) << 6));
+	} else {
+		mmio_write_32(w0_addr, dom | BIT_32(31));
+		mmio_write_32(w0_addr + 0x4, dom | BIT_32(31));
+	}
+
+	return 0;
+}
+
+static bool xrdc_check_pd(enum xrdc_comp_type type,
+			  uint16_t id, enum xrdc_pd_type pd)
+{
+	unsigned int i, size;
+	uint32_t item = type | XRDC_ID(id);
+	uint32_t *list;
+
+	if (pd == XRDC_HIFI_PD) {
+		size = ARRAY_SIZE(hifi_xrdc_list);
+		list = hifi_xrdc_list;
+	} else if (pd == XRDC_AV_PD) {
+		size = ARRAY_SIZE(av_periph_xrdc_list);
+		list = av_periph_xrdc_list;
+	} else {
+		return false;
+	}
+
+	for (i = 0U; i < size; i++) {
+		if (item == list[i]) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static bool xrdc_check_lpav(enum xrdc_comp_type type, uint16_t id)
+{
+	return xrdc_check_pd(type, id, XRDC_AV_PD);
+}
+
+static bool xrdc_check_hifi(enum xrdc_comp_type type, uint16_t id)
+{
+	return xrdc_check_pd(type, id, XRDC_HIFI_PD);
+}
+
+static bool xrdc_check_ad(enum xrdc_comp_type type, uint16_t id)
+{
+	return (!xrdc_check_pd(type, id, XRDC_HIFI_PD) &&
+			!xrdc_check_pd(type, id, XRDC_AV_PD));
+}
+
+static int xrdc_apply_config(xrdc_check_func check_func)
+{
+	unsigned int i, j;
+	uint32_t val;
+
+	for (i = 0U; i < ARRAY_SIZE(imx8ulp_mda); i++) {
+		if (check_func(MDA_TYPE, imx8ulp_mda[i].mda_id)) {
+			xrdc_config_mda(imx8ulp_mda[i].mda_id,
+					imx8ulp_mda[i].did, imx8ulp_mda[i].sa);
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(imx8ulp_mrc); i++) {
+		if (check_func(MRC_TYPE, imx8ulp_mrc[i].mrc_id)) {
+			xrdc_config_mrc_w0_w1(imx8ulp_mrc[i].mrc_id,
+					      imx8ulp_mrc[i].region_id,
+					      imx8ulp_mrc[i].region_start,
+					      imx8ulp_mrc[i].region_size);
+
+			val = 0;
+			for (j = 0U; j < DID_MAX; j++) {
+				val |= imx8ulp_mrc[i].dsel[j] << (3 * j);
+			}
+
+			xrdc_config_mrc_w2(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id, val);
+			xrdc_config_mrc_w3_w4(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id,
+				0, imx8ulp_mrc[i].accset[0] | (imx8ulp_mrc[i].accset[1] << 16) | BIT_32(31));
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(imx8ulp_pdac); i++) {
+		if (check_func(PAC_TYPE, imx8ulp_pdac[i].pac_msc_id)) {
+			val = 0;
+			for (j = 0U; j < DID_MAX; j++) {
+				val |= imx8ulp_pdac[i].dsel[j] << (3 * j);
+			}
+
+			if (imx8ulp_pdac[i].slot_id == PAC_SLOT_ALL) {
+				/* Apply to all slots*/
+				for (j = 0U; j < imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]; j++) {
+					xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, j, val);
+				}
+			} else {
+				if (imx8ulp_pdac[i].slot_id >= imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]) {
+					return -EINVAL;
+				}
+
+				xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, imx8ulp_pdac[i].slot_id, val);
+			}
+		}
+	}
+
+	for (i = 0U; i < ARRAY_SIZE(imx8ulp_msc); i++) {
+		if (check_func(MSC_TYPE, imx8ulp_msc[i].pac_msc_id)) {
+			val = 0;
+			for (j = 0U; j < DID_MAX; j++) {
+				val |= imx8ulp_msc[i].dsel[j] << (3 * j);
+			}
+
+			if (imx8ulp_msc[i].slot_id == MSC_SLOT_ALL) {
+				/* Apply to all slots*/
+				for (j = 0U; j < imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]; j++) {
+					xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, j, val);
+				}
+			} else {
+				if (imx8ulp_msc[i].slot_id >= imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]) {
+					return -EINVAL;
+				}
+
+				xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, imx8ulp_msc[i].slot_id, val);
+			}
+		}
+	}
+
+	return 0;
+}
+
+int xrdc_apply_lpav_config(void)
+{
+	/* Configure PAC2 to allow to access PCC5 */
+	xrdc_config_pac(2, 39, 0xe00000);
+
+	/* Enable the eDMA2 MP clock for MDA16 access */
+	mmio_write_32(IMX_PCC5_BASE + 0x0, 0xc0000000);
+	return xrdc_apply_config(xrdc_check_lpav);
+}
+
+int xrdc_apply_hifi_config(void)
+{
+	return xrdc_apply_config(xrdc_check_hifi);
+}
+
+int xrdc_apply_apd_config(void)
+{
+	return xrdc_apply_config(xrdc_check_ad);
+}
+
+void xrdc_enable(void)
+{
+	mmio_write_32(XRDC_ADDR, BIT(14) | BIT(15) | BIT(0));
+}
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/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index eb88b12..a627ed7 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -199,8 +199,6 @@
 
 void bl31_plat_runtime_setup(void)
 {
-	console_switch_state(CONSOLE_FLAG_RUNTIME);
-
 #if TRANSFER_LIST
 	if (bl31_tl) {
 		/*
@@ -210,4 +208,7 @@
 		memcpy((void *)FW_NS_HANDOFF_BASE, bl31_tl, bl31_tl->max_size);
 	}
 #endif
+
+	console_flush();
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
 }
diff --git a/plat/qemu/qemu/qemu_measured_boot.c b/plat/qemu/qemu/qemu_measured_boot.c
index 077f7a4..76a4da1 100644
--- a/plat/qemu/qemu/qemu_measured_boot.c
+++ b/plat/qemu/qemu/qemu_measured_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  * Copyright (c) 2022-2023, Linaro.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
 #include <plat/common/common_def.h>
 #include <plat/common/platform.h>
 #include <tools_share/tbbr_oid.h>
@@ -20,16 +21,16 @@
 
 /* QEMU table with platform specific image IDs, names and PCRs */
 static const event_log_metadata_t qemu_event_log_metadata[] = {
-	{ BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
-	{ BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
-	{ BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
-	{ BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
-	{ BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
-	{ HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 },
-	{ NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 },
-	{ SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
-	{ SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
-	{ TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
+	{ BL31_IMAGE_ID, MBOOT_BL31_IMAGE_STRING, PCR_0 },
+	{ BL32_IMAGE_ID, MBOOT_BL32_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA1_IMAGE_ID, MBOOT_BL32_EXTRA1_IMAGE_STRING, PCR_0 },
+	{ BL32_EXTRA2_IMAGE_ID, MBOOT_BL32_EXTRA2_IMAGE_STRING, PCR_0 },
+	{ BL33_IMAGE_ID, MBOOT_BL33_IMAGE_STRING, PCR_0 },
+	{ HW_CONFIG_ID, MBOOT_HW_CONFIG_STRING, PCR_0 },
+	{ NT_FW_CONFIG_ID, MBOOT_NT_FW_CONFIG_STRING, PCR_0 },
+	{ SCP_BL2_IMAGE_ID, MBOOT_SCP_BL2_IMAGE_STRING, PCR_0 },
+	{ SOC_FW_CONFIG_ID, MBOOT_SOC_FW_CONFIG_STRING, PCR_0 },
+	{ TOS_FW_CONFIG_ID, MBOOT_TOS_FW_CONFIG_STRING, PCR_0 },
 
 	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
 };
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.S b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.S
new file mode 100644
index 0000000..26f3313
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* convoluted way to make sure that the define is pasted just the right way */
+.macro INCBIN file sym sec
+	.section \sec
+	.global \sym
+	.type \sym, @object
+	.align 4
+\sym :
+	.incbin \file
+	.size \sym , .-\sym
+	.global \sym\()_end
+\sym\()_end :
+.endm
+
+INCBIN ""RK3399M0FW"", "rk3399m0_bin", ".sram.incbin"
+INCBIN ""RK3399M0PMUFW"", "rk3399m0pmu_bin", ".pmusram.incbin"
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
deleted file mode 100644
index 25596b1..0000000
--- a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/* convoluted way to make sure that the define is pasted just the right way */
-#define INCBIN(file, sym, sec) \
-	__asm__( \
-		".section " sec "\n" \
-		".global " sym "\n" \
-		".type " sym ", %object\n" \
-		".align 4\n" \
-		sym ":\n" \
-		".incbin \"" file "\"\n" \
-		".size " sym ", .-" sym "\n" \
-		".global " sym "_end\n" \
-		sym "_end:\n" \
-	)
-
-INCBIN(RK3399M0FW, "rk3399m0_bin", ".sram.incbin");
-INCBIN(RK3399M0PMUFW, "rk3399m0pmu_bin", ".pmusram.incbin");
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index aba67c2..2394dce 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -61,7 +61,7 @@
 			${RK_PLAT_SOC}/plat_sip_calls.c			\
 			${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\
 			${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
-			${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c		\
+			${RK_PLAT_SOC}/drivers/pmu/pmu_fw.S		\
 			${RK_PLAT_SOC}/drivers/pmu/m0_ctl.c		\
 			${RK_PLAT_SOC}/drivers/pwm/pwm.c		\
 			${RK_PLAT_SOC}/drivers/secure/secure.c		\
@@ -102,7 +102,7 @@
 # CCACHE_EXTRAFILES is needed because ccache doesn't handle .incbin
 export CCACHE_EXTRAFILES
 ${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW):$(RK3399M0PMUFW)
-${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW)
+${RK_PLAT_SOC}/drivers/pmu/pmu_fw.S: $(RK3399M0FW)
 
 $(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},${BUILD_PLAT}))
 .PHONY: $(RK3399M0FW)
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index 86795d7..f8a0c18 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -493,12 +493,10 @@
  */
 #if !PSA_FWU_SUPPORT
 			const partition_entry_t *entry;
-			const struct efi_guid img_type_guid = STM32MP_FIP_GUID;
-			uuid_t img_type_uuid;
+			const struct efi_guid fip_guid = STM32MP_FIP_GUID;
 
-			guidcpy(&img_type_uuid, &img_type_guid);
 			partition_init(GPT_IMAGE_ID);
-			entry = get_partition_entry_by_type(&img_type_uuid);
+			entry = get_partition_entry_by_type(&fip_guid);
 			if (entry == NULL) {
 				entry = get_partition_entry(FIP_IMAGE_NAME);
 				if (entry == NULL) {
@@ -613,8 +611,6 @@
  *     - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode.
  * we select the previous_active_index.
  */
-#define INVALID_BOOT_IDX		0xFFFFFFFFU
-
 uint32_t plat_fwu_get_boot_idx(void)
 {
 	/*
@@ -622,32 +618,38 @@
 	 * even if this function is called several times.
 	 */
 	static uint32_t boot_idx = INVALID_BOOT_IDX;
-	const struct fwu_metadata *data;
-
-	data = fwu_get_metadata();
 
 	if (boot_idx == INVALID_BOOT_IDX) {
+		const struct fwu_metadata *data = fwu_get_metadata();
+
 		boot_idx = data->active_index;
-		if (fwu_is_trial_run_state()) {
+
+		if (data->bank_state[boot_idx] == FWU_BANK_STATE_VALID) {
 			if (stm32_get_and_dec_fwu_trial_boot_cnt() == 0U) {
 				WARN("Trial FWU fails %u times\n",
 				     FWU_MAX_TRIAL_REBOOT);
-				boot_idx = data->previous_active_index;
+				boot_idx = fwu_get_alternate_boot_bank();
 			}
-		} else {
+		} else if (data->bank_state[boot_idx] ==
+			   FWU_BANK_STATE_ACCEPTED) {
 			stm32_set_max_fwu_trial_boot_cnt();
+		} else {
+			ERROR("The active bank(%u) of the platform is in Invalid State.\n",
+				boot_idx);
+			boot_idx = fwu_get_alternate_boot_bank();
+			stm32_clear_fwu_trial_boot_cnt();
 		}
 	}
 
 	return boot_idx;
 }
 
-static void *stm32_get_image_spec(const uuid_t *img_type_uuid)
+static void *stm32_get_image_spec(const struct efi_guid *img_type_guid)
 {
 	unsigned int i;
 
 	for (i = 0U; i < MAX_NUMBER_IDS; i++) {
-		if ((guidcmp(&policies[i].img_type_guid, img_type_uuid)) == 0) {
+		if ((guidcmp(&policies[i].img_type_guid, img_type_guid)) == 0) {
 			return (void *)policies[i].image_spec;
 		}
 	}
@@ -660,20 +662,23 @@
 	unsigned int i;
 	uint32_t boot_idx;
 	const partition_entry_t *entry __maybe_unused;
-	const uuid_t *img_type_uuid;
-	const uuid_t *img_uuid __maybe_unused;
+	const struct fwu_image_entry *img_entry;
+	const void *img_type_guid;
+	const void *img_guid;
 	io_block_spec_t *image_spec;
 	const uint16_t boot_itf = stm32mp_get_boot_itf_selected();
 
 	boot_idx = plat_fwu_get_boot_idx();
 	assert(boot_idx < NR_OF_FW_BANKS);
+	VERBOSE("Selecting to boot from bank %u\n", boot_idx);
 
+	img_entry = (void *)&metadata->fw_desc.img_entry;
 	for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
-		img_type_uuid = &metadata->img_entry[i].img_type_uuid;
+		img_type_guid = &img_entry[i].img_type_guid;
 
-		img_uuid = &metadata->img_entry[i].img_props[boot_idx].img_uuid;
+		img_guid = &img_entry[i].img_bank_info[boot_idx].img_guid;
 
-		image_spec = stm32_get_image_spec(img_type_uuid);
+		image_spec = stm32_get_image_spec(img_type_guid);
 		if (image_spec == NULL) {
 			ERROR("Unable to get image spec for the image in the metadata\n");
 			panic();
@@ -683,7 +688,7 @@
 #if (STM32MP_SDMMC || STM32MP_EMMC)
 		case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
 		case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
-			entry = get_partition_entry_by_uuid(img_uuid);
+			entry = get_partition_entry_by_guid(img_guid);
 			if (entry == NULL) {
 				ERROR("No partition with the uuid mentioned in metadata\n");
 				panic();
@@ -695,9 +700,9 @@
 #endif
 #if STM32MP_SPI_NOR
 		case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
-			if (guidcmp(img_uuid, &STM32MP_NOR_FIP_A_GUID) == 0) {
+			if (guidcmp(img_guid, &STM32MP_NOR_FIP_A_GUID) == 0) {
 				image_spec->offset = STM32MP_NOR_FIP_A_OFFSET;
-			} else if (guidcmp(img_uuid, &STM32MP_NOR_FIP_B_GUID) == 0) {
+			} else if (guidcmp(img_guid, &STM32MP_NOR_FIP_B_GUID) == 0) {
 				image_spec->offset = STM32MP_NOR_FIP_B_OFFSET;
 			} else {
 				ERROR("Invalid uuid mentioned in metadata\n");
diff --git a/plat/st/common/common.mk b/plat/st/common/common.mk
index f49112d..b9b62c0 100644
--- a/plat/st/common/common.mk
+++ b/plat/st/common/common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, STMicroelectronics - All Rights Reserved
+# Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -183,12 +183,10 @@
 MBEDTLS_MAJOR=$(shell grep -hP "define MBEDTLS_VERSION_MAJOR" \
 ${MBEDTLS_DIR}/include/mbedtls/*.h | grep -oe '\([0-9.]*\)')
 
-ifeq (${MBEDTLS_MAJOR}, 2)
-MBEDTLS_CONFIG_FILE		?=	"<stm32mp_mbedtls_config-2.h>"
-endif
-
 ifeq (${MBEDTLS_MAJOR}, 3)
 MBEDTLS_CONFIG_FILE		?=	"<stm32mp_mbedtls_config-3.h>"
+else
+$(error Error: TF-A only supports MbedTLS versions > 3.x)
 endif
 endif
 
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index 0ff6092..a1ed1ad 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -142,6 +142,7 @@
 void stm32mp1_fwu_set_boot_idx(void);
 uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void);
 void stm32_set_max_fwu_trial_boot_cnt(void);
+void stm32_clear_fwu_trial_boot_cnt(void);
 #endif /* PSA_FWU_SUPPORT */
 
 #endif /* STM32MP_COMMON_H */
diff --git a/plat/st/common/include/stm32mp_mbedtls_config-2.h b/plat/st/common/include/stm32mp_mbedtls_config-2.h
deleted file mode 100644
index 66ff346..0000000
--- a/plat/st/common/include/stm32mp_mbedtls_config-2.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2022-2023, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#ifndef MBEDTLS_CONFIG_H
-#define MBEDTLS_CONFIG_H
-
-/*
- * Key algorithms currently supported on mbed TLS libraries
- */
-#define TF_MBEDTLS_USE_RSA	0
-#define TF_MBEDTLS_USE_ECDSA	1
-
-/*
- * Hash algorithms currently supported on mbed TLS libraries
- */
-#define TF_MBEDTLS_SHA256		1
-#define TF_MBEDTLS_SHA384		2
-#define TF_MBEDTLS_SHA512		3
-
-/*
- * Configuration file to build mbed TLS with the required features for
- * Trusted Boot
- */
-
-#define MBEDTLS_PLATFORM_MEMORY
-#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
-/* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */
-#define MBEDTLS_PLATFORM_SNPRINTF_ALT
-
-#define MBEDTLS_PKCS1_V21
-
-#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
-#define MBEDTLS_X509_CHECK_KEY_USAGE
-#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
-
-#define MBEDTLS_ASN1_PARSE_C
-#define MBEDTLS_ASN1_WRITE_C
-
-#define MBEDTLS_BASE64_C
-#define MBEDTLS_BIGNUM_C
-
-#define MBEDTLS_ERROR_C
-#define MBEDTLS_MD_C
-
-#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
-#define MBEDTLS_OID_C
-
-#define MBEDTLS_PK_C
-#define MBEDTLS_PK_PARSE_C
-#define MBEDTLS_PK_WRITE_C
-
-#define MBEDTLS_PLATFORM_C
-
-#if TF_MBEDTLS_USE_ECDSA
-#define MBEDTLS_ECDSA_C
-#define MBEDTLS_ECP_C
-#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
-#define MBEDTLS_ECP_NO_INTERNAL_RNG
-#endif
-#if TF_MBEDTLS_USE_RSA
-#define MBEDTLS_RSA_C
-#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
-#endif
-
-#define MBEDTLS_SHA256_C
-#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256)
-#define MBEDTLS_SHA512_C
-#endif
-
-#define MBEDTLS_VERSION_C
-
-#define MBEDTLS_X509_USE_C
-#define MBEDTLS_X509_CRT_PARSE_C
-
-#if TF_MBEDTLS_USE_AES_GCM
-#define MBEDTLS_AES_C
-#define MBEDTLS_CIPHER_C
-#define MBEDTLS_GCM_C
-#endif
-
-/* MPI / BIGNUM options */
-#define MBEDTLS_MPI_WINDOW_SIZE			2
-
-#if TF_MBEDTLS_USE_RSA
-#if TF_MBEDTLS_KEY_SIZE <= 2048
-#define MBEDTLS_MPI_MAX_SIZE			256
-#else
-#define MBEDTLS_MPI_MAX_SIZE			512
-#endif
-#else
-#define MBEDTLS_MPI_MAX_SIZE			256
-#endif
-
-/* Memory buffer allocator options */
-#define MBEDTLS_MEMORY_ALIGN_MULTIPLE		8
-
-/*
- * Prevent the use of 128-bit division which
- * creates dependency on external libraries.
- */
-#define MBEDTLS_NO_UDBL_DIVISION
-
-#ifndef __ASSEMBLER__
-/* System headers required to build mbed TLS with the current configuration */
-#include <stdlib.h>
-#include <mbedtls/check_config.h>
-#endif
-
-/*
- * Mbed TLS heap size is smal as we only use the asn1
- * parsing functions
- * digest, signature and crypto algorithm are done by
- * other library.
- */
-
-#define TF_MBEDTLS_HEAP_SIZE           U(5120)
-#endif /* MBEDTLS_CONFIG_H */
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();
 	}
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index 0e69513..f098eb3 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -714,4 +714,13 @@
 			   TAMP_BOOT_FWU_INFO_CNT_MSK);
 	clk_disable(RTCAPB);
 }
+
+void stm32_clear_fwu_trial_boot_cnt(void)
+{
+	uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID);
+
+	clk_enable(RTCAPB);
+	mmio_clrbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK);
+	clk_disable(RTCAPB);
+}
 #endif /* PSA_FWU_SUPPORT */
diff --git a/services/std_svc/drtm/drtm_main.c b/services/std_svc/drtm/drtm_main.c
index 3acf683..b9c83fa 100644
--- a/services/std_svc/drtm/drtm_main.c
+++ b/services/std_svc/drtm/drtm_main.c
@@ -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
  *
@@ -211,7 +211,7 @@
 	running_on_single_core = psci_is_last_on_cpu_safe();
 	if (!running_on_single_core) {
 		ERROR("DRTM: invalid launch due to non-boot PE not being turned off\n");
-		return DENIED;
+		return SECONDARY_PE_NOT_OFF;
 	}
 
 	return SUCCESS;
@@ -658,7 +658,7 @@
 	drtm_dl_prepare_eret_to_dlme(&args, dlme_el);
 
 	/*
-	 * As per DRTM beta0 spec table #28 invalidate the instruction cache
+	 * As per DRTM 1.0 spec table #30 invalidate the instruction cache
 	 * before jumping to the DLME. This is required to defend against
 	 * potentially-malicious cache contents.
 	 */
diff --git a/services/std_svc/drtm/drtm_main.h b/services/std_svc/drtm/drtm_main.h
index 6005163..a7d053f 100644
--- a/services/std_svc/drtm/drtm_main.h
+++ b/services/std_svc/drtm/drtm_main.h
@@ -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
  *
@@ -55,6 +55,12 @@
 	NOT_FOUND = -4,
 	INTERNAL_ERROR = -5,
 	MEM_PROTECT_INVALID = -6,
+	COPROCESSOR_ERROR = -7,
+	OUT_OF_RESOURCE = -8,
+	INVALID_DATA = -9,
+	SECONDARY_PE_NOT_OFF = -10,
+	ALREADY_CLOSED = -11,
+	TPM_ERROR = -12
 };
 
 typedef struct {
@@ -89,6 +95,7 @@
 	uint64_t dlme_addr_map_size;
 	uint64_t dlme_tpm_log_size;
 	uint64_t dlme_tcb_hashes_table_size;
+	uint64_t dlme_acpi_tables_region_size;
 	uint64_t dlme_impdef_region_size;
 } __aligned(__alignof(uint16_t /* First member's type, `uint16_t version'. */));
 
diff --git a/services/std_svc/errata_abi/cpu_errata_info.h b/services/std_svc/errata_abi/cpu_errata_info.h
index 02dd3a8..2d59fc9 100644
--- a/services/std_svc/errata_abi/cpu_errata_info.h
+++ b/services/std_svc/errata_abi/cpu_errata_info.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,42 +11,25 @@
 #include <arch_helpers.h>
 
 #if __aarch64__
-#include <cortex_a35.h>
-#include <cortex_a510.h>
-#include <cortex_a520.h>
-#include <cortex_a53.h>
-#include <cortex_a57.h>
-#include <cortex_a55.h>
 #include <cortex_a710.h>
-#include <cortex_a72.h>
-#include <cortex_a73.h>
-#include <cortex_a75.h>
-#include <cortex_a76.h>
-#include <cortex_a77.h>
 #include <cortex_a78.h>
 #include <cortex_a78_ae.h>
 #include <cortex_a78c.h>
-#include <cortex_a715.h>
-#include <cortex_x1.h>
 #include <cortex_x2.h>
 #include <cortex_x3.h>
-#include <neoverse_n1.h>
+#include <cortex_x4.h>
 #include <neoverse_n2.h>
 #include <neoverse_v1.h>
 #include <neoverse_v2.h>
-#else
-#include <cortex_a15.h>
-#include <cortex_a17.h>
-#include <cortex_a57.h>
-#include <cortex_a9.h>
 #endif
 
-#define MAX_ERRATA_ENTRIES	32
+/* Max number of platform based errata with no workaround in EL3 */
+#define MAX_PLAT_CPU_ERRATA_ENTRIES	2
 
-#define ERRATA_LIST_END		(MAX_ERRATA_ENTRIES - 1)
+#define ERRATA_LIST_END		(MAX_PLAT_CPU_ERRATA_ENTRIES - 1)
 
 /* Default values for unused memory in the array */
-#define UNDEF_ERRATA		{UINT_MAX, UCHAR_MAX, UCHAR_MAX, false, false}
+#define UNDEF_ERRATA		{UINT_MAX, UCHAR_MAX, UCHAR_MAX}
 
 #define EXTRACT_PARTNUM(x)	((x >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
 
@@ -59,15 +42,11 @@
 	unsigned int em_errata_id;
 	unsigned char em_rxpx_lo;	/* lowest revision of errata applicable for the cpu */
 	unsigned char em_rxpx_hi;	/* highest revision of errata applicable for the cpu */
-	bool errata_enabled;		/* indicate if errata enabled */
-	/* flag to indicate if errata query is based out of non-arm interconnect */
-	bool non_arm_interconnect;
 };
 
 struct em_cpu_list{
-	/* field to hold cpu specific part number defined in midr reg */
-	unsigned long cpu_partnumber;
-	struct   em_cpu cpu_errata_list[MAX_ERRATA_ENTRIES];
+	unsigned long cpu_partnumber;	/* cpu specific part number defined in midr reg */
+	struct   em_cpu cpu_errata_list[MAX_PLAT_CPU_ERRATA_ENTRIES];
 };
 
 int32_t verify_errata_implemented(uint32_t errata_id, uint32_t forward_flag);
diff --git a/services/std_svc/errata_abi/errata_abi_main.c b/services/std_svc/errata_abi/errata_abi_main.c
index 811adcb..0a1d4f3 100644
--- a/services/std_svc/errata_abi/errata_abi_main.c
+++ b/services/std_svc/errata_abi/errata_abi_main.c
@@ -6,6 +6,8 @@
 
 #include <assert.h>
 #include "cpu_errata_info.h"
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
 #include <lib/smccc.h>
 #include <lib/utils_def.h>
 #include <services/errata_abi_svc.h>
@@ -17,197 +19,14 @@
  */
 struct em_cpu_list *cpu_ptr;
 
-extern uint8_t cpu_get_rev_var(void);
-
 /* Structure array that holds CPU specific errata information */
 struct em_cpu_list cpu_list[] = {
-#if CORTEX_A9_H_INC
-{
-	.cpu_partnumber = CORTEX_A9_MIDR,
-	.cpu_errata_list = {
-		[0] = {794073, 0x00, 0xFF, ERRATA_A9_794073},
-		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A9_H_INC */
-
-#if CORTEX_A15_H_INC
-{
-	.cpu_partnumber = CORTEX_A15_MIDR,
-	.cpu_errata_list = {
-		[0] = {816470, 0x30, 0xFF, ERRATA_A15_816470},
-		[1] = {827671, 0x30, 0xFF, ERRATA_A15_827671},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A15_H_INC */
-
-#if CORTEX_A17_H_INC
-{
-	.cpu_partnumber = CORTEX_A17_MIDR,
-	.cpu_errata_list = {
-		[0] = {852421, 0x00, 0x12, ERRATA_A17_852421},
-		[1] = {852423, 0x00, 0x12, ERRATA_A17_852423},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A17_H_INC */
-
-#if CORTEX_A35_H_INC
-{
-	.cpu_partnumber = CORTEX_A35_MIDR,
-	.cpu_errata_list = {
-		[0] = {855472, 0x00, 0x00, ERRATA_A35_855472},
-		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A35_H_INC */
-
-#if CORTEX_A53_H_INC
-{
-	.cpu_partnumber = CORTEX_A53_MIDR,
-	.cpu_errata_list = {
-		[0] = {819472, 0x00, 0x01, ERRATA_A53_819472},
-		[1] = {824069, 0x00, 0x02, ERRATA_A53_824069},
-		[2] = {826319, 0x00, 0x02, ERRATA_A53_826319},
-		[3] = {827319, 0x00, 0x02, ERRATA_A53_827319},
-		[4] = {835769, 0x00, 0x04, ERRATA_A53_835769},
-		[5] = {836870, 0x00, 0x03, ERRATA_A53_836870},
-		[6] = {843419, 0x00, 0x04, ERRATA_A53_843419},
-		[7] = {855873, 0x03, 0xFF, ERRATA_A53_855873},
-		[8] = {1530924, 0x00, 0xFF, ERRATA_A53_1530924},
-		[9 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A53_H_INC */
-
-#if CORTEX_A55_H_INC
-{
-	.cpu_partnumber = CORTEX_A55_MIDR,
-	.cpu_errata_list = {
-		[0] = {768277, 0x00, 0x00, ERRATA_A55_768277},
-		[1] = {778703, 0x00, 0x00, ERRATA_A55_778703},
-		[2] = {798797, 0x00, 0x00, ERRATA_A55_798797},
-		[3] = {846532, 0x00, 0x01, ERRATA_A55_846532},
-		[4] = {903758, 0x00, 0x01, ERRATA_A55_903758},
-		[5] = {1221012, 0x00, 0x10, ERRATA_A55_1221012},
-		[6] = {1530923, 0x00, 0xFF, ERRATA_A55_1530923},
-		[7 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A55_H_INC */
-
-#if CORTEX_A57_H_INC
-{
-	.cpu_partnumber = CORTEX_A57_MIDR,
-	.cpu_errata_list = {
-		[0] = {806969, 0x00, 0x00, ERRATA_A57_806969},
-		[1] = {813419, 0x00, 0x00, ERRATA_A57_813419},
-		[2] = {813420, 0x00, 0x00, ERRATA_A57_813420},
-		[3] = {814670, 0x00, 0x00, ERRATA_A57_814670},
-		[4] = {817169, 0x00, 0x01, ERRATA_A57_817169},
-		[5] = {826974, 0x00, 0x11, ERRATA_A57_826974},
-		[6] = {826977, 0x00, 0x11, ERRATA_A57_826977},
-		[7] = {828024, 0x00, 0x11, ERRATA_A57_828024},
-		[8] = {829520, 0x00, 0x12, ERRATA_A57_829520},
-		[9] = {833471, 0x00, 0x12, ERRATA_A57_833471},
-		[10] = {859972, 0x00, 0x13, ERRATA_A57_859972},
-		[11] = {1319537, 0x00, 0xFF, ERRATA_A57_1319537},
-		[12 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A57_H_INC */
-
-#if CORTEX_A72_H_INC
-{
-	.cpu_partnumber = CORTEX_A72_MIDR,
-	.cpu_errata_list = {
-		[0] = {859971, 0x00, 0x03, ERRATA_A72_859971},
-		[1] = {1319367, 0x00, 0xFF, ERRATA_A72_1319367},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A72_H_INC */
-
-#if CORTEX_A73_H_INC
-{
-	.cpu_partnumber = CORTEX_A73_MIDR,
-	.cpu_errata_list = {
-		[0] = {852427, 0x00, 0x00, ERRATA_A73_852427},
-		[1] = {855423, 0x00, 0x01, ERRATA_A73_855423},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A73_H_INC */
-
-#if CORTEX_A75_H_INC
-{
-	.cpu_partnumber = CORTEX_A75_MIDR,
-	.cpu_errata_list = {
-		[0] = {764081, 0x00, 0x00, ERRATA_A75_764081},
-		[1] = {790748, 0x00, 0x00, ERRATA_A75_790748},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A75_H_INC */
-
-#if CORTEX_A76_H_INC
-{
-	.cpu_partnumber = CORTEX_A76_MIDR,
-	.cpu_errata_list = {
-		[0] = {1073348, 0x00, 0x10, ERRATA_A76_1073348},
-		[1] = {1130799, 0x00, 0x20, ERRATA_A76_1130799},
-		[2] = {1165522, 0x00, 0xFF, ERRATA_A76_1165522},
-		[3] = {1220197, 0x00, 0x20, ERRATA_A76_1220197},
-		[4] = {1257314, 0x00, 0x30, ERRATA_A76_1257314},
-		[5] = {1262606, 0x00, 0x30, ERRATA_A76_1262606},
-		[6] = {1262888, 0x00, 0x30, ERRATA_A76_1262888},
-		[7] = {1275112, 0x00, 0x30, ERRATA_A76_1275112},
-		[8] = {1286807, 0x00, 0x30, ERRATA_A76_1286807},
-		[9] = {1791580, 0x00, 0x40, ERRATA_A76_1791580},
-		[10] = {1868343, 0x00, 0x40, ERRATA_A76_1868343},
-		[11] = {1946160, 0x30, 0x41, ERRATA_A76_1946160},
-		[12] = {2743102, 0x00, 0x41, ERRATA_A76_2743102},
-		[13 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A76_H_INC */
-
-#if CORTEX_A77_H_INC
-{
-	.cpu_partnumber = CORTEX_A77_MIDR,
-	.cpu_errata_list = {
-		[0] = {1508412, 0x00, 0x10, ERRATA_A77_1508412},
-		[1] = {1791578, 0x00, 0x11, ERRATA_A77_1791578},
-		[2] = {1800714, 0x00, 0x11, ERRATA_A77_1800714},
-		[3] = {1925769, 0x00, 0x11, ERRATA_A77_1925769},
-		[4] = {1946167, 0x00, 0x11, ERRATA_A77_1946167},
-		[5] = {2356587, 0x00, 0x11, ERRATA_A77_2356587},
-		[6] = {2743100, 0x00, 0x11, ERRATA_A77_2743100},
-		[7 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A77_H_INC */
-
 #if CORTEX_A78_H_INC
 {
 	.cpu_partnumber = CORTEX_A78_MIDR,
 	.cpu_errata_list = {
-		[0] = {1688305, 0x00, 0x10, ERRATA_A78_1688305},
-		[1] = {1821534, 0x00, 0x10, ERRATA_A78_1821534},
-		[2] = {1941498, 0x00, 0x11, ERRATA_A78_1941498},
-		[3] = {1951500, 0x10, 0x11, ERRATA_A78_1951500},
-		[4] = {1952683, 0x00, 0x00, ERRATA_A78_1952683},
-		[5] = {2132060, 0x00, 0x12, ERRATA_A78_2132060},
-		[6] = {2242635, 0x10, 0x12, ERRATA_A78_2242635},
-		[7] = {2376745, 0x00, 0x12, ERRATA_A78_2376745},
-		[8] = {2395406, 0x00, 0x12, ERRATA_A78_2395406},
-		[9] = {2712571, 0x00, 0x12, ERRATA_A78_2712571, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[10] = {2742426, 0x00, 0x12, ERRATA_A78_2742426},
-		[11] = {2772019, 0x00, 0x12, ERRATA_A78_2772019},
-		[12] = {2779479, 0x00, 0x12, ERRATA_A78_2779479},
-		[13 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2712571, 0x00, 0x12},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_A78_H_INC */
@@ -216,13 +35,8 @@
 {
 	.cpu_partnumber = CORTEX_A78_AE_MIDR,
 	.cpu_errata_list = {
-		[0] = {1941500, 0x00, 0x01, ERRATA_A78_AE_1941500},
-		[1] = {1951502, 0x00, 0x01, ERRATA_A78_AE_1951502},
-		[2] = {2376748, 0x00, 0x02, ERRATA_A78_AE_2376748},
-		[3] = {2395408, 0x00, 0x01, ERRATA_A78_AE_2395408},
-		[4] = {2712574, 0x00, 0x02, ERRATA_A78_AE_2712574, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[5 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2712574, 0x00, 0x02},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_A78_AE_H_INC */
@@ -231,82 +45,18 @@
 {
 	.cpu_partnumber = CORTEX_A78C_MIDR,
 	.cpu_errata_list = {
-		[0] = {1827430, 0x00, 0x00, ERRATA_A78C_1827430},
-		[1] = {1827440, 0x00, 0x00, ERRATA_A78C_1827440},
-		[2] = {2132064, 0x01, 0x02, ERRATA_A78C_2132064},
-		[3] = {2242638, 0x01, 0x02, ERRATA_A78C_2242638},
-		[4] = {2376749, 0x01, 0x02, ERRATA_A78C_2376749},
-		[5] = {2395411, 0x01, 0x02, ERRATA_A78C_2395411},
-		[6] = {2683027, 0x01, 0x02, ERRATA_A78C_2683027},
-		[7] = {2712575, 0x01, 0x02, ERRATA_A78C_2712575, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[8] = {2743232, 0x01, 0x02, ERRATA_A78C_2743232},
-		[9] = {2772121, 0x00, 0x02, ERRATA_A78C_2772121},
-		[10] = {2779484, 0x01, 0x02, ERRATA_A78C_2779484},
-		[11 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2712575, 0x01, 0x02},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_A78C_H_INC */
 
-#if CORTEX_X1_H_INC
-{
-	.cpu_partnumber = CORTEX_X1_MIDR,
-	.cpu_errata_list = {
-		[0] = {1688305, 0x00, 0x10, ERRATA_X1_1688305},
-		[1] = {1821534, 0x00, 0x10, ERRATA_X1_1821534},
-		[2] = {1827429, 0x00, 0x10, ERRATA_X1_1827429},
-		[3 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_X1_H_INC */
-
-#if NEOVERSE_N1_H_INC
-{
-	.cpu_partnumber = NEOVERSE_N1_MIDR,
-	.cpu_errata_list = {
-		[0] = {1043202, 0x00, 0x10, ERRATA_N1_1043202},
-		[1] = {1073348, 0x00, 0x10, ERRATA_N1_1073348},
-		[2] = {1130799, 0x00, 0x20, ERRATA_N1_1130799},
-		[3] = {1165347, 0x00, 0x20, ERRATA_N1_1165347},
-		[4] = {1207823, 0x00, 0x20, ERRATA_N1_1207823},
-		[5] = {1220197, 0x00, 0x20, ERRATA_N1_1220197},
-		[6] = {1257314, 0x00, 0x30, ERRATA_N1_1257314},
-		[7] = {1262606, 0x00, 0x30, ERRATA_N1_1262606},
-		[8] = {1262888, 0x00, 0x30, ERRATA_N1_1262888},
-		[9] = {1275112, 0x00, 0x30, ERRATA_N1_1275112},
-		[10] = {1315703, 0x00, 0x30, ERRATA_N1_1315703},
-		[11] = {1542419, 0x30, 0x40, ERRATA_N1_1542419},
-		[12] = {1868343, 0x00, 0x40, ERRATA_N1_1868343},
-		[13] = {1946160, 0x30, 0x41, ERRATA_N1_1946160},
-		[14] = {2743102, 0x00, 0x41, ERRATA_N1_2743102},
-		[15 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* NEOVERSE_N1_H_INC */
-
 #if NEOVERSE_V1_H_INC
 {
 	.cpu_partnumber = NEOVERSE_V1_MIDR,
 	.cpu_errata_list = {
-		[0] = {1618635, 0x00, 0x00, ERRATA_V1_1618635},
-		[1] = {1774420, 0x00, 0x10, ERRATA_V1_1774420},
-		[2] = {1791573, 0x00, 0x10, ERRATA_V1_1791573},
-		[3] = {1852267, 0x00, 0x10, ERRATA_V1_1852267},
-		[4] = {1925756, 0x00, 0x11, ERRATA_V1_1925756},
-		[5] = {1940577, 0x10, 0x11, ERRATA_V1_1940577},
-		[6] = {1966096, 0x10, 0x11, ERRATA_V1_1966096},
-		[7] = {2108267, 0x00, 0x12, ERRATA_V1_2108267},
-		[8] = {2139242, 0x00, 0x11, ERRATA_V1_2139242},
-		[9] = {2216392, 0x10, 0x11, ERRATA_V1_2216392},
-		[10] = {2294912, 0x00, 0x12, ERRATA_V1_2294912},
-		[11] = {2348377, 0x00, 0x11, ERRATA_V1_2348377},
-		[12] = {2372203, 0x00, 0x11, ERRATA_V1_2372203},
-		[13] = {2701953, 0x00, 0x11, ERRATA_V1_2701953, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[14] = {2743093, 0x00, 0x12, ERRATA_V1_2743093},
-		[15] = {2743233, 0x00, 0x12, ERRATA_V1_2743233},
-		[16] = {2779461, 0x00, 0x12, ERRATA_V1_2779461},
-		[17 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2701953, 0x00, 0x11},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* NEOVERSE_V1_H_INC */
@@ -315,26 +65,8 @@
 {
 	.cpu_partnumber = CORTEX_A710_MIDR,
 	.cpu_errata_list = {
-		[0] = {1987031, 0x00, 0x20, ERRATA_A710_1987031},
-		[1] = {2008768, 0x00, 0x20, ERRATA_A710_2008768},
-		[2] = {2017096, 0x00, 0x20, ERRATA_A710_2017096},
-		[3] = {2055002, 0x10, 0x20, ERRATA_A710_2055002},
-		[4] = {2058056, 0x00, 0x21, ERRATA_A710_2058056},
-		[5] = {2081180, 0x00, 0x20, ERRATA_A710_2081180},
-		[6] = {2083908, 0x20, 0x20, ERRATA_A710_2083908},
-		[7] = {2136059, 0x00, 0x20, ERRATA_A710_2136059},
-		[8] = {2147715, 0x20, 0x20, ERRATA_A710_2147715},
-		[9] = {2216384, 0x00, 0x20, ERRATA_A710_2216384},
-		[10] = {2267065, 0x00, 0x20, ERRATA_A710_2267065},
-		[11] = {2282622, 0x00, 0x21, ERRATA_A710_2282622},
-		[12] = {2291219, 0x00, 0x20, ERRATA_A710_2291219},
-		[13] = {2371105, 0x00, 0x20, ERRATA_A710_2371105},
-		[14] = {2701952, 0x00, 0x21, ERRATA_A710_2701952, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[15] = {2742423, 0x00, 0x21, ERRATA_A710_2742423},
-		[16] = {2768515, 0x00, 0x21, ERRATA_A710_2768515},
-		[17] = {2778471, 0x00, 0x21, ERRATA_A710_2778471},
-		[18 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2701952, 0x00, 0x21},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_A710_H_INC */
@@ -343,28 +75,8 @@
 {
 	.cpu_partnumber = NEOVERSE_N2_MIDR,
 	.cpu_errata_list = {
-		[0] = {2002655, 0x00, 0x00, ERRATA_N2_2002655},
-		[1] = {2009478, 0x00, 0x00, ERRATA_N2_2009478},
-		[2] = {2025414, 0x00, 0x00, ERRATA_N2_2025414},
-		[3] = {2067956, 0x00, 0x00, ERRATA_N2_2067956},
-		[4] = {2138953, 0x00, 0x03, ERRATA_N2_2138953},
-		[5] = {2138956, 0x00, 0x00, ERRATA_N2_2138956},
-		[6] = {2138958, 0x00, 0x00, ERRATA_N2_2138958},
-		[7] = {2189731, 0x00, 0x00, ERRATA_N2_2189731},
-		[8] = {2242400, 0x00, 0x00, ERRATA_N2_2242400},
-		[9] = {2242415, 0x00, 0x00, ERRATA_N2_2242415},
-		[10] = {2280757, 0x00, 0x00, ERRATA_N2_2280757},
-		[11] = {2326639, 0x00, 0x00, ERRATA_N2_2326639},
-		[12] = {2340933, 0x00, 0x00, ERRATA_N2_2340933},
-		[13] = {2346952, 0x00, 0x02, ERRATA_N2_2346952},
-		[14] = {2376738, 0x00, 0x00, ERRATA_N2_2376738},
-		[15] = {2388450, 0x00, 0x00, ERRATA_N2_2388450},
-		[16] = {2728475, 0x00, 0x02, ERRATA_N2_2728475, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[17] = {2743014, 0x00, 0x02, ERRATA_N2_2743014},
-		[18] = {2743089, 0x00, 0x02, ERRATA_N2_2743089},
-		[19] = {2779511, 0x00, 0x02, ERRATA_N2_2779511},
-		[20 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2728475, 0x00, 0x02},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* NEOVERSE_N2_H_INC */
@@ -373,185 +85,126 @@
 {
 	.cpu_partnumber = CORTEX_X2_MIDR,
 	.cpu_errata_list = {
-		[0] = {2002765, 0x00, 0x20, ERRATA_X2_2002765},
-		[1] = {2017096, 0x00, 0x20, ERRATA_X2_2017096},
-		[2] = {2058056, 0x00, 0x21, ERRATA_X2_2058056},
-		[3] = {2081180, 0x00, 0x20, ERRATA_X2_2081180},
-		[4] = {2083908, 0x20, 0x20, ERRATA_X2_2083908},
-		[5] = {2147715, 0x20, 0x20, ERRATA_X2_2147715},
-		[6] = {2216384, 0x00, 0x20, ERRATA_X2_2216384},
-		[7] = {2282622, 0x00, 0x21, ERRATA_X2_2282622},
-		[8] = {2371105, 0x00, 0x20, ERRATA_X2_2371105},
-		[9] = {2701952, 0x00, 0x21, ERRATA_X2_2701952, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[10] = {2742423, 0x00, 0x21, ERRATA_X2_2742423},
-		[11] = {2768515, 0x00, 0x21, ERRATA_X2_2768515},
-		[12] = {2778471, 0x00, 0x21, ERRATA_X2_2778471},
-		[13 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2701952, 0x00, 0x21},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_X2_H_INC */
 
-#if CORTEX_A510_H_INC
-{
-	.cpu_partnumber = CORTEX_A510_MIDR,
-	.cpu_errata_list = {
-		[0] = {1922240, 0x00, 0x00, ERRATA_A510_1922240},
-		[1] = {2041909, 0x02, 0x02, ERRATA_A510_2041909},
-		[2] = {2042739, 0x00, 0x02, ERRATA_A510_2042739},
-		[3] = {2080326, 0x02, 0x02, ERRATA_A510_2080326},
-		[4] = {2172148, 0x00, 0x10, ERRATA_A510_2172148},
-		[5] = {2218950, 0x00, 0x10, ERRATA_A510_2218950},
-		[6] = {2250311, 0x00, 0x10, ERRATA_A510_2250311},
-		[7] = {2288014, 0x00, 0x10, ERRATA_A510_2288014},
-		[8] = {2347730, 0x00, 0x11, ERRATA_A510_2347730},
-		[9] = {2371937, 0x00, 0x11, ERRATA_A510_2371937},
-		[10] = {2666669, 0x00, 0x11, ERRATA_A510_2666669},
-		[11] = {2684597, 0x00, 0x12, ERRATA_A510_2684597},
-		[12 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A510_H_INC */
-
 #if NEOVERSE_V2_H_INC
 {
 	.cpu_partnumber = NEOVERSE_V2_MIDR,
 	.cpu_errata_list = {
-		[0] = {2331132, 0x00, 0x02, ERRATA_V2_2331132},
-		[1] = {2618597, 0x00, 0x01, ERRATA_V2_2618597},
-		[2] = {2662553, 0x00, 0x01, ERRATA_V2_2662553},
-		[3] = {2719103, 0x00, 0x01, ERRATA_V2_2719103, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[4] = {2719105, 0x00, 0x01, ERRATA_V2_2719105},
-		[5] = {2743011, 0x00, 0x01, ERRATA_V2_2743011},
-		[6] = {2779510, 0x00, 0x01, ERRATA_V2_2779510},
-		[7] = {2801372, 0x00, 0x01, ERRATA_V2_2801372},
-		[8 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2719103, 0x00, 0x01},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* NEOVERSE_V2_H_INC */
 
-#if CORTEX_A715_H_INC
-{
-	.cpu_partnumber = CORTEX_A715_MIDR,
-	.cpu_errata_list = {
-		[0] = {2561034, 0x10, 0x10, ERRATA_A715_2561034},
-		[1] = {2701951, 0x00, 0x11, ERRATA_A715_2701951, \
-			ERRATA_NON_ARM_INTERCONNECT},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
-	}
-},
-#endif /* CORTEX_A715_H_INC */
-
 #if CORTEX_X3_H_INC
 {
 	.cpu_partnumber = CORTEX_X3_MIDR,
 	.cpu_errata_list = {
-		[0] = {2070301, 0x00, 0x12, ERRATA_X3_2070301},
-		[1] = {2266875, 0x00, 0x10, ERRATA_X3_2266875},
-		[2] = {2302506, 0x00, 0x11, ERRATA_X3_2302506},
-		[3] = {2313909, 0x00, 0x10, ERRATA_X3_2313909},
-		[4] = {2615812, 0x00, 0x11, ERRATA_X3_2615812},
-		[5] = {2641945, 0x00, 0x10, ERRATA_X3_2641945},
-		[6] = {2742421, 0x00, 0x11, ERRATA_X3_2742421},
-		[7] = {2743088, 0x00, 0x11, ERRATA_X3_2743088},
-		[8] = {2779509, 0x00, 0x11, ERRATA_X3_2779509},
-		[9 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2701951, 0x00, 0x11},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* CORTEX_X3_H_INC */
 
-#if CORTEX_A520_H_INC
+#if CORTEX_X4_H_INC
 {
-	.cpu_partnumber = CORTEX_A520_MIDR,
+	.cpu_partnumber = CORTEX_X4_MIDR,
 	.cpu_errata_list = {
-		[0] = {2630792, 0x00, 0x01, ERRATA_A520_2630792},
-		[1] = {2858100, 0x00, 0x01, ERRATA_A520_2858100},
-		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[0] = {2701112, 0x00, 0x00},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
-#endif /* CORTEX_A520_H_INC */
+#endif /* CORTEX_X4_H_INC */
 
 };
 
-/*
- * Function to do binary search and check for the specific errata ID
- * in the array of structures specific to the cpu identified.
- */
-int32_t binary_search(struct em_cpu_list *ptr, uint32_t erratum_id, uint8_t rxpx_val)
-{
-	int low_index = 0U, mid_index = 0U;
+#if ERRATA_NON_ARM_INTERCONNECT
 
-	int high_index = MAX_ERRATA_ENTRIES - 1;
+/* Check if the errata is enabled for non-arm interconnect */
+static int32_t non_arm_interconnect_errata(uint32_t errata_id, long rev_var)
+{
+	int32_t ret_val = EM_UNKNOWN_ERRATUM;
 
-	assert(ptr != NULL);
+	/* Determine the number of cpu listed in the cpu list */
+	uint8_t size_cpulist = ARRAY_SIZE(cpu_list);
 
-	/*
-	 * Pointer to the errata list of the cpu that matches
-	 * extracted partnumber in the cpu list
-	 */
-	struct em_cpu *erratum_ptr = NULL;
+	/* Read the midr reg to extract cpu, revision and variant info */
+	uint32_t midr_val = read_midr();
 
-	while (low_index <= high_index) {
-		mid_index = (low_index + high_index) / 2;
+	for (uint8_t i = 0U; i < size_cpulist; i++) {
+		cpu_ptr = &cpu_list[i];
+		/*
+		 * If the cpu partnumber in the cpu list, matches the midr
+		 * part number, check to see if the errata ID matches
+		 */
+		if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(cpu_ptr->cpu_partnumber)) {
 
-		erratum_ptr = &ptr->cpu_errata_list[mid_index];
-		assert(erratum_ptr != NULL);
+			struct em_cpu *ptr = NULL;
 
-		if (erratum_id < erratum_ptr->em_errata_id) {
-			high_index = mid_index - 1;
-		} else if (erratum_id > erratum_ptr->em_errata_id) {
-			low_index = mid_index + 1;
-		} else if (erratum_id == erratum_ptr->em_errata_id) {
-			if (RXPX_RANGE(rxpx_val, erratum_ptr->em_rxpx_lo, \
-				erratum_ptr->em_rxpx_hi)) {
-				if ((erratum_ptr->errata_enabled) && \
-				(!(erratum_ptr->non_arm_interconnect))) {
-					return EM_HIGHER_EL_MITIGATION;
+			for (int j = 0; j < MAX_PLAT_CPU_ERRATA_ENTRIES; j++) {
+				ptr = &cpu_ptr->cpu_errata_list[j];
+				assert(ptr != NULL);
+				if (errata_id == ptr->em_errata_id) {
+					if (RXPX_RANGE(rev_var, ptr->em_rxpx_lo, ptr->em_rxpx_hi)) {
+						ret_val = EM_AFFECTED;
+						break;
+					}
+					ret_val = EM_NOT_AFFECTED;
+					break;
 				}
-				return EM_AFFECTED;
 			}
-			return EM_NOT_AFFECTED;
+			break;
 		}
 	}
-	/* no matching errata ID */
-	return EM_UNKNOWN_ERRATUM;
+	return ret_val;
 }
+#endif
 
 /* Function to check if the errata exists for the specific CPU and rxpx */
 int32_t verify_errata_implemented(uint32_t errata_id, uint32_t forward_flag)
 {
-	/*
-	 * Read MIDR value and extract the revision, variant and partnumber
-	 */
-	static uint32_t midr_val, cpu_partnum;
-	static uint8_t  cpu_rxpx_val;
-	int32_t ret_val = EM_UNKNOWN_ERRATUM;
+	int32_t ret_val;
+	struct cpu_ops *cpu_ops;
+	struct erratum_entry *entry, *end;
+	long rev_var;
 
-	/* Determine the number of cpu listed in the cpu list */
-	uint8_t size_cpulist = ARRAY_SIZE(cpu_list);
+	ret_val = EM_UNKNOWN_ERRATUM;
+	rev_var = cpu_get_rev_var();
 
-	/* Read the midr reg to extract cpu, revision and variant info */
-	midr_val = read_midr();
+#if ERRATA_NON_ARM_INTERCONNECT
+	ret_val = non_arm_interconnect_errata(errata_id, rev_var);
+	if (ret_val != EM_UNKNOWN_ERRATUM) {
+		return ret_val;
+	}
+#endif
 
-	/* Extract revision and variant from the MIDR register */
-	cpu_rxpx_val = cpu_get_rev_var();
+	cpu_ops = get_cpu_ops_ptr();
+	assert(cpu_ops != NULL);
 
-	/* Extract the cpu partnumber and check if the cpu is in the cpu list */
-	cpu_partnum = EXTRACT_PARTNUM(midr_val);
+	entry = cpu_ops->errata_list_start;
+	assert(entry != NULL);
 
-	for (uint8_t i = 0; i < size_cpulist; i++) {
-		cpu_ptr = &cpu_list[i];
-		uint16_t partnum_extracted = EXTRACT_PARTNUM(cpu_ptr->cpu_partnumber);
+	end = cpu_ops->errata_list_end;
+	assert(end != NULL);
 
-		if (partnum_extracted == cpu_partnum) {
-			/*
-			 * If the midr value is in the cpu list, binary search
-			 * for the errata ID and specific revision in the list.
-			 */
-			ret_val = binary_search(cpu_ptr, errata_id, cpu_rxpx_val);
-			break;
+	end--; /* point to the last erratum entry of the queried cpu */
+
+	while ((entry <= end) && (ret_val == EM_UNKNOWN_ERRATUM)) {
+		if (entry->id == errata_id) {
+			if (entry->check_func(rev_var)) {
+				if (entry->chosen)
+					return EM_HIGHER_EL_MITIGATION;
+				else
+					return EM_AFFECTED;
+			}
+			return EM_NOT_AFFECTED;
 		}
+		entry += 1;
 	}
 	return ret_val;
 }
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index fb096bc..b3b2a69 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -109,8 +109,8 @@
 
 static void rmm_el2_context_init(el2_sysregs_t *regs)
 {
-	regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2;
-	regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1;
+	write_el2_ctx_common(regs, spsr_el2, REALM_SPSR_EL2);
+	write_el2_ctx_common(regs, sctlr_el2, SCTLR_EL2_RES1);
 }
 
 /*******************************************************************************
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
index 72bc33f..c58adba 100644
--- a/services/std_svc/sdei/sdei_intr_mgmt.c
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -13,6 +13,7 @@
 #include <arch_features.h>
 #include <bl31/ehf.h>
 #include <bl31/interrupt_mgmt.h>
+#include <bl31/sync_handle.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <common/runtime_svc.h>
@@ -237,9 +238,7 @@
 /*
  * Prepare for ERET:
  * - Set the ELR to the registered handler address
- * - Set the SPSR register as described in the SDEI documentation and
- *   the AArch64.TakeException() pseudocode function in
- *   ARM DDI 0487F.c page J1-7635
+ * - Set the SPSR register by calling the common create_spsr() function
  */
 
 static void sdei_set_elr_spsr(sdei_entry_t *se, sdei_dispatch_context_t *disp_ctx)
@@ -250,57 +249,7 @@
 
 	u_register_t interrupted_pstate = disp_ctx->spsr_el3;
 
-	/* Check the SPAN bit in the client el SCTLR */
-	u_register_t client_el_sctlr;
-
-	if (client_el == MODE_EL2) {
-		client_el_sctlr = read_sctlr_el2();
-	} else {
-		client_el_sctlr = read_sctlr_el1();
-	}
-
-	/*
-	 * Check whether to force the PAN bit or use the value in the
-	 * interrupted EL according to the check described in
-	 * TakeException. Since the client can only be Non-Secure
-	 * EL2 or El1 some of the conditions in ElIsInHost() we know
-	 * will always be True.
-	 * When the client_el is EL2 we know that there will be a SPAN
-	 * bit in SCTLR_EL2 as we have already checked for the condition
-	 * HCR_EL2.E2H = 1 and HCR_EL2.TGE = 1
-	 */
-	u_register_t hcr_el2 = read_hcr();
-	bool el_is_in_host = (read_feat_vhe_id_field() != 0U) &&
-			     (hcr_el2 & HCR_TGE_BIT) &&
-			     (hcr_el2 & HCR_E2H_BIT);
-
-	if (is_feat_pan_supported() &&
-	    ((client_el == MODE_EL1) ||
-		(client_el == MODE_EL2 && el_is_in_host)) &&
-	    ((client_el_sctlr & SCTLR_SPAN_BIT) == 0U)) {
-		sdei_spsr |=  SPSR_PAN_BIT;
-	} else {
-		sdei_spsr |= (interrupted_pstate & SPSR_PAN_BIT);
-	}
-
-	/* If SSBS is implemented, take the value from the client el SCTLR */
-	u_register_t ssbs_enabled = (read_id_aa64pfr1_el1()
-					>> ID_AA64PFR1_EL1_SSBS_SHIFT)
-					& ID_AA64PFR1_EL1_SSBS_MASK;
-	if (ssbs_enabled != SSBS_UNAVAILABLE) {
-		u_register_t  ssbs_bit = ((client_el_sctlr & SCTLR_DSSBS_BIT)
-						>> SCTLR_DSSBS_SHIFT)
-						<< SPSR_SSBS_SHIFT_AARCH64;
-		sdei_spsr |= ssbs_bit;
-	}
-
-	/* If MTE is implemented in the client el set the TCO bit */
-	if (is_feat_mte_supported()) {
-		sdei_spsr |= SPSR_TCO_BIT_AARCH64;
-	}
-
-	/* Take the DIT field from the pstate of the interrupted el */
-	sdei_spsr |= (interrupted_pstate & SPSR_DIT_BIT);
+	sdei_spsr = create_spsr(interrupted_pstate, client_el);
 
 	cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep, sdei_spsr);
 }