Merge changes from topic "stm32mp2_bl2_updates" into integration

* changes:
  feat(stm32mp2): load fw-config file
  feat(stm32mp2): add fw-config compilation
  feat(stm32mp2-fdts): add fw-config files for STM32MP257F-EV1
  feat(stm32mp2-fdts): add fw-config file
  feat(stm32mp2-fdts): add clock tree for STM32MP257F-EV1
  feat(stm32mp2): enable DDR sub-system clock
  feat(stm32mp2): add fixed regulators support
  feat(stm32mp2): print board info
  feat(stm32mp2): display CPU info
  feat(stm32mp2): get chip ID
  feat(stm32mp2): add BL2 boot first steps
  feat(stm32mp2): add defines for the PWR peripheral
  feat(stm32mp2-fdts): add SD-card and eMMC support on STM32MP257F-EV1
  feat(stm32mp2-fdts): add sdmmc pins definition
  feat(stm32mp2-fdts): add sdmmc nodes in SoC DT file
  feat(stm32mp2-fdts): add io_policies
  feat(stm32mp2-fdts): remove pins-are-numbered
diff --git a/Makefile b/Makefile
index baf8431..64bccbc 100644
--- a/Makefile
+++ b/Makefile
@@ -121,6 +121,9 @@
 SP_MK_GEN		?=	${SPTOOLPATH}/sp_mk_generator.py
 SP_DTS_LIST_FRAGMENT	?=	${BUILD_PLAT}/sp_list_fragment.dts
 
+# Variables for use with Certificate Conversion (cot-dt2c) Tool
+CERTCONVPATH	?= tools/cot_dt2c
+
 # Variables for use with ROMLIB
 ROMLIBPATH		?=	lib/romlib
 
@@ -454,6 +457,9 @@
 			ifeq ($(SPMC_AT_EL3),1)
                                 $(error SPM cannot be enabled in both S-EL2 and EL3.)
 			endif
+			ifeq ($(CTX_INCLUDE_SVE_REGS),1)
+                                $(error SVE context management not needed with Hafnium SPMC.)
+			endif
 		endif
 
 		ifeq ($(findstring optee_sp,$(ARM_SPMC_MANIFEST_DTS)),optee_sp)
@@ -972,25 +978,52 @@
 	endif
 endif #(ENABLE_SME_FOR_SWD)
 
+# Enabling SVE for SWD requires enabling SVE for NWD due to ENABLE_FEAT
+# mechanism.
 ifeq (${ENABLE_SVE_FOR_SWD},1)
-	ifeq (${ENABLE_SVE_FOR_NS},0)
-                $(error "ENABLE_SVE_FOR_SWD requires ENABLE_SVE_FOR_NS")
-	endif
-endif #(ENABLE_SVE_FOR_SWD)
+    ifeq (${ENABLE_SVE_FOR_NS},0)
+        $(error "ENABLE_SVE_FOR_SWD requires ENABLE_SVE_FOR_NS")
+    endif
+endif
 
-# SVE and SME cannot be used with CTX_INCLUDE_FPREGS since secure manager does
-# its own context management including FPU registers.
-ifeq (${CTX_INCLUDE_FPREGS},1)
-	ifneq (${ENABLE_SME_FOR_NS},0)
-                $(error "ENABLE_SME_FOR_NS cannot be used with CTX_INCLUDE_FPREGS")
-	endif
+# Enabling SVE for both the worlds typically requires the context
+# management of SVE registers. The only exception being SPMC at S-EL2.
+ifeq (${ENABLE_SVE_FOR_SWD}, 1)
+    ifneq (${ENABLE_SVE_FOR_NS}, 0)
+        ifeq (${CTX_INCLUDE_SVE_REGS}-$(SPMD_SPM_AT_SEL2),0-0)
+            $(warning "ENABLE_SVE_FOR_SWD and ENABLE_SVE_FOR_NS together require CTX_INCLUDE_SVE_REGS")
+        endif
+    endif
+endif
 
-	ifeq (${ENABLE_SVE_FOR_NS},1)
-		# Warning instead of error due to CI dependency on this
-                $(warning "ENABLE_SVE_FOR_NS cannot be used with CTX_INCLUDE_FPREGS")
-                $(warning "Forced ENABLE_SVE_FOR_NS=0")
-		override ENABLE_SVE_FOR_NS	:= 0
-	endif
+# Enabling SVE in either world while enabling CTX_INCLUDE_FPREGS requires
+# CTX_INCLUDE_SVE_REGS to be enabled due to architectural dependency between FP
+# and SVE registers.
+ifeq (${CTX_INCLUDE_FPREGS}, 1)
+    ifneq (${ENABLE_SVE_FOR_NS},0)
+        ifeq (${CTX_INCLUDE_SVE_REGS},0)
+	    # Warning instead of error due to CI dependency on this
+            $(warning "CTX_INCLUDE_FPREGS and ENABLE_SVE_FOR_NS together require CTX_INCLUDE_SVE_REGS")
+            $(warning "Forced ENABLE_SVE_FOR_NS=0")
+	    override ENABLE_SVE_FOR_NS	:= 0
+        endif
+    endif
+endif #(CTX_INCLUDE_FPREGS)
+
+# SVE context management is only required if secure world has access to SVE/FP
+# functionality.
+ifeq (${CTX_INCLUDE_SVE_REGS},1)
+    ifeq (${ENABLE_SVE_FOR_SWD},0)
+        $(error "CTX_INCLUDE_SVE_REGS requires ENABLE_SVE_FOR_SWD to also be enabled")
+    endif
+endif
+
+# SME cannot be used with CTX_INCLUDE_FPREGS since SPM does its own context
+# management including FPU registers.
+ifeq (${CTX_INCLUDE_FPREGS},1)
+    ifneq (${ENABLE_SME_FOR_NS},0)
+        $(error "ENABLE_SME_FOR_NS cannot be used with CTX_INCLUDE_FPREGS")
+    endif
 endif #(CTX_INCLUDE_FPREGS)
 
 ifeq ($(DRTM_SUPPORT),1)
@@ -1127,6 +1160,7 @@
 	CREATE_KEYS \
 	CTX_INCLUDE_AARCH32_REGS \
 	CTX_INCLUDE_FPREGS \
+	CTX_INCLUDE_SVE_REGS \
 	CTX_INCLUDE_EL2_REGS \
 	CTX_INCLUDE_MPAM_REGS \
 	DEBUG \
@@ -1165,6 +1199,7 @@
 	SEPARATE_CODE_AND_RODATA \
 	SEPARATE_BL2_NOLOAD_REGION \
 	SEPARATE_NOBITS_REGION \
+	SEPARATE_SIMD_SECTION \
 	SPIN_ON_BL1_EXIT \
 	SPM_MM \
 	SPMC_AT_EL3 \
@@ -1285,6 +1320,7 @@
 	COLD_BOOT_SINGLE_CPU \
 	CTX_INCLUDE_AARCH32_REGS \
 	CTX_INCLUDE_FPREGS \
+	CTX_INCLUDE_SVE_REGS \
 	CTX_INCLUDE_PAUTH_REGS \
 	CTX_INCLUDE_MPAM_REGS \
 	EL3_EXCEPTION_HANDLING \
@@ -1337,6 +1373,7 @@
 	SEPARATE_CODE_AND_RODATA \
 	SEPARATE_BL2_NOLOAD_REGION \
 	SEPARATE_NOBITS_REGION \
+	SEPARATE_SIMD_SECTION \
 	RECLAIM_INIT_CODE \
 	SPD_${SPD} \
 	SPIN_ON_BL1_EXIT \
@@ -1582,6 +1619,7 @@
 clean:
 	$(s)echo "  CLEAN"
 	$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
+	$(q)${MAKE} -C ${CERTCONVPATH} clean
 ifdef UNIX_MK
 	$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
 else
@@ -1597,6 +1635,7 @@
 	$(s)echo "  REALCLEAN"
 	$(call SHELL_REMOVE_DIR,${BUILD_BASE})
 	$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
+	$(q)${MAKE} -C ${CERTCONVPATH} clean
 ifdef UNIX_MK
 	$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
 else
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 7e9fde3..7dc71a2 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -42,10 +42,12 @@
 				bl31/bl31_context_mgmt.c			\
 				bl31/bl31_traps.c				\
 				common/runtime_svc.c				\
+				lib/cpus/errata_common.c			\
 				lib/cpus/aarch64/dsu_helpers.S			\
 				plat/common/aarch64/platform_mp_stack.S		\
 				services/arm_arch_svc/arm_arch_svc_setup.c	\
 				services/std_svc/std_svc_setup.c		\
+				lib/el3_runtime/simd_ctx.c			\
 				${PSCI_LIB_SOURCES}				\
 				${SPMD_SOURCES}					\
 				${SPM_MM_SOURCES}				\
diff --git a/changelog.yaml b/changelog.yaml
index 2b760c7..df0476f 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -805,6 +805,9 @@
           - title: RAS
             scope: ras
 
+          - title: SIMD
+            scope: simd
+
       - title: FCONF
         scope: fconf
 
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index cbed72f..8ac09ae 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -565,8 +565,8 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
 :|G|: `abdellatif-elkhlifi`_
-:|M|: Xueliang Zhong <xueliang.zhong@arm.com>
-:|G|: `xueliang-zhong-arm`_
+:|M|: Hugues Kamba Mpiana <hugues.kambampiana@arm.com>
+:|G|: `hugues-kambampiana-arm`_
 :|F|: plat/arm/board/corstone700
 :|F|: plat/arm/board/a5ds
 :|F|: plat/arm/board/corstone1000
@@ -1050,6 +1050,7 @@
 .. _harrisonmutai-arm: https://github.com/harrisonmutai-arm
 .. _hilamirandakuzi1: https://github.com/hilamirandakuzi1
 .. _hzhuang1: https://github.com/hzhuang1
+.. _hugues-kambampiana-arm: https://github.com/hugueskamba
 .. _JackyBai: https://github.com/JackyBai
 .. _J-Alves: https://github.com/J-Alves
 .. _jason-ch-chen: https://github.com/jason-ch-chen
@@ -1112,7 +1113,6 @@
 .. _vijayenthiran-arm: https://github.com/vijayenthiran-arm
 .. _vishnu-banavath: https://github.com/vishnu-banavath
 .. _vwadekar: https://github.com/vwadekar
-.. _xueliang-zhong-arm: https://github.com/xueliang-zhong-arm
 .. _Yann-lms: https://github.com/Yann-lms
 
 --------------
diff --git a/docs/components/context-management-library.rst b/docs/components/context-management-library.rst
index 56ba2ec..266b82a 100644
--- a/docs/components/context-management-library.rst
+++ b/docs/components/context-management-library.rst
@@ -98,14 +98,15 @@
 
 4. **Dynamic discovery of Feature enablement by EL3**
 
-TF-A supports three states for feature enablement at EL3, to make them available
+TF-A supports four states for feature enablement at EL3, to make them available
 for lower exception levels.
 
 .. code:: c
 
-	#define FEAT_STATE_DISABLED	0
-	#define FEAT_STATE_ENABLED	1
-	#define FEAT_STATE_CHECK	2
+	#define FEAT_STATE_DISABLED     	0
+	#define FEAT_STATE_ENABLED      	1
+	#define FEAT_STATE_CHECK        	2
+	#define FEAT_STATE_CHECK_ASYMMETRIC	3
 
 A pattern is established for feature enablement behavior.
 Each feature must support the 3 possible values with rigid semantics.
@@ -119,7 +120,26 @@
 - **FEAT_STATE_CHECK** - same as ``FEAT_STATE_ALWAYS`` except that the feature's
   existence will be checked at runtime. Default on dynamic platforms (example: FVP).
 
-.. note::
+- **FEAT_STATE_CHECK_ASYMMETRIC** - same as ``FEAT_STATE_CHECK`` except that the feature's
+  existence is asymmetric across cores, which requires the feature existence is checked
+  during warmboot path also. Note that only limited number of features can be asymmetric.
+
+ .. note::
+   Only limited number of features can be ``FEAT_STATE_CHECK_ASYMMETRIC`` this is due to
+   the fact that Operating systems are designed for SMP systems.
+   There are no clear guidelines what kind of mismatch is allowed but following pointers
+   can help making a decision
+
+    - All mandatory features must be symmetric.
+    - Any feature that impacts the generation of page tables must be symmetric.
+    - Any feature access which does not trap to EL3 should be symmetric.
+    - Features related with profiling, debug and trace could be asymmetric
+    - Migration of vCPU/tasks between CPUs should not cause an error
+
+    Whenever there is asymmetric feature support is added for a feature TF-A need to add
+    feature specific code in context management code.
+
+ .. note::
    ``FEAT_RAS`` is an exception here, as it impacts the execution of EL3 and
    it is essential to know its presence at compile time. Refer to ``ENABLE_FEAT``
    macro under :ref:`Build Options` section for more details.
@@ -498,4 +518,4 @@
 .. |Context Init WarmBoot| image:: ../resources/diagrams/context_init_warmboot.png
 .. _Trustzone for AArch64: https://developer.arm.com/documentation/102418/0101/TrustZone-in-the-processor/Switching-between-Security-states
 .. _Security States with RME: https://developer.arm.com/documentation/den0126/0100/Security-states
-.. _lib/el3_runtime/(aarch32/aarch64): https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/lib/el3_runtime
\ No newline at end of file
+.. _lib/el3_runtime/(aarch32/aarch64): https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/lib/el3_runtime
diff --git a/docs/components/cot-binding.rst b/docs/components/cot-binding.rst
index 702bb56..1d31e3d 100644
--- a/docs/components/cot-binding.rst
+++ b/docs/components/cot-binding.rst
@@ -138,7 +138,7 @@
          trusted-key-cert: trusted-key-cert {
             root-certificate;
             image-id = <TRUSTED_KEY_CERT_ID>;
-            antirollback-counter = <&trusted_nv_counter>;
+            antirollback-counter = <&trusted_nv_ctr>;
 
             trusted-world-pk: trusted-world-pk {
                oid = TRUSTED_WORLD_PK_OID;
@@ -152,7 +152,7 @@
             image-id = <SCP_FW_KEY_CERT_ID>;
             parent = <&trusted-key-cert>;
             signing-key = <&trusted_world_pk>;
-            antirollback-counter = <&trusted_nv_counter>;
+            antirollback-counter = <&trusted_nv_ctr>;
 
             scp_fw_content_pk: scp_fw_content_pk {
                oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -312,13 +312,13 @@
         #address-cells = <1>;
         #size-cells = <0>;
 
-        trusted-nv-counter: trusted_nv_counter {
+        trusted_nv_ctr: trusted_nv_ctr {
            id  = <TRUSTED_NV_CTR_ID>;
            reg = <TFW_NVCTR_BASE>;
            oid = TRUSTED_FW_NVCOUNTER_OID;
         };
 
-        non_trusted_nv_counter: non_trusted_nv_counter {
+        non_trusted_nv_ctr: non_trusted_nv_ctr {
            id  = <NON_TRUSTED_NV_CTR_ID>;
            reg = <NTFW_CTR_BASE>;
            oid = NON_TRUSTED_FW_NVCOUNTER_OID;
diff --git a/docs/components/ffa-manifest-binding.rst b/docs/components/ffa-manifest-binding.rst
index ee322ac..29b89b2 100644
--- a/docs/components/ffa-manifest-binding.rst
+++ b/docs/components/ffa-manifest-binding.rst
@@ -1,5 +1,5 @@
 FF-A manifest binding to device tree
-========================================
+====================================
 
 This document defines the nodes and properties used to define a partition,
 according to the FF-A specification.
@@ -82,7 +82,7 @@
      the partition. Absence of this field indicates that the entry point is at
      offset 0x0 from the base of the partition's binary.
 
-- xlat-granule [mandatory]
+- xlat-granule
    - value type: <u32>
    - Translation granule used with the partition:
 
@@ -91,10 +91,10 @@
       - 0x2: 64k
 
 - boot-order
-   - value type: <u16>
+   - value type: <u32>
    - A unique number amongst all partitions that specifies if this partition
      must be booted before others. The partition with the smaller number will be
-     booted first.
+     booted first. Highest vlue allowed for this field is 0xFFFF.
 
 - rx-tx-buffer
    - value type: "memory-regions" node
@@ -103,13 +103,15 @@
      The "compatible" must be the string "arm,ffa-manifest-rx_tx-buffer".
 
 - messaging-method [mandatory]
-   - value type: <u8>
+   - value type: <u32>
    - Specifies which messaging methods are supported by the partition, set bit
      means the feature is supported, clear bit - not supported:
 
-      - Bit[0]: partition can receive direct requests if set
-      - Bit[1]: partition can send direct requests if set
+      - Bit[0]: partition can receive direct requests via FFA_MSG_SEND_DIRECT_REQ ABI if set
+      - Bit[1]: partition can send direct requests via FFA_MSG_SEND_DIRECT_REQ ABI if set
       - Bit[2]: partition can send and receive indirect messages
+      - Bit[9]: partition can receive direct requests via FFA_MSG_SEND_DIRECT_REQ2 ABI if set
+      - Bit[10]: partition can send direct requests via FFA_MSG_SEND_DIRECT_REQ2 ABI if set
 
 - managed-exit
    - value type: <empty>
@@ -117,6 +119,11 @@
    - This field is deprecated in favor of ns-interrupts-action field in the FF-A
      v1.1 EAC0 spec.
 
+- managed-exit-virq
+   - value type: <empty>
+   - Indicates if the partition needs managed exit, if supported, to be signaled
+     through vFIQ signal.
+
 - ns-interrupts-action [mandatory]
    - value type: <u32>
    - Specifies the action that the SPMC must take in response to a Non-secure
@@ -136,6 +143,12 @@
       - 0x0: Other-Secure interrupt is queued
       - 0x1: Other-Secure interrupt is signaled
 
+- runtime-model
+   - value type: <u32>
+   - Indicates whether the SP execution can be preempted.
+   - This field is deprecated in favor of other-s-interrupts-action and
+     ns-interrupts-action fields in the FF-A v1.1 spec.
+
 - has-primary-scheduler
    - value type: <empty>
    - Presence of this field indicates that the partition implements the primary
@@ -157,11 +170,6 @@
      the FF-A boot information blob to be passed in the specified general purpose
      register.
 
-- stream-endpoint-ids
-   - value type: <prop-encoded-array>
-   - List of <u32> tuples, identifying the IDs this partition is acting as
-     proxy for.
-
 - power-management-messages
    - value type: <u32>
    - Specifies which power management messages a partition subscribes to.
@@ -172,6 +180,17 @@
       - Bit[1]: CPU_SUSPEND
       - Bit[2]: CPU_SUSPEND_RESUME
 
+- vm-availability-messages
+   - value type: <u32>
+   - Specifies which VM availability messages a partition subscribes to. A set
+     bit means the partition should be informed of the event, clear bit - should
+     not be informed of event:
+
+      - Bit[0]: VM created
+      - Bit[1]: VM destroyed
+
+.. _memory_region_node:
+
 Memory Regions
 --------------
 
@@ -209,6 +228,25 @@
      then communicate the region properties (including the base address chosen
      by the partition manager) to the partition.
 
+- stream-ids
+   - value type: <prop-encoded-array>
+   - List of IDs belonging to a DMA capable peripheral device that has access to
+     the memory region represented by current node.
+   - Each ID must have been declared in exactly one device region node.
+
+- smmu-id
+   - value type: <u32>
+   - Identifies the SMMU IP that enforces the access control for the DMA device
+     that owns the above stream-ids.
+
+- stream-ids-access-permissions
+   - value type: <prop-encoded-array>
+   - List of attributes representing the instruction and data access permissions
+     used by the DMA device streams to access the memory region represented by
+     current node.
+
+.. _device_region_node:
+
 Device Regions
 --------------
 
@@ -251,11 +289,10 @@
 
 - stream-ids
    - value type: <prop-encoded-array>
-   - A list of (id, mem-manage) pair, where:
+   - List of IDs where an ID is a unique <u32> value amongst all devices assigned
+     to the partition.
 
-      - id: A unique <u32> value amongst all devices assigned to the partition.
-
-- interrupts [mandatory]
+- interrupts
    - value type: <prop-encoded-array>
    - A list of (id, attributes) pair describing the device interrupts, where:
 
@@ -306,4 +343,4 @@
 
 --------------
 
-*Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/romlib-design.rst b/docs/components/romlib-design.rst
index 62c173a..c0f3ed3 100644
--- a/docs/components/romlib-design.rst
+++ b/docs/components/romlib-design.rst
@@ -71,6 +71,15 @@
 The "library at ROM" contains a necessary init function that initialises the
 global variables defined by the functions inside "library at ROM".
 
+Wrapper functions are specified at the link stage of compilation and cannot
+interpose uppon functions within the same translation unit. For example, if
+function ``fn_a`` calls ``fn_b`` within translation unit ``functions.c`` and
+the romlib jump table includes an entry for ``fn_b``, ``fn_a`` will include
+a reference to ``fn_b``'s original program text instead of the wrapper. Thus
+the jumptable author must take care to include public entry points into
+translation units to avoid paying the program text cost twice, once in the
+original executable and once in romlib.
+
 Script
 ~~~~~~
 
@@ -86,7 +95,7 @@
 
 3. ``romlib_generator.py genwrappers [args]`` - Generates a wrapper function for
    each entry in the index file except for the ones that contain the keyword
-   ``patch``. The generated wrapper file is called ``<fn_name>.s``.
+   ``patch``. The generated wrapper file is called ``wrappers.s``.
 
 4. ``romlib_generator.py pre [args]`` - Preprocesses the index file which means
    it resolves all the include commands in the file recursively. It can also
diff --git a/docs/components/secure-partition-manager.rst b/docs/components/secure-partition-manager.rst
index b6f4219..220c3ce 100644
--- a/docs/components/secure-partition-manager.rst
+++ b/docs/components/secure-partition-manager.rst
@@ -10,42 +10,12 @@
 ========
 
 +--------+--------------------------------------+
-| CoT    | Chain of Trust                       |
-+--------+--------------------------------------+
-| DMA    | Direct Memory Access                 |
-+--------+--------------------------------------+
-| DTB    | Device Tree Blob                     |
-+--------+--------------------------------------+
 | DTS    | Device Tree Source                   |
 +--------+--------------------------------------+
-| EC     | Execution Context                    |
-+--------+--------------------------------------+
-| FIP    | Firmware Image Package               |
-+--------+--------------------------------------+
 | FF-A   | Firmware Framework for Arm A-profile |
 +--------+--------------------------------------+
-| IPA    | Intermediate Physical Address        |
-+--------+--------------------------------------+
-| JOP    | Jump-Oriented Programming            |
-+--------+--------------------------------------+
 | NWd    | Normal World                         |
 +--------+--------------------------------------+
-| ODM    | Original Design Manufacturer         |
-+--------+--------------------------------------+
-| OEM    | Original Equipment Manufacturer      |
-+--------+--------------------------------------+
-| PA     | Physical Address                     |
-+--------+--------------------------------------+
-| PE     | Processing Element                   |
-+--------+--------------------------------------+
-| PM     | Power Management                     |
-+--------+--------------------------------------+
-| PVM    | Primary VM                           |
-+--------+--------------------------------------+
-| ROP    | Return-Oriented Programming          |
-+--------+--------------------------------------+
-| SMMU   | System Memory Management Unit        |
-+--------+--------------------------------------+
 | SP     | Secure Partition                     |
 +--------+--------------------------------------+
 | SPD    | Secure Payload Dispatcher            |
@@ -56,16 +26,8 @@
 +--------+--------------------------------------+
 | SPMD   | SPM Dispatcher                       |
 +--------+--------------------------------------+
-| SiP    | Silicon Provider                     |
-+--------+--------------------------------------+
 | SWd    | Secure World                         |
 +--------+--------------------------------------+
-| TLV    | Tag-Length-Value                     |
-+--------+--------------------------------------+
-| TOS    | Trusted Operating System             |
-+--------+--------------------------------------+
-| VM     | Virtual Machine                      |
-+--------+--------------------------------------+
 
 Foreword
 ========
@@ -74,34 +36,14 @@
 codebase:
 
 #. S-EL2 SPMC based on the FF-A specification `[1]`_, enabling virtualization in
-   the secure world, managing multiple S-EL1 or S-EL0 partitions.
+   the secure world, managing multiple S-EL1 or S-EL0 partitions `[5]`_.
 #. EL3 SPMC based on the FF-A specification, managing a single S-EL1 partition
-   without virtualization in the secure world.
+   without virtualization in the secure world `[6]`_.
 #. EL3 SPM based on the MM specification, legacy implementation managing a
    single S-EL0 partition `[2]`_.
 
 These implementations differ in their respective SW architecture and only one
-can be selected at build time. This document:
-
-- describes the implementation from bullet 1. when the SPMC resides at S-EL2.
-- is not an architecture specification and it might provide assumptions
-  on sections mandated as implementation-defined in the specification.
-- covers the implications to TF-A used as a bootloader, and Hafnium used as a
-  reference code base for an S-EL2/SPMC secure firmware on platforms
-  implementing the FEAT_SEL2 architecture extension.
-
-Terminology
------------
-
-- The term Hypervisor refers to the NS-EL2 component managing Virtual Machines
-  (or partitions) in the normal world.
-- The term SPMC refers to the S-EL2 component managing secure partitions in
-  the secure world when the FEAT_SEL2 architecture extension is implemented.
-- Alternatively, SPMC can refer to an S-EL1 component, itself being a secure
-  partition and implementing the FF-A ABI on platforms not implementing the
-  FEAT_SEL2 architecture extension.
-- The term VM refers to a normal world Virtual Machine managed by an Hypervisor.
-- The term SP refers to a secure world "Virtual Machine" managed by an SPMC.
+can be selected at build time.
 
 Support for legacy platforms
 ----------------------------
@@ -123,16 +65,6 @@
 - S-EL2 SPMC for platforms implementing the FEAT_SEL2 architecture
   extension. The SPMD relays the FF-A protocol from EL3 to S-EL2.
 
-Sample reference stack
-======================
-
-The following diagram illustrates a possible configuration when the
-FEAT_SEL2 architecture extension is implemented, showing the SPMD
-and SPMC, one or multiple secure partitions, with an optional
-Hypervisor:
-
-.. image:: ../resources/diagrams/ff-a-spm-sel2.png
-
 TF-A build options
 ==================
 
@@ -147,16 +79,15 @@
   level to being at S-EL2. It defaults to enabled (value 1) when
   SPD=spmd is chosen.
 - **SPMC_AT_EL3**: this option adjusts the SPMC exception level to being
-  at EL3.
-- If neither ``SPMD_SPM_AT_SEL2`` or ``SPMC_AT_EL3`` are enabled the SPMC
-  exception level is set to S-EL1.
+  at EL3. If neither ``SPMD_SPM_AT_SEL2`` or ``SPMC_AT_EL3`` are enabled the
+  SPMC exception level is set to S-EL1.
   ``SPMD_SPM_AT_SEL2`` is enabled. The context save/restore routine
   and exhaustive list of registers is visible at `[4]`_.
 - **SPMC_AT_EL3_SEL0_SP**: this option enables the support to load SEL0 SP
   when SPMC at EL3 support is enabled.
 - **SP_LAYOUT_FILE**: this option specifies a text description file
   providing paths to SP binary images and manifests in DTS format
-  (see `Describing secure partitions`_). It
+  (see `[3]`_). It
   is required when ``SPMD_SPM_AT_SEL2`` is enabled hence when multiple
   secure partitions are to be loaded by BL2 on behalf of the SPMC.
 
@@ -275,1358 +206,28 @@
     PLAT=fvp \
     all fip
 
-FVP model invocation
-====================
-
-The FVP command line needs the following options to exercise the S-EL2 SPMC:
-
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_arm_v8-5=1                         | Implements FEAT_SEL2, FEAT_PAuth,  |
-| - cluster1.has_arm_v8-5=1                         | and FEAT_BTI.                      |
-+---------------------------------------------------+------------------------------------+
-| - pci.pci_smmuv3.mmu.SMMU_AIDR=2                  | Parameters required for the        |
-| - pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B         | SMMUv3.2 modeling.                 |
-| - pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002         |                                    |
-| - pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714             |                                    |
-| - pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472         |                                    |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002       |                                    |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR2=0                |                                    |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR3=0                |                                    |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_branch_target_exception=1          | Implements FEAT_BTI.               |
-| - cluster1.has_branch_target_exception=1          |                                    |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_pointer_authentication=2           | Implements FEAT_PAuth              |
-| - cluster1.has_pointer_authentication=2           |                                    |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.memory_tagging_support_level=2         | Implements FEAT_MTE2               |
-| - cluster1.memory_tagging_support_level=2         |                                    |
-| - bp.dram_metadata.is_enabled=1                   |                                    |
-+---------------------------------------------------+------------------------------------+
-
-Sample FVP command line invocation:
-
-.. code:: shell
-
-    <path-to-fvp-model>/FVP_Base_RevC-2xAEMvA -C pctl.startup=0.0.0.0 \
-    -C cluster0.NUM_CORES=4 -C cluster1.NUM_CORES=4 -C bp.secure_memory=1 \
-    -C bp.secureflashloader.fname=trusted-firmware-a/build/fvp/debug/bl1.bin \
-    -C bp.flashloader0.fname=trusted-firmware-a/build/fvp/debug/fip.bin \
-    -C bp.pl011_uart0.out_file=fvp-uart0.log -C bp.pl011_uart1.out_file=fvp-uart1.log \
-    -C bp.pl011_uart2.out_file=fvp-uart2.log \
-    -C cluster0.has_arm_v8-5=1 -C cluster1.has_arm_v8-5=1 \
-    -C cluster0.has_pointer_authentication=2 -C cluster1.has_pointer_authentication=2 \
-    -C cluster0.has_branch_target_exception=1 -C cluster1.has_branch_target_exception=1 \
-    -C cluster0.memory_tagging_support_level=2 -C cluster1.memory_tagging_support_level=2 \
-    -C bp.dram_metadata.is_enabled=1 \
-    -C pci.pci_smmuv3.mmu.SMMU_AIDR=2 -C pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B \
-    -C pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 -C pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 \
-    -C pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472 -C pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 \
-    -C pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 -C pci.pci_smmuv3.mmu.SMMU_S_IDR3=0
-
 Boot process
 ============
 
-Loading Hafnium and secure partitions in the secure world
----------------------------------------------------------
-
-TF-A BL2 is the bootlader for the SPMC and SPs in the secure world.
-
-SPs may be signed by different parties (SiP, OEM/ODM, TOS vendor, etc.).
-Thus they are supplied as distinct signed entities within the FIP flash
-image. The FIP image itself is not signed hence this provides the ability
-to upgrade SPs in the field.
-
-Booting through TF-A
---------------------
-
-SP manifests
-~~~~~~~~~~~~
-
-An SP manifest describes SP attributes as defined in `[1]`_
-(partition manifest at virtual FF-A instance) in DTS format. It is
-represented as a single file associated with the SP. A sample is
-provided by `[5]`_. A binding document is provided by `[6]`_.
-
-Secure Partition packages
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Secure partitions are bundled as independent package files consisting
-of:
-
-- a header
-- a DTB
-- an image payload
-
-The header starts with a magic value and offset values to SP DTB and
-image payload. Each SP package is loaded independently by BL2 loader
-and verified for authenticity and integrity.
-
-The SP package identified by its UUID (matching FF-A uuid property) is
-inserted as a single entry into the FIP at end of the TF-A build flow
-as shown:
-
-.. code:: shell
-
-    Trusted Boot Firmware BL2: offset=0x1F0, size=0x8AE1, cmdline="--tb-fw"
-    EL3 Runtime Firmware BL31: offset=0x8CD1, size=0x13000, cmdline="--soc-fw"
-    Secure Payload BL32 (Trusted OS): offset=0x1BCD1, size=0x15270, cmdline="--tos-fw"
-    Non-Trusted Firmware BL33: offset=0x30F41, size=0x92E0, cmdline="--nt-fw"
-    HW_CONFIG: offset=0x3A221, size=0x2348, cmdline="--hw-config"
-    TB_FW_CONFIG: offset=0x3C569, size=0x37A, cmdline="--tb-fw-config"
-    SOC_FW_CONFIG: offset=0x3C8E3, size=0x48, cmdline="--soc-fw-config"
-    TOS_FW_CONFIG: offset=0x3C92B, size=0x427, cmdline="--tos-fw-config"
-    NT_FW_CONFIG: offset=0x3CD52, size=0x48, cmdline="--nt-fw-config"
-    B4B5671E-4A90-4FE1-B81F-FB13DAE1DACB: offset=0x3CD9A, size=0xC168, cmdline="--blob"
-    D1582309-F023-47B9-827C-4464F5578FC8: offset=0x48F02, size=0xC168, cmdline="--blob"
-
-.. uml:: ../resources/diagrams/plantuml/fip-secure-partitions.puml
-
-Describing secure partitions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A json-formatted description file is passed to the build flow specifying paths
-to the SP binary image and associated DTS partition manifest file. The latter
-is processed by the dtc compiler to generate a DTB fed into the SP package.
-Optionally, the partition's json description can contain offsets for both
-the image and partition manifest within the SP package. Both offsets need to be
-4KB aligned, because it is the translation granule supported by Hafnium SPMC.
-These fields can be leveraged to support SPs with S1 translation granules that
-differ from 4KB, and to configure the regions allocated within the SP package,
-as well as to comply with the requirements for the implementation of the boot
-information protocol (see `Passing boot data to the SP`_ for more details). In
-case the offsets are absent in their json node, they default to 0x1000 and
-0x4000 for the manifest offset and image offset respectively.
-This file also specifies the SP owner (as an optional field) identifying the
-signing domain in case of dual root CoT.
-The SP owner can either be the silicon or the platform provider. The
-corresponding "owner" field value can either take the value of "SiP" or "Plat".
-In absence of "owner" field, it defaults to "SiP" owner.
-The UUID of the partition can be specified as a field in the description file or
-if it does not exist there the UUID is extracted from the DTS partition
-manifest.
-
-.. code:: shell
-
-    {
-        "tee1" : {
-            "image": "tee1.bin",
-             "pm": "tee1.dts",
-             "owner": "SiP",
-             "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
-        },
-
-        "tee2" : {
-            "image": "tee2.bin",
-            "pm": "tee2.dts",
-            "owner": "Plat"
-        },
-
-        "tee3" : {
-            "image": {
-                "file": "tee3.bin",
-                "offset":"0x2000"
-             },
-            "pm": {
-                "file": "tee3.dts",
-                "offset":"0x6000"
-             },
-            "owner": "Plat"
-        },
-    }
-
-SPMC manifest
-~~~~~~~~~~~~~
-
-This manifest contains the SPMC *attribute* node consumed by the SPMD at boot
-time. It implements `[1]`_ (SP manifest at physical FF-A instance) and serves
-two different cases:
-
-- The SPMC resides at S-EL1: the SPMC manifest is used by the SPMD to setup a
-  SP that co-resides with the SPMC and executes at S-EL1 or Secure Supervisor
-  mode.
-- The SPMC resides at S-EL2: the SPMC manifest is used by the SPMD to setup
-  the environment required by the SPMC to run at S-EL2. SPs run at S-EL1 or
-  S-EL0.
-
-.. code:: shell
-
-    attribute {
-        spmc_id = <0x8000>;
-        maj_ver = <0x1>;
-        min_ver = <0x1>;
-        exec_state = <0x0>;
-        load_address = <0x0 0x6000000>;
-        entrypoint = <0x0 0x6000000>;
-        binary_size = <0x60000>;
-    };
-
-- *spmc_id* defines the endpoint ID value that SPMC can query through
-  ``FFA_ID_GET``.
-- *maj_ver/min_ver*. SPMD checks provided version versus its internal
-  version and aborts if not matching.
-- *exec_state* defines the SPMC execution state (AArch64 or AArch32).
-  Notice Hafnium used as a SPMC only supports AArch64.
-- *load_address* and *binary_size* are mostly used to verify secondary
-  entry points fit into the loaded binary image.
-- *entrypoint* defines the cold boot primary core entry point used by
-  SPMD (currently matches ``BL32_BASE``) to enter the SPMC.
-
-Other nodes in the manifest are consumed by Hafnium in the secure world.
-A sample can be found at `[7]`_:
-
-- The *hypervisor* node describes SPs. *is_ffa_partition* boolean attribute
-  indicates a FF-A compliant SP. The *load_address* field specifies the load
-  address at which BL2 loaded the SP package.
-- *cpus* node provide the platform topology and allows MPIDR to VMPIDR mapping.
-  Note the primary core is declared first, then secondary cores are declared
-  in reverse order.
-- The *memory* nodes provide platform information on the ranges of memory
-  available for use by SPs at runtime. These ranges relate to either
-  secure or non-secure memory, depending on the *device_type* field.
-  If the field specifies "memory" the range is secure, else if it specifies
-  "ns-memory" the memory is non-secure. The system integrator must exclude
-  the memory used by other components that are not SPs, such as the monitor,
-  or the SPMC itself, the OS Kernel/Hypervisor, or other NWd VMs. The SPMC
-  limits the SP's address space such that they do not access memory outside
-  of those ranges.
+The boot process involving SPMC is highly dependent on the SPMC implementation.
+It is recommended to refer to corresponding SPMC documentation for further
+details. Some aspects of boot process are described here in the greater interest
+of the project.
 
 SPMC boot
-~~~~~~~~~
+---------
 
-The SPMC is loaded by BL2 as the BL32 image.
+When SPMC resides at a lower EL i.e., S-EL1 or S-EL2, it is loaded by BL2 as the
+BL32 image. The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[7]`_.
 
-The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[9]`_.
-
-BL2 passes the SPMC manifest address to BL31 through a register.
-
-At boot time, the SPMD in BL31 runs from the primary core, initializes the core
-contexts and launches the SPMC (BL32) passing the following information through
-registers:
+BL2 passes the SPMC manifest address to BL31 through a register. At boot time,
+the SPMD in BL31 runs from the primary core, initializes the core contexts and
+launches the SPMC (BL32) passing the following information through registers:
 
 - X0 holds the ``TOS_FW_CONFIG`` physical address (or SPMC manifest blob).
 - X1 holds the ``HW_CONFIG`` physical address.
 - X4 holds the currently running core linear id.
 
-Loading of SPs
-~~~~~~~~~~~~~~
-
-At boot time, BL2 loads SPs sequentially in addition to the SPMC as depicted
-below:
-
-.. uml:: ../resources/diagrams/plantuml/bl2-loading-sp.puml
-
-Note this boot flow is an implementation sample on Arm's FVP platform.
-Platforms not using TF-A's *Firmware CONFiguration* framework would adjust to a
-different boot flow. The flow restricts to a maximum of 8 secure partitions.
-
-Secure boot
-~~~~~~~~~~~
-
-The SP content certificate is inserted as a separate FIP item so that BL2 loads SPMC,
-SPMC manifest, secure partitions and verifies them for authenticity and integrity.
-Refer to TBBR specification `[3]`_.
-
-The multiple-signing domain feature (in current state dual signing domain `[8]`_) allows
-the use of two root keys namely S-ROTPK and NS-ROTPK:
-
-- SPMC (BL32) and SPMC manifest are signed by the SiP using the S-ROTPK.
-- BL33 may be signed by the OEM using NS-ROTPK.
-- An SP may be signed either by SiP (using S-ROTPK) or by OEM (using NS-ROTPK).
-- A maximum of 4 partitions can be signed with the S-ROTPK key and 4 partitions
-  signed with the NS-ROTPK key.
-
-Also refer to `Describing secure partitions`_ and `TF-A build options`_ sections.
-
-Hafnium in the secure world
-===========================
-
-General considerations
-----------------------
-
-Build platform for the secure world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In the Hafnium reference implementation specific code parts are only relevant to
-the secure world. Such portions are isolated in architecture specific files
-and/or enclosed by a ``SECURE_WORLD`` macro.
-
-Secure partitions scheduling
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The FF-A specification `[1]`_ provides two ways to relinquinsh CPU time to
-secure partitions. For this a VM (Hypervisor or OS kernel), or SP invokes one of:
-
-- the FFA_MSG_SEND_DIRECT_REQ interface.
-- the FFA_RUN interface.
-
-Additionally a secure interrupt can pre-empt the normal world execution and give
-CPU cycles by transitioning to EL3 and S-EL2.
-
-Platform topology
-~~~~~~~~~~~~~~~~~
-
-The *execution-ctx-count* SP manifest field can take the value of one or the
-total number of PEs. The FF-A specification `[1]`_  recommends the
-following SP types:
-
-- Pinned MP SPs: an execution context matches a physical PE. MP SPs must
-  implement the same number of ECs as the number of PEs in the platform.
-- Migratable UP SPs: a single execution context can run and be migrated on any
-  physical PE. Such SP declares a single EC in its SP manifest. An UP SP can
-  receive a direct message request originating from any physical core targeting
-  the single execution context.
-
-Parsing SP partition manifests
-------------------------------
-
-Hafnium consumes SP manifests as defined in `[1]`_ and `SP manifests`_.
-Note the current implementation may not implement all optional fields.
-
-The SP manifest may contain memory and device regions nodes. In case of
-an S-EL2 SPMC:
-
-- Memory regions are mapped in the SP EL1&0 Stage-2 translation regime at
-  load time (or EL1&0 Stage-1 for an S-EL1 SPMC). A memory region node can
-  specify RX/TX buffer regions in which case it is not necessary for an SP
-  to explicitly invoke the ``FFA_RXTX_MAP`` interface. The memory referred
-  shall be contained within the memory ranges defined in SPMC manifest. The
-  NS bit in the attributes field should be consistent with the security
-  state of the range that it relates to. I.e. non-secure memory shall be
-  part of a non-secure memory range, and secure memory shall be contained
-  in a secure memory range of a given platform.
-- Device regions are mapped in the SP EL1&0 Stage-2 translation regime (or
-  EL1&0 Stage-1 for an S-EL1 SPMC) as peripherals and possibly allocate
-  additional resources (e.g. interrupts).
-
-For the S-EL2 SPMC, base addresses for memory and device region nodes are IPAs
-provided the SPMC identity maps IPAs to PAs within SP EL1&0 Stage-2 translation
-regime.
-
-Note: in the current implementation both VTTBR_EL2 and VSTTBR_EL2 point to the
-same set of page tables. It is still open whether two sets of page tables shall
-be provided per SP. The memory region node as defined in the specification
-provides a memory security attribute hinting to map either to the secure or
-non-secure EL1&0 Stage-2 table if it exists.
-
-Passing boot data to the SP
----------------------------
-
-In `[1]`_ , the section  "Boot information protocol" defines a method for passing
-data to the SPs at boot time. It specifies the format for the boot information
-descriptor and boot information header structures, which describe the data to be
-exchanged between SPMC and SP.
-The specification also defines the types of data that can be passed.
-The aggregate of both the boot info structures and the data itself is designated
-the boot information blob, and is passed to a Partition as a contiguous memory
-region.
-
-Currently, the SPM implementation supports the FDT type which is used to pass the
-partition's DTB manifest.
-
-The region for the boot information blob is allocated through the SP package.
-
-.. image:: ../resources/diagrams/partition-package.png
-
-To adjust the space allocated for the boot information blob, the json description
-of the SP (see section `Describing secure partitions`_) shall be updated to contain
-the manifest offset. If no offset is provided the manifest offset defaults to 0x1000,
-which is the page size in the Hafnium SPMC.
-
-The configuration of the boot protocol is done in the SPs manifest. As defined by
-the specification, the manifest field 'gp-register-num' configures the GP register
-which shall be used to pass the address to the partitions boot information blob when
-booting the partition.
-In addition, the Hafnium SPMC implementation requires the boot information arguments
-to be listed in a designated DT node:
-
-.. code:: shell
-
-  boot-info {
-      compatible = "arm,ffa-manifest-boot-info";
-      ffa_manifest;
-  };
-
-The whole secure partition package image (see `Secure Partition packages`_) is
-mapped to the SP secure EL1&0 Stage-2 translation regime. As such, the SP can
-retrieve the address for the boot information blob in the designated GP register,
-process the boot information header and descriptors, access its own manifest
-DTB blob and extract its partition manifest properties.
-
-SP Boot order
--------------
-
-SP manifests provide an optional boot order attribute meant to resolve
-dependencies such as an SP providing a service required to properly boot
-another SP. SPMC boots the SPs in accordance to the boot order attribute,
-lowest to the highest value. If the boot order attribute is absent from the FF-A
-manifest, the SP is treated as if it had the highest boot order value
-(i.e. lowest booting priority).
-
-It is possible for an SP to call into another SP through a direct request
-provided the latter SP has already been booted.
-
-Boot phases
------------
-
-Primary core boot-up
-~~~~~~~~~~~~~~~~~~~~
-
-Upon boot-up, BL31 hands over to the SPMC (BL32) on the primary boot physical
-core. The SPMC performs its platform initializations and registers the SPMC
-secondary physical core entry point physical address by the use of the
-`FFA_SECONDARY_EP_REGISTER`_ interface (SMC invocation from the SPMC to the SPMD
-at secure physical FF-A instance).
-
-The SPMC then creates secure partitions based on SP packages and manifests. Each
-secure partition is launched in sequence (`SP Boot order`_) on their "primary"
-execution context. If the primary boot physical core linear id is N, an MP SP is
-started using EC[N] on PE[N] (see `Platform topology`_). If the partition is a
-UP SP, it is started using its unique EC0 on PE[N].
-
-The SP primary EC (or the EC used when the partition is booted as described
-above):
-
-- Performs the overall SP boot time initialization, and in case of a MP SP,
-  prepares the SP environment for other execution contexts.
-- In the case of a MP SP, it invokes the FFA_SECONDARY_EP_REGISTER at secure
-  virtual FF-A instance (SMC invocation from SP to SPMC) to provide the IPA
-  entry point for other execution contexts.
-- Exits through ``FFA_MSG_WAIT`` to indicate successful initialization or
-  ``FFA_ERROR`` in case of failure.
-
-Secondary cores boot-up
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Once the system is started and NWd brought up, a secondary physical core is
-woken up by the ``PSCI_CPU_ON`` service invocation. The TF-A SPD hook mechanism
-calls into the SPMD on the newly woken up physical core. Then the SPMC is
-entered at the secondary physical core entry point.
-
-In the current implementation, the first SP is resumed on the coresponding EC
-(the virtual CPU which matches the physical core). The implication is that the
-first SP must be a MP SP.
-
-In a linux based system, once secure and normal worlds are booted but prior to
-a NWd FF-A driver has been loaded:
-
-- The first SP has initialized all its ECs in response to primary core boot up
-  (at system initialization) and secondary core boot up (as a result of linux
-  invoking PSCI_CPU_ON for all secondary cores).
-- Other SPs have their first execution context initialized as a result of secure
-  world initialization on the primary boot core. Other ECs for those SPs have to
-  be run first through ffa_run to complete their initialization (which results
-  in the EC completing with FFA_MSG_WAIT).
-
-Refer to `Power management`_ for further details.
-
-Notifications
--------------
-
-The FF-A v1.1 specification `[1]`_ defines notifications as an asynchronous
-communication mechanism with non-blocking semantics. It allows for one FF-A
-endpoint to signal another for service provision, without hindering its current
-progress.
-
-Hafnium currently supports 64 notifications. The IDs of each notification define
-a position in a 64-bit bitmap.
-
-The signaling of notifications can interchangeably happen between NWd and SWd
-FF-A endpoints.
-
-The SPMC is in charge of managing notifications from SPs to SPs, from SPs to
-VMs, and from VMs to SPs. An hypervisor component would only manage
-notifications from VMs to VMs. Given the SPMC has no visibility of the endpoints
-deployed in NWd, the Hypervisor or OS kernel must invoke the interface
-FFA_NOTIFICATION_BITMAP_CREATE to allocate the notifications bitmap per FF-A
-endpoint in the NWd that supports it.
-
-A sender can signal notifications once the receiver has provided it with
-permissions. Permissions are provided by invoking the interface
-FFA_NOTIFICATION_BIND.
-
-Notifications are signaled by invoking FFA_NOTIFICATION_SET. Henceforth
-they are considered to be in a pending sate. The receiver can retrieve its
-pending notifications invoking FFA_NOTIFICATION_GET, which, from that moment,
-are considered to be handled.
-
-Per the FF-A v1.1 spec, each FF-A endpoint must be associated with a scheduler
-that is in charge of donating CPU cycles for notifications handling. The
-FF-A driver calls FFA_NOTIFICATION_INFO_GET to retrieve the information about
-which FF-A endpoints have pending notifications. The receiver scheduler is
-called and informed by the FF-A driver, and it should allocate CPU cycles to the
-receiver.
-
-There are two types of notifications supported:
-
-- Global, which are targeted to a FF-A endpoint and can be handled within any of
-  its execution contexts, as determined by the scheduler of the system.
-- Per-vCPU, which are targeted to a FF-A endpoint and to be handled within a
-  a specific execution context, as determined by the sender.
-
-The type of a notification is set when invoking FFA_NOTIFICATION_BIND to give
-permissions to the sender.
-
-Notification signaling resorts to two interrupts:
-
-- Schedule Receiver Interrupt: non-secure physical interrupt to be handled by
-  the FF-A driver within the receiver scheduler. At initialization the SPMC
-  donates a SGI ID chosen from the secure SGI IDs range and configures it as
-  non-secure. The SPMC triggers this SGI on the currently running core when
-  there are pending notifications, and the respective receivers need CPU cycles
-  to handle them.
-- Notifications Pending Interrupt: virtual interrupt to be handled by the
-  receiver of the notification. Set when there are pending notifications for the
-  given secure partition. The NPI is pended when the NWd relinquishes CPU cycles
-  to an SP.
-
-The notifications receipt support is enabled in the partition FF-A manifest.
-
-Mandatory interfaces
---------------------
-
-The following interfaces are exposed to SPs:
-
--  ``FFA_VERSION``
--  ``FFA_FEATURES``
--  ``FFA_RX_RELEASE``
--  ``FFA_RXTX_MAP``
--  ``FFA_RXTX_UNMAP``
--  ``FFA_PARTITION_INFO_GET``
--  ``FFA_ID_GET``
--  ``FFA_MSG_WAIT``
--  ``FFA_MSG_SEND_DIRECT_REQ``
--  ``FFA_MSG_SEND_DIRECT_RESP``
--  ``FFA_MEM_DONATE``
--  ``FFA_MEM_LEND``
--  ``FFA_MEM_SHARE``
--  ``FFA_MEM_RETRIEVE_REQ``
--  ``FFA_MEM_RETRIEVE_RESP``
--  ``FFA_MEM_RELINQUISH``
--  ``FFA_MEM_FRAG_RX``
--  ``FFA_MEM_FRAG_TX``
--  ``FFA_MEM_RECLAIM``
--  ``FFA_RUN``
-
-As part of the FF-A v1.1 support, the following interfaces were added:
-
- - ``FFA_NOTIFICATION_BITMAP_CREATE``
- - ``FFA_NOTIFICATION_BITMAP_DESTROY``
- - ``FFA_NOTIFICATION_BIND``
- - ``FFA_NOTIFICATION_UNBIND``
- - ``FFA_NOTIFICATION_SET``
- - ``FFA_NOTIFICATION_GET``
- - ``FFA_NOTIFICATION_INFO_GET``
- - ``FFA_SPM_ID_GET``
- - ``FFA_SECONDARY_EP_REGISTER``
- - ``FFA_MEM_PERM_GET``
- - ``FFA_MEM_PERM_SET``
- - ``FFA_MSG_SEND2``
- - ``FFA_RX_ACQUIRE``
-
-FFA_VERSION
-~~~~~~~~~~~
-
-``FFA_VERSION`` requires a *requested_version* parameter from the caller.
-The returned value depends on the caller:
-
-- Hypervisor or OS kernel in NS-EL1/EL2: the SPMD returns the SPMC version
-  specified in the SPMC manifest.
-- SP: the SPMC returns its own implemented version.
-- SPMC at S-EL1/S-EL2: the SPMD returns its own implemented version.
-
-FFA_FEATURES
-~~~~~~~~~~~~
-
-FF-A features supported by the SPMC may be discovered by secure partitions at
-boot (that is prior to NWd is booted) or run-time.
-
-The SPMC calling FFA_FEATURES at secure physical FF-A instance always get
-FFA_SUCCESS from the SPMD.
-
-The request made by an Hypervisor or OS kernel is forwarded to the SPMC and
-the response relayed back to the NWd.
-
-FFA_RXTX_MAP/FFA_RXTX_UNMAP
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When invoked from a secure partition FFA_RXTX_MAP maps the provided send and
-receive buffers described by their IPAs to the SP EL1&0 Stage-2 translation
-regime as secure buffers in the MMU descriptors.
-
-When invoked from the Hypervisor or OS kernel, the buffers are mapped into the
-SPMC EL2 Stage-1 translation regime and marked as NS buffers in the MMU
-descriptors. The provided addresses may be owned by a VM in the normal world,
-which is expected to receive messages from the secure world. The SPMC will in
-this case allocate internal state structures to facilitate RX buffer access
-synchronization (through FFA_RX_ACQUIRE interface), and to permit SPs to send
-messages.
-
-The FFA_RXTX_UNMAP unmaps the RX/TX pair from the translation regime of the
-caller, either it being the Hypervisor or OS kernel, as well as a secure
-partition.
-
-FFA_PARTITION_INFO_GET
-~~~~~~~~~~~~~~~~~~~~~~
-
-Partition info get call can originate:
-
-- from SP to SPMC
-- from Hypervisor or OS kernel to SPMC. The request is relayed by the SPMD.
-
-FFA_ID_GET
-~~~~~~~~~~
-
-The FF-A id space is split into a non-secure space and secure space:
-
-- FF-A ID with bit 15 clear relates to VMs.
-- FF-A ID with bit 15 set related to SPs.
-- FF-A IDs 0, 0xffff, 0x8000 are assigned respectively to the Hypervisor, SPMD
-  and SPMC.
-
-The SPMD returns:
-
-- The default zero value on invocation from the Hypervisor.
-- The ``spmc_id`` value specified in the SPMC manifest on invocation from
-  the SPMC (see `SPMC manifest`_)
-
-This convention helps the SPMC to determine the origin and destination worlds in
-an FF-A ABI invocation. In particular the SPMC shall filter unauthorized
-transactions in its world switch routine. It must not be permitted for a VM to
-use a secure FF-A ID as origin world by spoofing:
-
-- A VM-to-SP direct request/response shall set the origin world to be non-secure
-  (FF-A ID bit 15 clear) and destination world to be secure (FF-A ID bit 15
-  set).
-- Similarly, an SP-to-SP direct request/response shall set the FF-A ID bit 15
-  for both origin and destination IDs.
-
-An incoming direct message request arriving at SPMD from NWd is forwarded to
-SPMC without a specific check. The SPMC is resumed through eret and "knows" the
-message is coming from normal world in this specific code path. Thus the origin
-endpoint ID must be checked by SPMC for being a normal world ID.
-
-An SP sending a direct message request must have bit 15 set in its origin
-endpoint ID and this can be checked by the SPMC when the SP invokes the ABI.
-
-The SPMC shall reject the direct message if the claimed world in origin endpoint
-ID is not consistent:
-
--  It is either forwarded by SPMD and thus origin endpoint ID must be a "normal
-   world ID",
--  or initiated by an SP and thus origin endpoint ID must be a "secure world ID".
-
-
-FFA_MSG_SEND_DIRECT_REQ/FFA_MSG_SEND_DIRECT_RESP
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This is a mandatory interface for secure partitions consisting in direct request
-and responses with the following rules:
-
-- An SP can send a direct request to another SP.
-- An SP can receive a direct request from another SP.
-- An SP can send a direct response to another SP.
-- An SP cannot send a direct request to an Hypervisor or OS kernel.
-- An Hypervisor or OS kernel can send a direct request to an SP.
-- An SP can send a direct response to an Hypervisor or OS kernel.
-
-FFA_NOTIFICATION_BITMAP_CREATE/FFA_NOTIFICATION_BITMAP_DESTROY
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The secure partitions notifications bitmap are statically allocated by the SPMC.
-Hence, this interface is not to be issued by secure partitions.
-
-At initialization, the SPMC is not aware of VMs/partitions deployed in the
-normal world. Hence, the Hypervisor or OS kernel must use both ABIs for SPMC
-to be prepared to handle notifications for the provided VM ID.
-
-FFA_NOTIFICATION_BIND/FFA_NOTIFICATION_UNBIND
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Pair of interfaces to manage permissions to signal notifications. Prior to
-handling notifications, an FF-A endpoint must allow a given sender to signal a
-bitmap of notifications.
-
-If the receiver doesn't have notification support enabled in its FF-A manifest,
-it won't be able to bind notifications, hence forbidding it to receive any
-notifications.
-
-FFA_NOTIFICATION_SET/FFA_NOTIFICATION_GET
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-FFA_NOTIFICATION_GET retrieves all pending global notifications and
-per-vCPU notifications targeted to the current vCPU.
-
-Hafnium maintains a global count of pending notifications which gets incremented
-and decremented when handling FFA_NOTIFICATION_SET and FFA_NOTIFICATION_GET
-respectively. A delayed SRI is triggered if the counter is non-zero when the
-SPMC returns to normal world.
-
-FFA_NOTIFICATION_INFO_GET
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Hafnium maintains a global count of pending notifications whose information
-has been retrieved by this interface. The count is incremented and decremented
-when handling FFA_NOTIFICATION_INFO_GET and FFA_NOTIFICATION_GET respectively.
-It also tracks notifications whose information has been retrieved individually,
-such that it avoids duplicating returned information for subsequent calls to
-FFA_NOTIFICATION_INFO_GET. For each notification, this state information is
-reset when receiver called FFA_NOTIFICATION_GET to retrieve them.
-
-FFA_SPM_ID_GET
-~~~~~~~~~~~~~~
-
-Returns the FF-A ID allocated to an SPM component which can be one of SPMD
-or SPMC.
-
-At initialization, the SPMC queries the SPMD for the SPMC ID, using the
-FFA_ID_GET interface, and records it. The SPMC can also query the SPMD ID using
-the FFA_SPM_ID_GET interface at the secure physical FF-A instance.
-
-Secure partitions call this interface at the virtual FF-A instance, to which
-the SPMC returns the priorly retrieved SPMC ID.
-
-The Hypervisor or OS kernel can issue the FFA_SPM_ID_GET call handled by the
-SPMD, which returns the SPMC ID.
-
-FFA_SECONDARY_EP_REGISTER
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When the SPMC boots, all secure partitions are initialized on their primary
-Execution Context.
-
-The FFA_SECONDARY_EP_REGISTER interface is to be used by a secure partition
-from its first execution context, to provide the entry point address for
-secondary execution contexts.
-
-A secondary EC is first resumed either upon invocation of PSCI_CPU_ON from
-the NWd or by invocation of FFA_RUN.
-
-FFA_RX_ACQUIRE/FFA_RX_RELEASE
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The RX buffers can be used to pass information to an FF-A endpoint in the
-following scenarios:
-
- - When it was targetted by a FFA_MSG_SEND2 invokation from another endpoint.
- - Return the result of calling ``FFA_PARTITION_INFO_GET``.
- - In a memory share operation, as part of the ``FFA_MEM_RETRIEVE_RESP``,
-   with the memory descriptor of the shared memory.
-
-If a normal world VM is expected to exchange messages with secure world,
-its RX/TX buffer addresses are forwarded to the SPMC via FFA_RXTX_MAP ABI,
-and are from this moment owned by the SPMC.
-The hypervisor must call the FFA_RX_ACQUIRE interface before attempting
-to use the RX buffer, in any of the aforementioned scenarios. A successful
-call to FFA_RX_ACQUIRE transfers ownership of RX buffer to hypervisor, such
-that it can be safely used.
-
-The FFA_RX_RELEASE interface is used after the FF-A endpoint is done with
-processing the data received in its RX buffer. If the RX buffer has been
-acquired by the hypervisor, the FFA_RX_RELEASE call must be forwarded to
-the SPMC to reestablish SPMC's RX ownership.
-
-An attempt from an SP to send a message to a normal world VM whose RX buffer
-was acquired by the hypervisor fails with error code FFA_BUSY, to preserve
-the RX buffer integrity.
-The operation could then be conducted after FFA_RX_RELEASE.
-
-FFA_MSG_SEND2
-~~~~~~~~~~~~~
-
-Hafnium copies a message from the sender TX buffer into receiver's RX buffer.
-For messages from SPs to VMs, operation is only possible if the SPMC owns
-the receiver's RX buffer.
-
-Both receiver and sender need to enable support for indirect messaging,
-in their respective partition manifest. The discovery of support
-of such feature can be done via FFA_PARTITION_INFO_GET.
-
-On a successful message send, Hafnium pends an RX buffer full framework
-notification for the receiver, to inform it about a message in the RX buffer.
-
-The handling of framework notifications is similar to that of
-global notifications. Binding of these is not necessary, as these are
-reserved to be used by the hypervisor or SPMC.
-
-SPMC-SPMD direct requests/responses
------------------------------------
-
-Implementation-defined FF-A IDs are allocated to the SPMC and SPMD.
-Using those IDs in source/destination fields of a direct request/response
-permits SPMD to SPMC communication and either way.
-
-- SPMC to SPMD direct request/response uses SMC conduit.
-- SPMD to SPMC direct request/response uses ERET conduit.
-
-This is used in particular to convey power management messages.
-
-Memory Sharing
---------------
-
-Hafnium implements the following memory sharing interfaces:
-
- - ``FFA_MEM_SHARE`` - for shared access between lender and borrower.
- - ``FFA_MEM_LEND`` - borrower to obtain exclusive access, though lender
-   retains ownership of the memory.
- - ``FFA_MEM_DONATE`` - lender permanently relinquishes ownership of memory
-   to the borrower.
-
-The ``FFA_MEM_RETRIEVE_REQ`` interface is for the borrower to request the
-memory to be mapped into its address space: for S-EL1 partitions the SPM updates
-their stage 2 translation regime; for S-EL0 partitions the SPM updates their
-stage 1 translation regime. On a successful call, the SPMC responds back with
-``FFA_MEM_RETRIEVE_RESP``.
-
-The ``FFA_MEM_RELINQUISH`` interface is for when the borrower is done with using
-a memory region.
-
-The ``FFA_MEM_RECLAIM`` interface is for the owner of the memory to reestablish
-its ownership and exclusive access to the memory shared.
-
-The memory transaction descriptors are transmitted via RX/TX buffers. In
-situations where the size of the memory transaction descriptor exceeds the
-size of the RX/TX buffers, Hafnium provides support for fragmented transmission
-of the full transaction descriptor. The ``FFA_MEM_FRAG_RX`` and ``FFA_MEM_FRAG_TX``
-interfaces are for receiving and transmitting the next fragment, respectively.
-
-If lender and borrower(s) are SPs, all memory sharing operations are supported.
-
-Hafnium also supports memory sharing operations between the normal world and the
-secure world. If there is an SP involved, the SPMC allocates data to track the
-state of the operation.
-
-The SPMC is also the designated allocator for the memory handle. The hypervisor
-or OS kernel has the possibility to rely on the SPMC to maintain the state
-of the operation, thus saving memory.
-A lender SP can only donate NS memory to a borrower from the normal world.
-
-The SPMC supports the hypervisor retrieve request, as defined by the FF-A
-v1.1 EAC0 specification, in section 16.4.3. The intent is to aid with operations
-that the hypervisor must do for a VM retriever. For example, when handling
-an FFA_MEM_RECLAIM, if the hypervisor relies on SPMC to keep the state
-of the operation, the hypervisor retrieve request can be used to obtain
-that state information, do the necessary validations, and update stage 2
-memory translation.
-
-Hafnium also supports memory lend and share targetting multiple borrowers.
-This is the case for a lender SP to multiple SPs, and for a lender VM to
-multiple endpoints (from both secure world and normal world). If there is
-at least one borrower VM, the hypervisor is in charge of managing its
-stage 2 translation on a successful memory retrieve.
-The semantics of ``FFA_MEM_DONATE`` implies ownership transmission,
-which should target only one partition.
-
-The memory share interfaces are backwards compatible with memory transaction
-descriptors from FF-A v1.0. These get translated to FF-A v1.1 descriptors for
-Hafnium's internal processing of the operation. If the FF-A version of a
-borrower is v1.0, Hafnium provides FF-A v1.0 compliant memory transaction
-descriptors on memory retrieve response.
-
-PE MMU configuration
---------------------
-
-With secure virtualization enabled (``HCR_EL2.VM = 1``) and for S-EL1
-partitions, two IPA spaces (secure and non-secure) are output from the
-secure EL1&0 Stage-1 translation.
-The EL1&0 Stage-2 translation hardware is fed by:
-
-- A secure IPA when the SP EL1&0 Stage-1 MMU is disabled.
-- One of secure or non-secure IPA when the secure EL1&0 Stage-1 MMU is enabled.
-
-``VTCR_EL2`` and ``VSTCR_EL2`` provide configuration bits for controlling the
-NS/S IPA translations. The following controls are set up:
-``VSTCR_EL2.SW = 0`` , ``VSTCR_EL2.SA = 0``, ``VTCR_EL2.NSW = 0``,
-``VTCR_EL2.NSA = 1``:
-
-- Stage-2 translations for the NS IPA space access the NS PA space.
-- Stage-2 translation table walks for the NS IPA space are to the secure PA space.
-
-Secure and non-secure IPA regions (rooted to by ``VTTBR_EL2`` and ``VSTTBR_EL2``)
-use the same set of Stage-2 page tables within a SP.
-
-The ``VTCR_EL2/VSTCR_EL2/VTTBR_EL2/VSTTBR_EL2`` virtual address space
-configuration is made part of a vCPU context.
-
-For S-EL0 partitions with VHE enabled, a single secure EL2&0 Stage-1 translation
-regime is used for both Hafnium and the partition.
-
-Schedule modes and SP Call chains
----------------------------------
-
-An SP execution context is said to be in SPMC scheduled mode if CPU cycles are
-allocated to it by SPMC. Correspondingly, an SP execution context is said to be
-in Normal world scheduled mode if CPU cycles are allocated by the normal world.
-
-A call chain represents all SPs in a sequence of invocations of a direct message
-request. When execution on a PE is in the secure state, only a single call chain
-that runs in the Normal World scheduled mode can exist. FF-A v1.1 spec allows
-any number of call chains to run in the SPMC scheduled mode but the Hafnium
-SPMC restricts the number of call chains in SPMC scheduled mode to only one for
-keeping the implementation simple.
-
-Partition runtime models
-------------------------
-
-The runtime model of an endpoint describes the transitions permitted for an
-execution context between various states. These are the four partition runtime
-models supported (refer to `[1]`_ section 7):
-
-  - RTM_FFA_RUN: runtime model presented to an execution context that is
-    allocated CPU cycles through FFA_RUN interface.
-  - RTM_FFA_DIR_REQ: runtime model presented to an execution context that is
-    allocated CPU cycles through FFA_MSG_SEND_DIRECT_REQ interface.
-  - RTM_SEC_INTERRUPT: runtime model presented to an execution context that is
-    allocated CPU cycles by SPMC to handle a secure interrupt.
-  - RTM_SP_INIT: runtime model presented to an execution context that is
-    allocated CPU cycles by SPMC to initialize its state.
-
-If an endpoint execution context attempts to make an invalid transition or a
-valid transition that could lead to a loop in the call chain, SPMC denies the
-transition with the help of above runtime models.
-
-Interrupt management
---------------------
-
-GIC ownership
-~~~~~~~~~~~~~
-
-The SPMC owns the GIC configuration. Secure and non-secure interrupts are
-trapped at S-EL2. The SPMC manages interrupt resources and allocates interrupt
-IDs based on SP manifests. The SPMC acknowledges physical interrupts and injects
-virtual interrupts by setting the use of vIRQ/vFIQ bits before resuming a SP.
-
-Abbreviations:
-
-  - NS-Int: A non-secure physical interrupt. It requires a switch to the normal
-    world to be handled if it triggers while execution is in secure world.
-  - Other S-Int: A secure physical interrupt targeted to an SP different from
-    the one that is currently running.
-  - Self S-Int: A secure physical interrupt targeted to the SP that is currently
-    running.
-
-Non-secure interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This section documents the actions supported in SPMC in response to a non-secure
-interrupt as per the guidance provided by FF-A v1.1 EAC0 specification.
-An SP specifies one of the following actions in its partition manifest:
-
-  - Non-secure interrupt is signaled.
-  - Non-secure interrupt is signaled after a managed exit.
-  - Non-secure interrupt is queued.
-
-An SP execution context in a call chain could specify a less permissive action
-than subsequent SP execution contexts in the same call chain. The less
-permissive action takes precedence over the more permissive actions specified
-by the subsequent execution contexts. Please refer to FF-A v1.1 EAC0 section
-8.3.1 for further explanation.
-
-Secure interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This section documents the support implemented for secure interrupt handling in
-SPMC as per the guidance provided by FF-A v1.1 EAC0 specification.
-The following assumptions are made about the system configuration:
-
-  - In the current implementation, S-EL1 SPs are expected to use the para
-    virtualized ABIs for interrupt management rather than accessing the virtual
-    GIC interface.
-  - Unless explicitly stated otherwise, this support is applicable only for
-    S-EL1 SPs managed by SPMC.
-  - Secure interrupts are configured as G1S or G0 interrupts.
-  - All physical interrupts are routed to SPMC when running a secure partition
-    execution context.
-  - All endpoints with multiple execution contexts have their contexts pinned
-    to corresponding CPUs. Hence, a secure virtual interrupt cannot be signaled
-    to a target vCPU that is currently running or blocked on a different
-    physical CPU.
-
-A physical secure interrupt could trigger while CPU is executing in normal world
-or secure world.
-The action of SPMC for a secure interrupt depends on: the state of the target
-execution context of the SP that is responsible for handling the interrupt;
-whether the interrupt triggered while execution was in normal world or secure
-world.
-
-Secure interrupt signaling mechanisms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Signaling refers to the mechanisms used by SPMC to indicate to the SP execution
-context that it has a pending virtual interrupt and to further run the SP
-execution context, such that it can handle the virtual interrupt. SPMC uses
-either the FFA_INTERRUPT interface with ERET conduit or vIRQ signal for signaling
-to S-EL1 SPs. When normal world execution is preempted by a secure interrupt,
-the SPMD uses the FFA_INTERRUPT ABI with ERET conduit to signal interrupt to SPMC
-running in S-EL2.
-
-+-----------+---------+---------------+---------------------------------------+
-| SP State  | Conduit | Interface and | Description                           |
-|           |         | parameters    |                                       |
-+-----------+---------+---------------+---------------------------------------+
-| WAITING   | ERET,   | FFA_INTERRUPT,| SPMC signals to SP the ID of pending  |
-|           | vIRQ    | Interrupt ID  | interrupt. It pends vIRQ signal and   |
-|           |         |               | resumes execution context of SP       |
-|           |         |               | through ERET.                         |
-+-----------+---------+---------------+---------------------------------------+
-| BLOCKED   | ERET,   | FFA_INTERRUPT | SPMC signals to SP that an interrupt  |
-|           | vIRQ    |               | is pending. It pends vIRQ signal and  |
-|           |         |               | resumes execution context of SP       |
-|           |         |               | through ERET.                         |
-+-----------+---------+---------------+---------------------------------------+
-| PREEMPTED | vIRQ    | NA            | SPMC pends the vIRQ signal but does   |
-|           |         |               | not resume execution context of SP.   |
-+-----------+---------+---------------+---------------------------------------+
-| RUNNING   | ERET,   | NA            | SPMC pends the vIRQ signal and resumes|
-|           | vIRQ    |               | execution context of SP through ERET. |
-+-----------+---------+---------------+---------------------------------------+
-
-Secure interrupt completion mechanisms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A SP signals secure interrupt handling completion to the SPMC through the
-following mechanisms:
-
-  - ``FFA_MSG_WAIT`` ABI if it was in WAITING state.
-  - ``FFA_RUN`` ABI if its was in BLOCKED state.
-
-This is a remnant of SPMC implementation based on the FF-A v1.0 specification.
-In the current implementation, S-EL1 SPs use the para-virtualized HVC interface
-implemented by SPMC to perform priority drop and interrupt deactivation (SPMC
-configures EOImode = 0, i.e. priority drop and deactivation are done together).
-The SPMC performs checks to deny the state transition upon invocation of
-either FFA_MSG_WAIT or FFA_RUN interface if the SP didn't perform the
-deactivation of the secure virtual interrupt.
-
-If the current SP execution context was preempted by a secure interrupt to be
-handled by execution context of target SP, SPMC resumes current SP after signal
-completion by target SP execution context.
-
-Actions for a secure interrupt triggered while execution is in normal world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-+-------------------+----------+-----------------------------------------------+
-| State of target   | Action   | Description                                   |
-| execution context |          |                                               |
-+-------------------+----------+-----------------------------------------------+
-| WAITING           | Signaled | This starts a new call chain in SPMC scheduled|
-|                   |          | mode.                                         |
-+-------------------+----------+-----------------------------------------------+
-| PREEMPTED         | Queued   | The target execution must have been preempted |
-|                   |          | by a non-secure interrupt. SPMC queues the    |
-|                   |          | secure virtual interrupt now. It is signaled  |
-|                   |          | when the target execution context next enters |
-|                   |          | the RUNNING state.                            |
-+-------------------+----------+-----------------------------------------------+
-| BLOCKED, RUNNING  | NA       | The target execution context is blocked or    |
-|                   |          | running on a different CPU. This is not       |
-|                   |          | supported by current SPMC implementation and  |
-|                   |          | execution hits panic.                         |
-+-------------------+----------+-----------------------------------------------+
-
-If normal world execution was preempted by a secure interrupt, SPMC uses
-FFA_NORMAL_WORLD_RESUME ABI to indicate completion of secure interrupt handling
-and further returns execution to normal world.
-
-The following figure describes interrupt handling flow when a secure interrupt
-triggers while execution is in normal world:
-
-.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-nwd.png
-
-A brief description of the events:
-
-  - 1) Secure interrupt triggers while normal world is running.
-  - 2) FIQ gets trapped to EL3.
-  - 3) SPMD signals secure interrupt to SPMC at S-EL2 using FFA_INTERRUPT ABI.
-  - 4) SPMC identifies target vCPU of SP and injects virtual interrupt (pends
-       vIRQ).
-  - 5) Assuming SP1 vCPU is in WAITING state, SPMC signals virtual interrupt
-       using FFA_INTERRUPT with interrupt id as an argument and resumes the SP1
-       vCPU using ERET in SPMC scheduled mode.
-  - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
-       interrupt is not masked i.e., PSTATE.I = 0
-  - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
-       HVC call. SPMC clears the pending virtual interrupt state management
-       and returns the pending virtual interrupt id.
-  - 8) SP1 services the virtual interrupt and invokes the paravirtualized
-       de-activation HVC call. SPMC de-activates the physical interrupt,
-       clears the fields tracking the secure interrupt and resumes SP1 vCPU.
-  - 9) SP1 performs secure interrupt completion through FFA_MSG_WAIT ABI.
-  - 10) SPMC returns control to EL3 using FFA_NORMAL_WORLD_RESUME.
-  - 11) EL3 resumes normal world execution.
-
-Actions for a secure interrupt triggered while execution is in secure world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-+-------------------+----------+------------------------------------------------+
-| State of target   | Action   | Description                                    |
-| execution context |          |                                                |
-+-------------------+----------+------------------------------------------------+
-| WAITING           | Signaled | This starts a new call chain in SPMC scheduled |
-|                   |          | mode.                                          |
-+-------------------+----------+------------------------------------------------+
-| PREEMPTED by Self | Signaled | The target execution context reenters the      |
-| S-Int             |          | RUNNING state to handle the secure virtual     |
-|                   |          | interrupt.                                     |
-+-------------------+----------+------------------------------------------------+
-| PREEMPTED by      | Queued   | SPMC queues the secure virtual interrupt now.  |
-| NS-Int            |          | It is signaled when the target execution       |
-|                   |          | context next enters the RUNNING state.         |
-+-------------------+----------+------------------------------------------------+
-| BLOCKED           | Signaled | Both preempted and target execution contexts   |
-|                   |          | must have been part of the Normal world        |
-|                   |          | scheduled call chain. Refer scenario 1 of      |
-|                   |          | Table 8.4 in the FF-A v1.1 EAC0 spec.          |
-+-------------------+----------+------------------------------------------------+
-| RUNNING           | NA       | The target execution context is running on a   |
-|                   |          | different CPU. This scenario is not supported  |
-|                   |          | by current SPMC implementation and execution   |
-|                   |          | hits panic.                                    |
-+-------------------+----------+------------------------------------------------+
-
-The following figure describes interrupt handling flow when a secure interrupt
-triggers while execution is in secure world. We assume OS kernel sends a direct
-request message to SP1. Further, SP1 sends a direct request message to SP2. SP1
-enters BLOCKED state and SPMC resumes SP2.
-
-.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-swd.png
-
-A brief description of the events:
-
-  - 1) Secure interrupt triggers while SP2 is running.
-  - 2) SP2 gets preempted and execution traps to SPMC as IRQ.
-  - 3) SPMC finds the target vCPU of secure partition responsible for handling
-       this secure interrupt. In this scenario, it is SP1.
-  - 4) SPMC pends vIRQ for SP1 and signals through FFA_INTERRUPT interface.
-       SPMC further resumes SP1 through ERET conduit. Note that SP1 remains in
-       Normal world schedule mode.
-  - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
-       interrupt is not masked i.e., PSTATE.I = 0
-  - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
-       HVC call. SPMC clears the pending virtual interrupt state management
-       and returns the pending virtual interrupt id.
-  - 8) SP1 services the virtual interrupt and invokes the paravirtualized
-       de-activation HVC call. SPMC de-activates the physical interrupt and
-       clears the fields tracking the secure interrupt and resumes SP1 vCPU.
-  - 9) Since SP1 direct request completed with FFA_INTERRUPT, it resumes the
-       direct request to SP2 by invoking FFA_RUN.
-  - 9) SPMC resumes the pre-empted vCPU of SP2.
-
-EL3 interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~
-
-In GICv3 based systems, EL3 interrupts are configured as Group0 secure
-interrupts. Execution traps to SPMC when a Group0 interrupt triggers while an
-SP is running. Further, SPMC running at S-EL2 uses FFA_EL3_INTR_HANDLE ABI to
-request EL3 platform firmware to handle a pending Group0 interrupt.
-Similarly, SPMD registers a handler with interrupt management framework to
-delegate handling of Group0 interrupt to the platform if the interrupt triggers
-in normal world.
-
- - Platform hook
-
-   - plat_spmd_handle_group0_interrupt
-
-     SPMD provides platform hook to handle Group0 secure interrupts. In the
-     current design, SPMD expects the platform not to delegate handling to the
-     NWd (such as through SDEI) while processing Group0 interrupts.
-
-Power management
-----------------
-
-In platforms with or without secure virtualization:
-
-- The NWd owns the platform PM policy.
-- The Hypervisor or OS kernel is the component initiating PSCI service calls.
-- The EL3 PSCI library is in charge of the PM coordination and control
-  (eventually writing to platform registers).
-- While coordinating PM events, the PSCI library calls backs into the Secure
-  Payload Dispatcher for events the latter has statically registered to.
-
-When using the SPMD as a Secure Payload Dispatcher:
-
-- A power management event is relayed through the SPD hook to the SPMC.
-- In the current implementation only cpu on (svc_on_finish) and cpu off
-  (svc_off) hooks are registered.
-- The behavior for the cpu on event is described in `Secondary cores boot-up`_.
-  The SPMC is entered through its secondary physical core entry point.
-- The cpu off event occurs when the NWd calls PSCI_CPU_OFF. The PM event is
-  signaled to the SPMC through a power management framework message.
-  It consists in a SPMD-to-SPMC direct request/response (`SPMC-SPMD direct
-  requests/responses`_) conveying the event details and SPMC response.
-  The SPMD performs a synchronous entry into the SPMC. The SPMC is entered and
-  updates its internal state to reflect the physical core is being turned off.
-  In the current implementation no SP is resumed as a consequence. This behavior
-  ensures a minimal support for CPU hotplug e.g. when initiated by the NWd linux
-  userspace.
-
-Arm architecture extensions for security hardening
-==================================================
-
-Hafnium supports the following architecture extensions for security hardening:
-
-- Pointer authentication (FEAT_PAuth): the extension permits detection of forged
-  pointers used by ROP type of attacks through the signing of the pointer
-  value. Hafnium is built with the compiler branch protection option to permit
-  generation of a pointer authentication code for return addresses (pointer
-  authentication for instructions). The APIA key is used while Hafnium runs.
-  A random key is generated at boot time and restored upon entry into Hafnium
-  at run-time. APIA and other keys (APIB, APDA, APDB, APGA) are saved/restored
-  in vCPU contexts permitting to enable pointer authentication in VMs/SPs.
-- Branch Target Identification (FEAT_BTI): the extension permits detection of
-  unexpected indirect branches used by JOP type of attacks. Hafnium is built
-  with the compiler branch protection option, inserting land pads at function
-  prologues that are reached by indirect branch instructions (BR/BLR).
-  Hafnium code pages are marked as guarded in the EL2 Stage-1 MMU descriptors
-  such that an indirect branch must always target a landpad. A fault is
-  triggered otherwise. VMs/SPs can (independently) mark their code pages as
-  guarded in the EL1&0 Stage-1 translation regime.
-- Memory Tagging Extension (FEAT_MTE): the option permits detection of out of
-  bound memory array accesses or re-use of an already freed memory region.
-  Hafnium enables the compiler option permitting to leverage MTE stack tagging
-  applied to core stacks. Core stacks are marked as normal tagged memory in the
-  EL2 Stage-1 translation regime. A synchronous data abort is generated upon tag
-  check failure on load/stores. A random seed is generated at boot time and
-  restored upon entry into Hafnium. MTE system registers are saved/restored in
-  vCPU contexts permitting MTE usage from VMs/SPs.
-
-SMMUv3 support in Hafnium
-=========================
-
-An SMMU is analogous to an MMU in a CPU. It performs address translations for
-Direct Memory Access (DMA) requests from system I/O devices.
-The responsibilities of an SMMU include:
-
--  Translation: Incoming DMA requests are translated from bus address space to
-   system physical address space using translation tables compliant to
-   Armv8/Armv7 VMSA descriptor format.
--  Protection: An I/O device can be prohibited from read, write access to a
-   memory region or allowed.
--  Isolation: Traffic from each individial device can be independently managed.
-   The devices are differentiated from each other using unique translation
-   tables.
-
-The following diagram illustrates a typical SMMU IP integrated in a SoC with
-several I/O devices along with Interconnect and Memory system.
-
-.. image:: ../resources/diagrams/MMU-600.png
-
-SMMU has several versions including SMMUv1, SMMUv2 and SMMUv3. Hafnium provides
-support for SMMUv3 driver in both normal and secure world. A brief introduction
-of SMMUv3 functionality and the corresponding software support in Hafnium is
-provided here.
-
-SMMUv3 features
----------------
-
--  SMMUv3 provides Stage1, Stage2 translation as well as nested (Stage1 + Stage2)
-   translation support. It can either bypass or abort incoming translations as
-   well.
--  Traffic (memory transactions) from each upstream I/O peripheral device,
-   referred to as Stream, can be independently managed using a combination of
-   several memory based configuration structures. This allows the SMMUv3 to
-   support a large number of streams with each stream assigned to a unique
-   translation context.
--  Support for Armv8.1 VMSA where the SMMU shares the translation tables with
-   a Processing Element. AArch32(LPAE) and AArch64 translation table format
-   are supported by SMMUv3.
--  SMMUv3 offers non-secure stream support with secure stream support being
-   optional. Logically, SMMUv3 behaves as if there is an indepdendent SMMU
-   instance for secure and non-secure stream support.
--  It also supports sub-streams to differentiate traffic from a virtualized
-   peripheral associated with a VM/SP.
--  Additionally, SMMUv3.2 provides support for PEs implementing Armv8.4-A
-   extensions. Consequently, SPM depends on Secure EL2 support in SMMUv3.2
-   for providing Secure Stage2 translation support to upstream peripheral
-   devices.
-
-SMMUv3 Programming Interfaces
------------------------------
-
-SMMUv3 has three software interfaces that are used by the Hafnium driver to
-configure the behaviour of SMMUv3 and manage the streams.
-
--  Memory based data strutures that provide unique translation context for
-   each stream.
--  Memory based circular buffers for command queue and event queue.
--  A large number of SMMU configuration registers that are memory mapped during
-   boot time by Hafnium driver. Except a few registers, all configuration
-   registers have independent secure and non-secure versions to configure the
-   behaviour of SMMUv3 for translation of secure and non-secure streams
-   respectively.
-
-Peripheral device manifest
---------------------------
-
-Currently, SMMUv3 driver in Hafnium only supports dependent peripheral devices.
-These devices are dependent on PE endpoint to initiate and receive memory
-management transactions on their behalf. The acccess to the MMIO regions of
-any such device is assigned to the endpoint during boot. Moreover, SMMUv3 driver
-uses the same stage 2 translations for the device as those used by partition
-manager on behalf of the PE endpoint. This ensures that the peripheral device
-has the same visibility of the physical address space as the endpoint. The
-device node of the corresponding partition manifest (refer to `[1]`_ section 3.2
-) must specify these additional properties for each peripheral device in the
-system :
-
--  smmu-id: This field helps to identify the SMMU instance that this device is
-   upstream of.
--  stream-ids: List of stream IDs assigned to this device.
-
-.. code:: shell
-
-    smmuv3-testengine {
-        base-address = <0x00000000 0x2bfe0000>;
-        pages-count = <32>;
-        attributes = <0x3>;
-        smmu-id = <0>;
-        stream-ids = <0x0 0x1>;
-        interrupts = <0x2 0x3>, <0x4 0x5>;
-        exclusive-access;
-    };
-
-SMMUv3 driver limitations
--------------------------
-
-The primary design goal for the Hafnium SMMU driver is to support secure
-streams.
-
--  Currently, the driver only supports Stage2 translations. No support for
-   Stage1 or nested translations.
--  Supports only AArch64 translation format.
--  No support for features such as PCI Express (PASIDs, ATS, PRI), MSI, RAS,
-   Fault handling, Performance Monitor Extensions, Event Handling, MPAM.
--  No support for independent peripheral devices.
-
-S-EL0 Partition support
-=======================
-The SPMC (Hafnium) has limited capability to run S-EL0 FF-A partitions using
-FEAT_VHE (mandatory with ARMv8.1 in non-secure state, and in secure world
-with ARMv8.4 and FEAT_SEL2).
-
-S-EL0 partitions are useful for simple partitions that don't require full
-Trusted OS functionality. It is also useful to reduce jitter and cycle
-stealing from normal world since they are more lightweight than VMs.
-
-S-EL0 partitions are presented, loaded and initialized the same as S-EL1 VMs by
-the SPMC. They are differentiated primarily by the 'exception-level' property
-and the 'execution-ctx-count' property in the SP manifest. They are host apps
-under the single EL2&0 Stage-1 translation regime controlled by the SPMC and
-call into the SPMC through SVCs as opposed to HVCs and SMCs. These partitions
-can use FF-A defined services (FFA_MEM_PERM_*) to update or change permissions
-for memory regions.
-
-S-EL0 partitions are required by the FF-A specification to be UP endpoints,
-capable of migrating, and the SPMC enforces this requirement. The SPMC allows
-a S-EL0 partition to accept a direct message from secure world and normal world,
-and generate direct responses to them.
-All S-EL0 partitions must use AArch64. AArch32 S-EL0 partitions are not supported.
-
-Memory sharing, indirect messaging, and notifications functionality with S-EL0
-partitions is supported.
-
-Interrupt handling is not supported with S-EL0 partitions and is work in
-progress.
 
 References
 ==========
@@ -1641,8 +242,7 @@
 
 .. _[3]:
 
-[3] `Trusted Boot Board Requirements
-Client <https://developer.arm.com/documentation/den0006/d/>`__
+[3] https://hafnium.readthedocs.io/en/latest/secure-partition-manager/secure-partition-manager.html#secure-partitions-layout-file
 
 .. _[4]:
 
@@ -1650,23 +250,15 @@
 
 .. _[5]:
 
-[5] https://git.trustedfirmware.org/TF-A/tf-a-tests.git/tree/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+[5] https://hafnium.readthedocs.io/en/latest/secure-partition-manager/index.html
 
 .. _[6]:
 
-[6] https://trustedfirmware-a.readthedocs.io/en/latest/components/ffa-manifest-binding.html
+[6] :ref:`EL3 Secure Partition Manager<EL3 Secure Partition Manager>`
 
 .. _[7]:
 
-[7] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
-
-.. _[8]:
-
-[8] https://lists.trustedfirmware.org/archives/list/tf-a@lists.trustedfirmware.org/thread/CFQFGU6H2D5GZYMUYGTGUSXIU3OYZP6U/
-
-.. _[9]:
-
-[9] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
+[7] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
 
 --------------
 
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 6147c1f..e6ca542 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -826,6 +826,10 @@
   feature is enabled and can assist the Kernel in the process of
   mitigation of the erratum.
 
+- ``ERRATA_X4_2726228``: This applies erratum 2726228 workaround to Cortex-X4
+  CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in
+  r0p2.
+
 -  ``ERRATA_X4_2740089``: This applies errata 2740089 workaround to Cortex-X4
    CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed
    in r0p2.
@@ -833,6 +837,9 @@
 - ``ERRATA_X4_2763018``: This applies errata 2763018 workaround to Cortex-X4
   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
 
+- ``ERRATA_X4_2816013``: This applies errata 2816013 workaround to Cortex-X4
+  CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
+
 For Cortex-A510, the following errata build flags are defined :
 
 -  ``ERRATA_A510_1922240``: This applies errata 1922240 workaround to
@@ -896,6 +903,10 @@
    Cortex-A520 CPU. This needs to be enabled for revisions r0p0 and r0p1.
    It is still open.
 
+-  ``ERRATA_A520_2938996``: This applies errata 2938996 workaround to
+   Cortex-A520 CPU. This needs to be enabled for revisions r0p0 and r0p1.
+   It is fixed in r0p2.
+
 For Cortex-A715, the following errata build flags are defined :
 
 -  ``ERRATA_A715_2331818``: This applies errata 2331818 workaround to
@@ -929,6 +940,14 @@
 
 For Cortex-A720, the following errata build flags are defined :
 
+-  ``ERRATA_A720_2792132``: This applies errata 2792132 workaround to
+   Cortex-A720 CPU. This needs to be enabled for revisions r0p0 and r0p1.
+   It is fixed in r0p2.
+
+-  ``ERRATA_A720_2844092``: This applies errata 2844092 workaround to
+   Cortex-A720 CPU. This needs to be enabled for revisions r0p0 and r0p1.
+   It is fixed in r0p2.
+
 -  ``ERRATA_A720_2926083``: This applies errata 2926083 workaround to
    Cortex-A720 CPU. This needs to be enabled for revisions r0p0 and r0p1.
    It is fixed in r0p2.
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 4c070ed..be38e15 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -99,6 +99,10 @@
    file that contains the BL32 private key in PEM format or a PKCS11 URI. If
    ``SAVE_KEYS=1``, only a file is accepted and it will be used to save the key.
 
+-  ``RMM``: This is an optional build option used when ``ENABLE_RME`` is set.
+   It specifies the path to RMM binary for the ``fip`` target. If the RMM option
+   is not specified, TF-A builds the TRP to load and run at R-EL2.
+
 -  ``BL33``: Path to BL33 image in the host file system. This is mandatory for
    ``fip`` target in case TF-A BL2 is used.
 
@@ -200,6 +204,13 @@
    Note that Pointer Authentication is enabled for Non-secure world irrespective
    of the value of this flag if the CPU supports it.
 
+-  ``CTX_INCLUDE_SVE_REGS``: Boolean option that, when set to 1, will cause the
+   SVE registers to be included when saving and restoring the CPU context. Note
+   that this build option requires ``ENABLE_SVE_FOR_SWD`` to be enabled. In
+   general, it is recommended to perform SVE context management in lower ELs
+   and skip in EL3 due to the additional cost of maintaining large data
+   structures to track the SVE state. Hence, the default value is 0.
+
 -  ``DEBUG``: Chooses between a debug and release build. It can take either 0
    (release) or 1 (debug) as values. 0 is the default.
 
@@ -501,21 +512,26 @@
 
 -  ``ENABLE_SVE_FOR_NS``: Numeric value to enable Scalable Vector Extension
    (SVE) for the Non-secure world only. SVE is an optional architectural feature
-   for AArch64. Note that when SVE is enabled for the Non-secure world, access
-   to SIMD and floating-point functionality from the Secure world is disabled by
-   default and controlled with ENABLE_SVE_FOR_SWD.
-   This is to avoid corruption of the Non-secure world data in the Z-registers
-   which are aliased by the SIMD and FP registers. The build option is not
-   compatible with the ``CTX_INCLUDE_FPREGS`` build option, and will raise an
-   assert on platforms where SVE is implemented and ``ENABLE_SVE_FOR_NS``
-   enabled.  This flag can take the values 0 to 2, to align with the
-   ``ENABLE_FEAT`` mechanism. At this time, this build option cannot be
-   used on systems that have SPM_MM enabled. The default is 1.
+   for AArch64. This flag can take the values 0 to 2, to align with the
+   ``ENABLE_FEAT`` mechanism. At this time, this build option cannot be used on
+   systems that have SPM_MM enabled. The default value is 2.
 
--  ``ENABLE_SVE_FOR_SWD``: Boolean option to enable SVE for the Secure world.
-   SVE is an optional architectural feature for AArch64. Note that this option
-   requires ENABLE_SVE_FOR_NS to be enabled. The default is 0 and it is
-   automatically disabled when the target architecture is AArch32.
+   Note that when SVE is enabled for the Non-secure world, access
+   to SVE, SIMD and floating-point functionality from the Secure world is
+   independently controlled by build option ``ENABLE_SVE_FOR_SWD``. When enabling
+   ``CTX_INCLUDE_FPREGS`` and ``ENABLE_SVE_FOR_NS`` together, it is mandatory to
+   enable ``CTX_INCLUDE_SVE_REGS``. This is to avoid corruption of the Non-secure
+   world data in the Z-registers which are aliased by the SIMD and FP registers.
+
+-  ``ENABLE_SVE_FOR_SWD``: Boolean option to enable SVE and FPU/SIMD functionality
+   for the Secure world. SVE is an optional architectural feature for AArch64.
+   The default is 0 and it is automatically disabled when the target architecture
+   is AArch32.
+
+   .. note::
+      This build flag requires ``ENABLE_SVE_FOR_NS`` to be enabled. When enabling
+      ``ENABLE_SVE_FOR_SWD``, a developer must carefully consider whether
+      ``CTX_INCLUDE_SVE_REGS`` is also needed.
 
 -  ``ENABLE_STACK_PROTECTOR``: String option to enable the stack protection
    checks in GCC. Allowed values are "all", "strong", "default" and "none". The
@@ -881,6 +897,11 @@
    flag is disabled by default and NOLOAD sections are placed in RAM immediately
    following the loaded firmware image.
 
+-  ``SEPARATE_SIMD_SECTION``: Setting this option to ``1`` allows the SIMD context
+    data structures to be put in a dedicated memory region as decided by platform
+    integrator. Default value is ``0`` which means the SIMD context is put in BSS
+    section of EL3 firmware.
+
 -  ``SMC_PCI_SUPPORT``: This option allows platforms to handle PCI configuration
    access requests via a standard SMCCC defined in `DEN0115`_. When combined with
    UEFI+ACPI this can provide a certain amount of OS forward compatibility
diff --git a/docs/license.rst b/docs/license.rst
index 8996105..9e0298b 100644
--- a/docs/license.rst
+++ b/docs/license.rst
@@ -93,9 +93,27 @@
 
    -  ``include/lib/dice/dice.h``
 
+-  Some source files originating from the `pydevicetree`_ 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:
+
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py``
+   -  ``tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py``
+
+
 .. _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
-
+.. _pydevicetree: https://pypi.org/project/pydevicetree/
diff --git a/docs/tools/cot-dt2c.rst b/docs/tools/cot-dt2c.rst
new file mode 100644
index 0000000..7b7e56f
--- /dev/null
+++ b/docs/tools/cot-dt2c.rst
@@ -0,0 +1,149 @@
+TF-A CoT dt2c Tool
+==================
+
+This tool is used to automatically generate the corresponding c file for a
+CoT DT file. Since currently TF-A support two type of CoT file: static c file
+and CoT DT binding. This is error prone and hard to maintain, therefore this
+tool can generate the c file for the platform that does not support CoT DT
+binding, given the CoT DT file so the c file can be deprecated.
+
+Prerequisites
+~~~~~~~~~~~~~
+
+#. Python (3.8 or later)
+#. `Poetry`_ Python package manager
+
+
+Getting Started
+~~~~~~~~~~~~~~~
+
+#. Install the tool
+
+    .. code::
+
+        make install
+
+
+#. Verify that the tool runs correctly
+
+    .. code::
+
+        make test
+
+
+#. Usage of the tool
+
+    .. code::
+
+        cot-dt2c
+
+    This command will output the following as usage for this command
+
+    .. code-block:: text
+
+        Usage: cot-dt2c [OPTIONS] COMMAND [ARGS]...
+
+        Options:
+        --version  Show the version and exit.
+        --help     Show this message and exit.
+
+        Commands:
+        convert-to-c
+        validate-cot
+        visualize-cot
+        validate-dt
+
+#. Uninstall the tool
+    .. code::
+
+        make uninstall
+
+    This command will uninstall the tool
+
+
+#. Uninstall the tool and clean all the build file
+    .. code::
+
+        make clean
+
+    This command will clean all the build file and implicitly uninstall the tool
+
+
+#. Call the make file from TF-A root directory
+    .. code::
+
+        make -C tools/cot-dt2c install
+        make -C tools/cot-dt2c uninstall
+        make -C tools/cot-dt2c clean
+
+Convert CoT descriptors to C file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To convert the CoT descriptors
+
+This command is for the platform that does not use CoT DT parser,
+which can generate the C file given the CoT descriptors. Before
+the conversion to C file, the tool will do an implicit checks on
+the validity of the CoT DT file.
+
+.. code::
+
+    cot-dt2c convert-to-c [INPUT DTB PATH] [OUTPUT C PATH]
+    cot-dt2c convert-to-c fdts/tbbr_cot_descriptors.dtsi test.c
+
+
+Validate CoT descriptors
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To validate the certificate
+
+The tests folder in the tool folder provides some bad-example of the
+DT file, and the tool will print out "not a valid CoT DT file" on console.
+
+The command will check the format of the CoT file
+
+#. The open bracket
+#. The open ifdef macro
+#. The missing mandatory attribute
+#. Malformed DT file (cert missing parent, missing root certs. etc.)
+
+Currently the validation is specifically for checking the CoT DT file
+
+.. code::
+
+    cot-dt2c validate-cot [INPUT DTB PATH]
+    cot-dt2c validate-cot fdts/tbbr_cot_descriptors.dtsi
+
+
+Visualize CoT descriptors
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command create a HTML to visualize the relationship between
+the certificates and the image of a CoT DT file.
+
+.. code::
+
+    cot-dt2c visualize-cot [INPUT DTB PATH]
+    cot-dt2c visualize-cot fdts/tbbr_cot_descriptors.dtsi
+
+
+Validate Other DT files
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The command will transform the dtsi/dts file into a more standard
+dtsi/dts file inside /tmp folder that can be used as input to dt-schema
+for further validation. Currently the tool will perform some basic validation
+for the file (syntax) and dt-schema can be used for advance checks. dt-schema
+is not installed along with the tool.
+
+.. code::
+
+    cot-dt2c validate-dt [INPUT DTS PATH or INPUT DTS folder]
+    cot-dt2c validate-dt fdts/
+    cot-dt2c validate-dt fdts/fvp-bsae-gicv3.dtsi
+
+--------------
+
+*Copyright (c) 2024, Arm Limited. All rights reserved.*
+
+.. _Poetry: https://python-poetry.org/docs/
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 91651bf..c0e214a 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -7,6 +7,7 @@
 
    memory-layout-tool
    transfer-list-compiler
+   cot-dt2c
 
 --------------
 
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 8ea164c..2be19db 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -686,6 +686,8 @@
 	gicr_write_ctlr(gicr_base,
 			rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
 
+	gicr_wait_for_pending_write(gicr_base);
+
 	/* Restore registers' content */
 	gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
 	gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
diff --git a/drivers/auth/cca/bl1_cot.c b/drivers/auth/cca/bl1_cot.c
new file mode 100644
index 0000000..43cb18a
--- /dev/null
+++ b/drivers/auth/cca/bl1_cot.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_mod.h>
+#include <platform_def.h>
+#include <tools_share/cca_oid.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+
+/*
+ * Parameter type descriptors.
+ */
+static auth_param_type_desc_t cca_nv_ctr = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_NV_CTR, CCA_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_RAW_DATA, 0);
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+
+/* CCA Content Certificate */
+static const auth_img_desc_t cca_content_cert = {
+	.img_id = CCA_CONTENT_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &cca_nv_ctr,
+				.plat_nv_ctr = &cca_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &tb_fw_hash,
+			.data = {
+				.ptr = (void *)tb_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &tb_fw_config_hash,
+			.data = {
+				.ptr = (void *)tb_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &fw_config_hash,
+			.data = {
+				.ptr = (void *)fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t bl2_image = {
+	.img_id = BL2_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &cca_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_hash
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t tb_fw_config = {
+	.img_id = TB_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &cca_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_config_hash
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t fw_config = {
+	.img_id = FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &cca_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &fw_config_hash
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+	[CCA_CONTENT_CERT_ID]			=	&cca_content_cert,
+	[BL2_IMAGE_ID]				=	&bl2_image,
+	[TB_FW_CONFIG_ID]			=	&tb_fw_config,
+	[FW_CONFIG_ID]				=	&fw_config,
+};
+
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/cca/cot.c b/drivers/auth/cca/cot.c
deleted file mode 100644
index 2a03604..0000000
--- a/drivers/auth/cca/cot.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-
-#include <mbedtls/version.h>
-
-#include <common/tbbr/cot_def.h>
-#include <drivers/auth/auth_mod.h>
-#include <tools_share/cca_oid.h>
-
-#include <platform_def.h>
-
-/*
- * Allocate static buffers to store the authentication parameters extracted from
- * the certificates.
- */
-static unsigned char fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char hw_config_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char rmm_hash_buf[HASH_DER_LEN];
-
-#ifdef IMAGE_BL2
-static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
-#if defined(SPD_spmd)
-static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
-#endif /* SPD_spmd */
-
-static unsigned char core_swd_pk_buf[PK_DER_LEN];
-static unsigned char plat_pk_buf[PK_DER_LEN];
-#endif /* IMAGE_BL2 */
-
-/*
- * Parameter type descriptors.
- */
-static auth_param_type_desc_t cca_nv_ctr = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_NV_CTR, CCA_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, 0);
-static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_SIG, 0);
-static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_SIG_ALG, 0);
-static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_RAW_DATA, 0);
-
-static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
-static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
-static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t rmm_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, RMM_HASH_OID);
-
-#ifdef IMAGE_BL2
-static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
-
-static auth_param_type_desc_t prot_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, PROT_PK_OID);
-static auth_param_type_desc_t swd_rot_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, SWD_ROT_PK_OID);
-static auth_param_type_desc_t core_swd_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, CORE_SWD_PK_OID);
-static auth_param_type_desc_t plat_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, PLAT_PK_OID);
-
-static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
-static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
-static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
-#if defined(SPD_spmd)
-static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
-static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
-static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
-static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
-static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
-static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
-static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
-static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-
-/* CCA Content Certificate */
-static const auth_img_desc_t cca_content_cert = {
-	.img_id = CCA_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &subject_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &cca_nv_ctr,
-				.plat_nv_ctr = &cca_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &tb_fw_hash,
-			.data = {
-				.ptr = (void *)tb_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &tb_fw_config_hash,
-			.data = {
-				.ptr = (void *)tb_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &fw_config_hash,
-			.data = {
-				.ptr = (void *)fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &hw_config_hash,
-			.data = {
-				.ptr = (void *)hw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[4] = {
-			.type_desc = &soc_fw_hash,
-			.data = {
-				.ptr = (void *)soc_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[5] = {
-			.type_desc = &soc_fw_config_hash,
-			.data = {
-				.ptr = (void *)soc_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[6] = {
-			.type_desc = &rmm_hash,
-			.data = {
-				.ptr = (void *)rmm_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-#ifdef IMAGE_BL1
-static const auth_img_desc_t bl2_image = {
-	.img_id = BL2_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tb_fw_hash
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t tb_fw_config = {
-	.img_id = TB_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tb_fw_config_hash
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t fw_config = {
-	.img_id = FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &fw_config_hash
-			}
-		}
-	}
-};
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-/* HW Config */
-static const auth_img_desc_t hw_config = {
-	.img_id = HW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &hw_config_hash
-			}
-		}
-	}
-};
-
-/* BL31 */
-static const auth_img_desc_t bl31_image = {
-	.img_id = BL31_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &soc_fw_hash
-			}
-		}
-	}
-};
-
-/* BL31 Config */
-static const auth_img_desc_t soc_fw_config = {
-	.img_id = SOC_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &soc_fw_config_hash
-			}
-		}
-	}
-};
-
-/* RMM */
-static const auth_img_desc_t rmm_image = {
-	.img_id = RMM_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &cca_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &rmm_hash
-			}
-		}
-	}
-};
-
-/* Core SWD Key Certificate */
-static const auth_img_desc_t core_swd_key_cert = {
-	.img_id = CORE_SWD_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL, /* SWD ROOT CERT */
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &swd_rot_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &core_swd_pk,
-			.data = {
-				.ptr = (void *)core_swd_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		}
-	}
-};
-
-/* SPMC Content Certificate */
-static const auth_img_desc_t trusted_os_fw_content_cert = {
-	.img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &core_swd_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &core_swd_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &tos_fw_hash,
-			.data = {
-				.ptr = (void *)tos_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &tos_fw_config_hash,
-			.data = {
-				.ptr = (void *)tos_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-/* SPMC */
-static const auth_img_desc_t bl32_image = {
-	.img_id = BL32_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_hash
-			}
-		}
-	}
-};
-
-/* SPM Config */
-static const auth_img_desc_t tos_fw_config = {
-	.img_id = TOS_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_config_hash
-			}
-		}
-	}
-};
-
-/* Platform Key Certificate */
-static const auth_img_desc_t plat_key_cert = {
-	.img_id = PLAT_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL, /* PLATFORM ROOT CERT */
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &prot_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &non_trusted_nv_ctr,
-				.plat_nv_ctr = &non_trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &plat_pk,
-			.data = {
-				.ptr = (void *)plat_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		}
-	}
-};
-
-/* Non-Trusted Firmware */
-static const auth_img_desc_t non_trusted_fw_content_cert = {
-	.img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &plat_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &plat_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &non_trusted_nv_ctr,
-				.plat_nv_ctr = &non_trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &nt_world_bl_hash,
-			.data = {
-				.ptr = (void *)nt_world_bl_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &nt_fw_config_hash,
-			.data = {
-				.ptr = (void *)nt_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl33_image = {
-	.img_id = BL33_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &non_trusted_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &nt_world_bl_hash
-			}
-		}
-	}
-};
-
-/* NT FW Config */
-static const auth_img_desc_t nt_fw_config = {
-	.img_id = NT_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &non_trusted_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &nt_fw_config_hash
-			}
-		}
-	}
-};
-
-/*
- * Secure Partitions
- */
-#if defined(SPD_spmd)
-static const auth_img_desc_t sip_sp_content_cert = {
-	.img_id = SIP_SP_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &core_swd_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &core_swd_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &sp_pkg1_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[0],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &sp_pkg2_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[1],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &sp_pkg3_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[2],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &sp_pkg4_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[3],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-DEFINE_SIP_SP_PKG(1);
-DEFINE_SIP_SP_PKG(2);
-DEFINE_SIP_SP_PKG(3);
-DEFINE_SIP_SP_PKG(4);
-
-static const auth_img_desc_t plat_sp_content_cert = {
-	.img_id = PLAT_SP_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &plat_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &plat_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &non_trusted_nv_ctr,
-				.plat_nv_ctr = &non_trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &sp_pkg5_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[4],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &sp_pkg6_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[5],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &sp_pkg7_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[6],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &sp_pkg8_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[7],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-DEFINE_PLAT_SP_PKG(5);
-DEFINE_PLAT_SP_PKG(6);
-DEFINE_PLAT_SP_PKG(7);
-DEFINE_PLAT_SP_PKG(8);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-/*
- * Chain of trust definition
- */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t * const cot_desc[] = {
-	[CCA_CONTENT_CERT_ID]			=	&cca_content_cert,
-	[BL2_IMAGE_ID]				=	&bl2_image,
-	[TB_FW_CONFIG_ID]			=	&tb_fw_config,
-	[FW_CONFIG_ID]				=	&fw_config,
-};
-#else /* IMAGE_BL2 */
-static const auth_img_desc_t * const cot_desc[] = {
-	[CCA_CONTENT_CERT_ID]			=	&cca_content_cert,
-	[HW_CONFIG_ID]				=	&hw_config,
-	[BL31_IMAGE_ID]				=	&bl31_image,
-	[SOC_FW_CONFIG_ID]			=	&soc_fw_config,
-	[RMM_IMAGE_ID]				=	&rmm_image,
-	[CORE_SWD_KEY_CERT_ID]			=	&core_swd_key_cert,
-	[TRUSTED_OS_FW_CONTENT_CERT_ID]		=	&trusted_os_fw_content_cert,
-	[BL32_IMAGE_ID]				=	&bl32_image,
-	[TOS_FW_CONFIG_ID]			=	&tos_fw_config,
-	[PLAT_KEY_CERT_ID]			=	&plat_key_cert,
-	[NON_TRUSTED_FW_CONTENT_CERT_ID]	=	&non_trusted_fw_content_cert,
-	[BL33_IMAGE_ID]				=	&bl33_image,
-	[NT_FW_CONFIG_ID]			=	&nt_fw_config,
-#if defined(SPD_spmd)
-	[SIP_SP_CONTENT_CERT_ID]		=	&sip_sp_content_cert,
-	[PLAT_SP_CONTENT_CERT_ID]		=	&plat_sp_content_cert,
-	[SP_PKG1_ID]				=	&sp_pkg1,
-	[SP_PKG2_ID]				=	&sp_pkg2,
-	[SP_PKG3_ID]				=	&sp_pkg3,
-	[SP_PKG4_ID]				=	&sp_pkg4,
-	[SP_PKG5_ID]				=	&sp_pkg5,
-	[SP_PKG6_ID]				=	&sp_pkg6,
-	[SP_PKG7_ID]				=	&sp_pkg7,
-	[SP_PKG8_ID]				=       &sp_pkg8,
-#endif
-};
-#endif /* IMAGE_BL1 */
-
-/* Register the CoT in the authentication module */
-REGISTER_COT(cot_desc);
diff --git a/drivers/auth/dualroot/bl1_cot.c b/drivers/auth/dualroot/bl1_cot.c
new file mode 100644
index 0000000..a548170
--- /dev/null
+++ b/drivers/auth/dualroot/bl1_cot.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_mod.h>
+#include <platform_def.h>
+#include <tools_share/dualroot_oid.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char scp_fw_hash_buf[HASH_DER_LEN];
+static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+
+/*
+ * Parameter type descriptors.
+ */
+static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_RAW_DATA, 0);
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, FWU_HASH_OID);
+
+static const auth_img_desc_t trusted_boot_fw_cert = {
+	.img_id = TRUSTED_BOOT_FW_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &tb_fw_hash,
+			.data = {
+				.ptr = (void *)tb_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &tb_fw_config_hash,
+			.data = {
+				.ptr = (void *)tb_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &fw_config_hash,
+			.data = {
+				.ptr = (void *)fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t bl2_image = {
+	.img_id = BL2_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_hash
+			}
+		}
+	}
+};
+
+/* TB FW Config */
+static const auth_img_desc_t tb_fw_config = {
+	.img_id = TB_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_config_hash
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t fw_config = {
+	.img_id = FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &fw_config_hash
+			}
+		}
+	}
+};
+
+/* FWU auth descriptor */
+static const auth_img_desc_t fwu_cert = {
+	.img_id = FWU_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &scp_bl2u_hash,
+			.data = {
+				.ptr = (void *)scp_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &bl2u_hash,
+			.data = {
+				.ptr = (void *)tb_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &ns_bl2u_hash,
+			.data = {
+				.ptr = (void *)nt_world_bl_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+
+/* SCP_BL2U */
+static const auth_img_desc_t scp_bl2u_image = {
+	.img_id = SCP_BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &scp_bl2u_hash
+			}
+		}
+	}
+};
+
+/* BL2U */
+static const auth_img_desc_t bl2u_image = {
+	.img_id = BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &bl2u_hash
+			}
+		}
+	}
+};
+
+/* NS_BL2U */
+static const auth_img_desc_t ns_bl2u_image = {
+	.img_id = NS_BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &ns_bl2u_hash
+			}
+		}
+	}
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
+	[BL2_IMAGE_ID]				=	&bl2_image,
+	[TB_FW_CONFIG_ID]			=	&tb_fw_config,
+	[FW_CONFIG_ID]				=	&fw_config,
+	[FWU_CERT_ID]				=	&fwu_cert,
+	[SCP_BL2U_IMAGE_ID]			=	&scp_bl2u_image,
+	[BL2U_IMAGE_ID]				=	&bl2u_image,
+	[NS_BL2U_IMAGE_ID]			=	&ns_bl2u_image
+};
+
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/dualroot/cot.c b/drivers/auth/dualroot/cot.c
deleted file mode 100644
index c89930c..0000000
--- a/drivers/auth/dualroot/cot.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-
-#include <mbedtls/version.h>
-
-#include <common/tbbr/cot_def.h>
-#include <drivers/auth/auth_mod.h>
-
-#include <tools_share/dualroot_oid.h>
-
-#include <platform_def.h>
-
-/*
- * Allocate static buffers to store the authentication parameters extracted from
- * the certificates.
- */
-static unsigned char fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char hw_config_hash_buf[HASH_DER_LEN];
-static unsigned char scp_fw_hash_buf[HASH_DER_LEN];
-static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
-
-#ifdef IMAGE_BL2
-static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_extra1_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_extra2_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
-#if defined(SPD_spmd)
-static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
-#endif /* SPD_spmd */
-
-static unsigned char trusted_world_pk_buf[PK_DER_LEN];
-static unsigned char content_pk_buf[PK_DER_LEN];
-#endif
-
-/*
- * Parameter type descriptors.
- */
-static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, 0);
-static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_SIG, 0);
-static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_SIG_ALG, 0);
-static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_RAW_DATA, 0);
-
-static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
-static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
-static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
-#ifdef IMAGE_BL1
-static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
-static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID);
-static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, FWU_HASH_OID);
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
-
-static auth_param_type_desc_t trusted_world_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, TRUSTED_WORLD_PK_OID);
-static auth_param_type_desc_t scp_fw_content_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, SCP_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t soc_fw_content_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, SOC_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t tos_fw_content_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, TRUSTED_OS_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t prot_pk = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_PUB_KEY, PROT_PK_OID);
-
-static auth_param_type_desc_t scp_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SCP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
-static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t tos_fw_extra1_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA1_HASH_OID);
-static auth_param_type_desc_t tos_fw_extra2_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA2_HASH_OID);
-static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
-static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
-#if defined(SPD_spmd)
-static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
-static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
-static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
-static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
-static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
-static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
-static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
-static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
-		AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-
-
-/* BL2 */
-static const auth_img_desc_t trusted_boot_fw_cert = {
-	.img_id = TRUSTED_BOOT_FW_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &subject_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &tb_fw_hash,
-			.data = {
-				.ptr = (void *)tb_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &tb_fw_config_hash,
-			.data = {
-				.ptr = (void *)tb_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &hw_config_hash,
-			.data = {
-				.ptr = (void *)hw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &fw_config_hash,
-			.data = {
-				.ptr = (void *)fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-#ifdef IMAGE_BL1
-static const auth_img_desc_t bl2_image = {
-	.img_id = BL2_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_boot_fw_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tb_fw_hash
-			}
-		}
-	}
-};
-#endif /* IMAGE_BL1 */
-
-/* HW Config */
-static const auth_img_desc_t hw_config = {
-	.img_id = HW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_boot_fw_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &hw_config_hash
-			}
-		}
-	}
-};
-
-/* TB FW Config */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t tb_fw_config = {
-	.img_id = TB_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_boot_fw_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tb_fw_config_hash
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t fw_config = {
-	.img_id = FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_boot_fw_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &fw_config_hash
-			}
-		}
-	}
-};
-
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-/* Trusted key certificate */
-static const auth_img_desc_t trusted_key_cert = {
-	.img_id = TRUSTED_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &subject_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &trusted_world_pk,
-			.data = {
-				.ptr = (void *)trusted_world_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		},
-	}
-};
-
-/* SCP Firmware */
-static const auth_img_desc_t scp_fw_key_cert = {
-	.img_id = SCP_FW_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &trusted_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &trusted_world_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &scp_fw_content_pk,
-			.data = {
-				.ptr = (void *)content_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t scp_fw_content_cert = {
-	.img_id = SCP_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &scp_fw_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &scp_fw_content_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &scp_fw_hash,
-			.data = {
-				.ptr = (void *)scp_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t scp_bl2_image = {
-	.img_id = SCP_BL2_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &scp_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &scp_fw_hash
-			}
-		}
-	}
-};
-
-/* SoC Firmware */
-static const auth_img_desc_t soc_fw_key_cert = {
-	.img_id = SOC_FW_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &trusted_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &trusted_world_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &soc_fw_content_pk,
-			.data = {
-				.ptr = (void *)content_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t soc_fw_content_cert = {
-	.img_id = SOC_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &soc_fw_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &soc_fw_content_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &soc_fw_hash,
-			.data = {
-				.ptr = (void *)soc_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &soc_fw_config_hash,
-			.data = {
-				.ptr = (void *)soc_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl31_image = {
-	.img_id = BL31_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &soc_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &soc_fw_hash
-			}
-		}
-	}
-};
-
-/* SOC FW Config */
-static const auth_img_desc_t soc_fw_config = {
-	.img_id = SOC_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &soc_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &soc_fw_config_hash
-			}
-		}
-	}
-};
-
-/* Trusted OS Firmware */
-static const auth_img_desc_t trusted_os_fw_key_cert = {
-	.img_id = TRUSTED_OS_FW_KEY_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &trusted_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &trusted_world_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &tos_fw_content_pk,
-			.data = {
-				.ptr = (void *)content_pk_buf,
-				.len = (unsigned int)PK_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t trusted_os_fw_content_cert = {
-	.img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &trusted_os_fw_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &tos_fw_content_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &tos_fw_hash,
-			.data = {
-				.ptr = (void *)tos_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &tos_fw_extra1_hash,
-			.data = {
-				.ptr = (void *)tos_fw_extra1_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &tos_fw_extra2_hash,
-			.data = {
-				.ptr = (void *)tos_fw_extra2_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &tos_fw_config_hash,
-			.data = {
-				.ptr = (void *)tos_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl32_image = {
-	.img_id = BL32_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_hash
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl32_extra1_image = {
-	.img_id = BL32_EXTRA1_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_extra1_hash
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl32_extra2_image = {
-	.img_id = BL32_EXTRA2_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_extra2_hash
-			}
-		}
-	}
-};
-
-/* TOS FW Config */
-static const auth_img_desc_t tos_fw_config = {
-	.img_id = TOS_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &trusted_os_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &tos_fw_config_hash
-			}
-		}
-	}
-};
-
-/* Non-Trusted Firmware */
-static const auth_img_desc_t non_trusted_fw_content_cert = {
-	.img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL, /* Root certificate.  */
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &prot_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &non_trusted_nv_ctr,
-				.plat_nv_ctr = &non_trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &nt_world_bl_hash,
-			.data = {
-				.ptr = (void *)nt_world_bl_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &nt_fw_config_hash,
-			.data = {
-				.ptr = (void *)nt_fw_config_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-static const auth_img_desc_t bl33_image = {
-	.img_id = BL33_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &non_trusted_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &nt_world_bl_hash
-			}
-		}
-	}
-};
-
-/* NT FW Config */
-static const auth_img_desc_t nt_fw_config = {
-	.img_id = NT_FW_CONFIG_ID,
-	.img_type = IMG_RAW,
-	.parent = &non_trusted_fw_content_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &nt_fw_config_hash
-			}
-		}
-	}
-};
-
-/*
- * Secure Partitions
- */
-#if defined(SPD_spmd)
-static const auth_img_desc_t sip_sp_content_cert = {
-	.img_id = SIP_SP_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = &trusted_key_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &trusted_world_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &trusted_nv_ctr,
-				.plat_nv_ctr = &trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &sp_pkg1_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[0],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &sp_pkg2_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[1],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &sp_pkg3_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[2],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &sp_pkg4_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[3],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-DEFINE_SIP_SP_PKG(1);
-DEFINE_SIP_SP_PKG(2);
-DEFINE_SIP_SP_PKG(3);
-DEFINE_SIP_SP_PKG(4);
-
-static const auth_img_desc_t plat_sp_content_cert = {
-	.img_id = PLAT_SP_CONTENT_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &prot_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		},
-		[1] = {
-			.type = AUTH_METHOD_NV_CTR,
-			.param.nv_ctr = {
-				.cert_nv_ctr = &non_trusted_nv_ctr,
-				.plat_nv_ctr = &non_trusted_nv_ctr
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &sp_pkg5_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[4],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &sp_pkg6_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[5],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &sp_pkg7_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[6],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[3] = {
-			.type_desc = &sp_pkg8_hash,
-			.data = {
-				.ptr = (void *)sp_pkg_hash_buf[7],
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-DEFINE_PLAT_SP_PKG(5);
-DEFINE_PLAT_SP_PKG(6);
-DEFINE_PLAT_SP_PKG(7);
-DEFINE_PLAT_SP_PKG(8);
-#endif /* SPD_spmd */
-
-#else  /* IMAGE_BL2 */
-
-/* FWU auth descriptor */
-static const auth_img_desc_t fwu_cert = {
-	.img_id = FWU_CERT_ID,
-	.img_type = IMG_CERT,
-	.parent = NULL,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_SIG,
-			.param.sig = {
-				.pk = &subject_pk,
-				.sig = &sig,
-				.alg = &sig_alg,
-				.data = &raw_data
-			}
-		}
-	},
-	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
-		[0] = {
-			.type_desc = &scp_bl2u_hash,
-			.data = {
-				.ptr = (void *)scp_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[1] = {
-			.type_desc = &bl2u_hash,
-			.data = {
-				.ptr = (void *)tb_fw_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		},
-		[2] = {
-			.type_desc = &ns_bl2u_hash,
-			.data = {
-				.ptr = (void *)nt_world_bl_hash_buf,
-				.len = (unsigned int)HASH_DER_LEN
-			}
-		}
-	}
-};
-
-/* SCP_BL2U */
-static const auth_img_desc_t scp_bl2u_image = {
-	.img_id = SCP_BL2U_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &fwu_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &scp_bl2u_hash
-			}
-		}
-	}
-};
-
-/* BL2U */
-static const auth_img_desc_t bl2u_image = {
-	.img_id = BL2U_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &fwu_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &bl2u_hash
-			}
-		}
-	}
-};
-
-/* NS_BL2U */
-static const auth_img_desc_t ns_bl2u_image = {
-	.img_id = NS_BL2U_IMAGE_ID,
-	.img_type = IMG_RAW,
-	.parent = &fwu_cert,
-	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
-		[0] = {
-			.type = AUTH_METHOD_HASH,
-			.param.hash = {
-				.data = &raw_data,
-				.hash = &ns_bl2u_hash
-			}
-		}
-	}
-};
-#endif /* IMAGE_BL2 */
-
-/*
- * Chain of trust definition
- */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t * const cot_desc[] = {
-	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
-	[BL2_IMAGE_ID]				=	&bl2_image,
-	[HW_CONFIG_ID]				=	&hw_config,
-	[TB_FW_CONFIG_ID]			=	&tb_fw_config,
-	[FW_CONFIG_ID]				=	&fw_config,
-	[FWU_CERT_ID]				=	&fwu_cert,
-	[SCP_BL2U_IMAGE_ID]			=	&scp_bl2u_image,
-	[BL2U_IMAGE_ID]				=	&bl2u_image,
-	[NS_BL2U_IMAGE_ID]			=	&ns_bl2u_image
-};
-#else /* IMAGE_BL2 */
-static const auth_img_desc_t * const cot_desc[] = {
-	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
-	[HW_CONFIG_ID]				=	&hw_config,
-	[TRUSTED_KEY_CERT_ID]			=	&trusted_key_cert,
-	[SCP_FW_KEY_CERT_ID]			=	&scp_fw_key_cert,
-	[SCP_FW_CONTENT_CERT_ID]		=	&scp_fw_content_cert,
-	[SCP_BL2_IMAGE_ID]			=	&scp_bl2_image,
-	[SOC_FW_KEY_CERT_ID]			=	&soc_fw_key_cert,
-	[SOC_FW_CONTENT_CERT_ID]		=	&soc_fw_content_cert,
-	[BL31_IMAGE_ID]				=	&bl31_image,
-	[SOC_FW_CONFIG_ID]			=	&soc_fw_config,
-	[TRUSTED_OS_FW_KEY_CERT_ID]		=	&trusted_os_fw_key_cert,
-	[TRUSTED_OS_FW_CONTENT_CERT_ID]		=	&trusted_os_fw_content_cert,
-	[BL32_IMAGE_ID]				=	&bl32_image,
-	[BL32_EXTRA1_IMAGE_ID]			=	&bl32_extra1_image,
-	[BL32_EXTRA2_IMAGE_ID]			=	&bl32_extra2_image,
-	[TOS_FW_CONFIG_ID]			=	&tos_fw_config,
-	[NON_TRUSTED_FW_CONTENT_CERT_ID]	=	&non_trusted_fw_content_cert,
-	[BL33_IMAGE_ID]				=	&bl33_image,
-	[NT_FW_CONFIG_ID]			=	&nt_fw_config,
-#if defined(SPD_spmd)
-	[SIP_SP_CONTENT_CERT_ID]		=	&sip_sp_content_cert,
-	[PLAT_SP_CONTENT_CERT_ID]		=	&plat_sp_content_cert,
-	[SP_PKG1_ID]				=	&sp_pkg1,
-	[SP_PKG2_ID]				=	&sp_pkg2,
-	[SP_PKG3_ID]				=	&sp_pkg3,
-	[SP_PKG4_ID]				=	&sp_pkg4,
-	[SP_PKG5_ID]				=	&sp_pkg5,
-	[SP_PKG6_ID]				=	&sp_pkg6,
-	[SP_PKG7_ID]				=	&sp_pkg7,
-	[SP_PKG8_ID]				=       &sp_pkg8,
-#endif
-};
-#endif
-
-/* Register the CoT in the authentication module */
-REGISTER_COT(cot_desc);
diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
index d62eed7..84e76f7 100644
--- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
+++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
@@ -9,6 +9,7 @@
 
 #define FXOSC_BASE_ADDR			(0x40050000UL)
 #define ARMPLL_BASE_ADDR		(0x40038000UL)
+#define PERIPHPLL_BASE_ADDR		(0x4003C000UL)
 #define ARM_DFS_BASE_ADDR		(0x40054000UL)
 #define CGM0_BASE_ADDR			(0x40030000UL)
 #define CGM1_BASE_ADDR			(0x40034000UL)
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index e23d928..fed16a7 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -22,6 +22,7 @@
 struct s32cc_clk_drv {
 	uintptr_t fxosc_base;
 	uintptr_t armpll_base;
+	uintptr_t periphpll_base;
 	uintptr_t armdfs_base;
 	uintptr_t cgm0_base;
 	uintptr_t cgm1_base;
@@ -42,6 +43,7 @@
 	static struct s32cc_clk_drv driver = {
 		.fxosc_base = FXOSC_BASE_ADDR,
 		.armpll_base = ARMPLL_BASE_ADDR,
+		.periphpll_base = PERIPHPLL_BASE_ADDR,
 		.armdfs_base = ARM_DFS_BASE_ADDR,
 		.cgm0_base = CGM0_BASE_ADDR,
 		.cgm1_base = CGM1_BASE_ADDR,
@@ -91,6 +93,9 @@
 	case S32CC_ARM_PLL:
 		*base = drv->armpll_base;
 		break;
+	case S32CC_PERIPH_PLL:
+		*base = drv->periphpll_base;
+		break;
 	case S32CC_ARM_DFS:
 		*base = drv->armdfs_base;
 		break;
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
index c4c73c7..45e2070 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -58,6 +58,13 @@
 				 S32CC_CLK_ARM_PLL_DFS1, 0, 0, 0);
 static struct s32cc_clk cgm0_mux0_clk = S32CC_MODULE_CLK(cgm0_mux0);
 
+static struct s32cc_clkmux cgm0_mux8 =
+	S32CC_SHARED_CLKMUX_INIT(S32CC_CGM0, 8, 3,
+				 S32CC_CLK_FIRC,
+				 S32CC_CLK_PERIPH_PLL_PHI3,
+				 S32CC_CLK_FXOSC, 0, 0);
+static struct s32cc_clk cgm0_mux8_clk = S32CC_MODULE_CLK(cgm0_mux8);
+
 /* XBAR */
 static struct s32cc_clk xbar_2x_clk =
 	S32CC_CHILD_CLK(cgm0_mux0_clk, 48 * MHZ, 800 * MHZ);
@@ -82,6 +89,14 @@
 static struct s32cc_clk xbar_div6_clk =
 	S32CC_FREQ_MODULE_CLK(xbar_div12, 4 * MHZ, 66666666);
 
+/* Linflex */
+static struct s32cc_clk linflex_baud_clk =
+	S32CC_CHILD_CLK(cgm0_mux8_clk, 19200, 133333333);
+static struct s32cc_fixed_div linflex_div =
+	S32CC_FIXED_DIV_INIT(linflex_baud_clk, 2);
+static struct s32cc_clk linflex_clk =
+	S32CC_FREQ_MODULE_CLK(linflex_div, 9600, 66666666);
+
 /* MC_CGM1 */
 static struct s32cc_clkmux cgm1_mux0 =
 	S32CC_SHARED_CLKMUX_INIT(S32CC_CGM1, 0, 3,
@@ -107,7 +122,24 @@
 	S32CC_FREQ_MODULE_CLK(a53_core_div10, S32CC_A53_MIN_FREQ / 10,
 			      S32CC_A53_MAX_FREQ / 10);
 
-static struct s32cc_clk *s32cc_hw_clk_list[13] = {
+/* PERIPH PLL */
+static struct s32cc_clkmux periph_pll_mux =
+	S32CC_CLKMUX_INIT(S32CC_PERIPH_PLL, 0, 2,
+			  S32CC_CLK_FIRC,
+			  S32CC_CLK_FXOSC, 0, 0, 0);
+static struct s32cc_clk periph_pll_mux_clk =
+	S32CC_MODULE_CLK(periph_pll_mux);
+static struct s32cc_pll periphpll =
+	S32CC_PLL_INIT(periph_pll_mux_clk, S32CC_PERIPH_PLL, 2);
+static struct s32cc_clk periph_pll_vco_clk =
+	S32CC_FREQ_MODULE_CLK(periphpll, 1300 * MHZ, 2 * GHZ);
+
+static struct s32cc_pll_out_div periph_pll_phi3_div =
+	S32CC_PLL_OUT_DIV_INIT(periphpll, 3);
+static struct s32cc_clk periph_pll_phi3_clk =
+	S32CC_FREQ_MODULE_CLK(periph_pll_phi3_div, 0, 133333333);
+
+static struct s32cc_clk *s32cc_hw_clk_list[22] = {
 	/* Oscillators */
 	[S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk,
 	[S32CC_CLK_ID(S32CC_CLK_SIRC)] = &sirc_clk,
@@ -116,6 +148,8 @@
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_PHI0)] = &arm_pll_phi0_clk,
 	/* ARM DFS */
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_DFS1)] = &arm_dfs1_clk,
+	/* PERIPH PLL */
+	[S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_PHI3)] = &periph_pll_phi3_clk,
 };
 
 static struct s32cc_clk_array s32cc_hw_clocks = {
@@ -124,12 +158,16 @@
 	.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
 };
 
-static struct s32cc_clk *s32cc_arch_clk_list[13] = {
+static struct s32cc_clk *s32cc_arch_clk_list[18] = {
 	/* ARM PLL */
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_MUX)] = &arm_pll_mux_clk,
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_VCO)] = &arm_pll_vco_clk,
+	/* PERIPH PLL */
+	[S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_MUX)] = &periph_pll_mux_clk,
+	[S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_VCO)] = &periph_pll_vco_clk,
 	/* MC_CGM0 */
 	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX0)] = &cgm0_mux0_clk,
+	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX8)] = &cgm0_mux8_clk,
 	/* XBAR */
 	[S32CC_CLK_ID(S32CC_CLK_XBAR_2X)] = &xbar_2x_clk,
 	[S32CC_CLK_ID(S32CC_CLK_XBAR)] = &xbar_clk,
@@ -143,6 +181,9 @@
 	[S32CC_CLK_ID(S32CC_CLK_A53_CORE)] = &a53_core_clk,
 	[S32CC_CLK_ID(S32CC_CLK_A53_CORE_DIV2)] = &a53_core_div2_clk,
 	[S32CC_CLK_ID(S32CC_CLK_A53_CORE_DIV10)] = &a53_core_div10_clk,
+	/* Linflex */
+	[S32CC_CLK_ID(S32CC_CLK_LINFLEX)] = &linflex_clk,
+	[S32CC_CLK_ID(S32CC_CLK_LINFLEX_BAUD)] = &linflex_baud_clk,
 };
 
 static struct s32cc_clk_array s32cc_arch_clocks = {
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index 2c256a5..8c4a9e8 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -4,15 +4,18 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <drivers/clk.h>
+#include <platform_def.h>
 #include <s32cc-clk-drv.h>
 #include <s32cc-clk-ids.h>
 #include <s32cc-clk-utils.h>
 
-#define S32CC_FXOSC_FREQ	(40U * MHZ)
-#define S32CC_ARM_PLL_VCO_FREQ	(2U * GHZ)
-#define S32CC_ARM_PLL_PHI0_FREQ	(1U * GHZ)
-#define S32CC_A53_FREQ		(1U * GHZ)
-#define S32CC_XBAR_2X_FREQ	(800U * MHZ)
+#define S32CC_FXOSC_FREQ		(40U * MHZ)
+#define S32CC_ARM_PLL_VCO_FREQ		(2U * GHZ)
+#define S32CC_ARM_PLL_PHI0_FREQ		(1U * GHZ)
+#define S32CC_A53_FREQ			(1U * GHZ)
+#define S32CC_XBAR_2X_FREQ		(800U * MHZ)
+#define S32CC_PERIPH_PLL_VCO_FREQ	(2U * GHZ)
+#define S32CC_PERIPH_PLL_PHI3_FREQ	UART_CLOCK_HZ
 
 static int enable_fxosc_clk(void)
 {
@@ -63,6 +66,38 @@
 	return ret;
 }
 
+static int enable_periph_pll(void)
+{
+	int ret;
+
+	ret = clk_set_parent(S32CC_CLK_PERIPH_PLL_MUX, S32CC_CLK_FXOSC);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_rate(S32CC_CLK_PERIPH_PLL_VCO, S32CC_PERIPH_PLL_VCO_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_rate(S32CC_CLK_PERIPH_PLL_PHI3, S32CC_PERIPH_PLL_PHI3_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_PERIPH_PLL_VCO);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_PERIPH_PLL_PHI3);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
+
 static int enable_a53_clk(void)
 {
 	int ret;
@@ -109,6 +144,23 @@
 		return ret;
 	}
 
+	return ret;
+}
+
+static int enable_uart_clk(void)
+{
+	int ret;
+
+	ret = clk_set_parent(S32CC_CLK_MC_CGM0_MUX8, S32CC_CLK_PERIPH_PLL_PHI3);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_LINFLEX_BAUD);
+	if (ret != 0) {
+		return ret;
+	}
+
 	return ret;
 }
 
@@ -128,6 +180,11 @@
 		return ret;
 	}
 
+	ret = enable_periph_pll();
+	if (ret != 0) {
+		return ret;
+	}
+
 	ret = enable_a53_clk();
 	if (ret != 0) {
 		return ret;
@@ -138,5 +195,10 @@
 		return ret;
 	}
 
+	ret = enable_uart_clk();
+	if (ret != 0) {
+		return ret;
+	}
+
 	return ret;
 }
diff --git a/drivers/nxp/console/linflex_console.S b/drivers/nxp/console/linflex_console.S
index abcbb59..d8c10ef 100644
--- a/drivers/nxp/console/linflex_console.S
+++ b/drivers/nxp/console/linflex_console.S
@@ -18,6 +18,7 @@
 
 #define LINFLEX_LINSR		(0x8)
 #define LINSR_LINS_INITMODE	(0x00001000)
+#define LINSR_LINS_RX_TX_MODE	(0x00008000)
 #define LINSR_LINS_MASK		(0x0000F000)
 
 #define LINFLEX_UARTCR		(0x10)
@@ -48,9 +49,11 @@
  */
 .globl console_linflex_core_init
 .globl console_linflex_core_putc
+.globl console_linflex_core_flush
 
 .globl console_linflex_register
 .globl console_linflex_putc
+.globl console_linflex_flush
 
 /**
  * uint32_t get_ldiv_mult(uintptr_t baseaddr, uint32_t clock,
@@ -175,10 +178,29 @@
 	str	x0, [x3, #CONSOLE_T_BASE]
 
 	mov	x0, x3
-	finish_console_register linflex, putc=1, getc=0, flush=0
+	finish_console_register linflex, putc=1, getc=0, flush=1
 endfunc console_linflex_register
 
 /**
+ * int console_linflex_core_flush(uintptr_t baseaddr);
+ *
+ * Loop while the TX fifo is not empty, depending on the selected UART mode.
+ *
+ * In:  x0 - Linflex base address
+ * Clobber list : x0 - x1
+ */
+func console_linflex_core_flush
+wait_rx_tx:
+	ldr	w1, [x0, LINFLEX_LINSR]
+	and	w1, w1, #LINSR_LINS_MASK
+	cmp	w1, #LINSR_LINS_RX_TX_MODE
+	b.eq	wait_rx_tx
+
+	mov	x0, #0
+	ret
+endfunc console_linflex_core_flush
+
+/**
  * int console_linflex_core_putc(int c, uintptr_t baseaddr);
 
  * Out: w0 - printed character on success, < 0 on error.
@@ -257,3 +279,21 @@
 	mov	x0, #-EINVAL
 	ret
 endfunc console_linflex_putc
+
+/**
+ * int console_linflex_flush(console_t *console);
+ *
+ * Function to wait for the TX FIFO to be cleared.
+ * In : x0 - pointer to console_t struct
+ * Out: x0 - return -1 on error else return 0.
+ * Clobber list : x0 - x1
+ */
+func console_linflex_flush
+	cbz	x0, flush_error
+	ldr	x0, [x0, #CONSOLE_T_BASE]
+
+	b	console_linflex_core_flush
+flush_error:
+	mov	x0, #-EINVAL
+	ret
+endfunc console_linflex_flush
diff --git a/fdts/cca_cot_descriptors.dtsi b/fdts/cca_cot_descriptors.dtsi
index 821f600..93d60ea 100644
--- a/fdts/cca_cot_descriptors.dtsi
+++ b/fdts/cca_cot_descriptors.dtsi
@@ -15,7 +15,7 @@
 		cca_content_cert: cca_content_cert {
 			root-certificate;
 			image-id =<CCA_CONTENT_CERT_ID>;
-			antirollback-counter = <&cca_nv_counter>;
+			antirollback-counter = <&cca_nv_ctr>;
 
 			tb_fw_hash: tb_fw_hash {
 				oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -44,7 +44,7 @@
 			root-certificate;
 			image-id = <CORE_SWD_KEY_CERT_ID>;
 			signing-key = <&swd_rot_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			core_swd_pk: core_swd_pk {
 				oid = CORE_SWD_PK_OID;
@@ -55,7 +55,7 @@
 			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
 			parent = <&core_swd_key_cert>;
 			signing-key = <&core_swd_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_hash: tos_fw_hash {
 				oid = TRUSTED_OS_FW_HASH_OID;
@@ -69,7 +69,7 @@
 			root-certificate;
 			image-id = <PLAT_KEY_CERT_ID>;
 			signing-key = <&prot_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			plat_pk: plat_pk {
 				oid = PLAT_PK_OID;
@@ -80,7 +80,7 @@
 			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
 			parent = <&plat_key_cert>;
 			signing-key = <&plat_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_world_bl_hash: nt_world_bl_hash {
 				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -95,7 +95,7 @@
 			image-id = <SIP_SP_CONTENT_CERT_ID>;
 			parent = <&core_swd_key_cert>;
 			signing-key = <&core_swd_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			sp_pkg1_hash: sp_pkg1_hash {
 				oid = SP_PKG1_HASH_OID;
@@ -115,7 +115,7 @@
 			image-id = <PLAT_SP_CONTENT_CERT_ID>;
 			parent = <&plat_key_cert>;
 			signing-key = <&plat_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			sp_pkg5_hash: sp_pkg5_hash {
 				oid = SP_PKG5_HASH_OID;
@@ -242,17 +242,17 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 
-	cca_nv_counter: cca_nv_counter {
+	cca_nv_ctr: cca_nv_ctr {
 		id  = <TRUSTED_NV_CTR_ID>;
 		oid = CCA_FW_NVCOUNTER_OID;
 	};
 
-	trusted_nv_counter: trusted_nv_counter {
+	trusted_nv_ctr: trusted_nv_ctr {
 		id  = <TRUSTED_NV_CTR_ID>;
 		oid = TRUSTED_FW_NVCOUNTER_OID;
 	};
 
-	non_trusted_nv_counter: non_trusted_nv_counter {
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
 		id  = <NON_TRUSTED_NV_CTR_ID>;
 		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
 	};
diff --git a/fdts/dualroot_cot_descriptors.dtsi b/fdts/dualroot_cot_descriptors.dtsi
index 459a1dd..bea7af5 100644
--- a/fdts/dualroot_cot_descriptors.dtsi
+++ b/fdts/dualroot_cot_descriptors.dtsi
@@ -15,7 +15,7 @@
 		trusted_boot_fw_cert: trusted_boot_fw_cert {
 			root-certificate;
 			image-id =<TRUSTED_BOOT_FW_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tb_fw_hash: tb_fw_hash {
 				oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -34,7 +34,7 @@
 		trusted_key_cert: trusted_key_cert {
 			root-certificate;
 			image-id = <TRUSTED_KEY_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			trusted_world_pk: trusted_world_pk {
 				oid = TRUSTED_WORLD_PK_OID;
@@ -45,7 +45,7 @@
 			image-id = <SCP_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			scp_fw_content_pk: scp_fw_content_pk {
 				oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -56,7 +56,7 @@
 			image-id = <SCP_FW_CONTENT_CERT_ID>;
 			parent = <&scp_fw_key_cert>;
 			signing-key = <&scp_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			scp_fw_hash: scp_fw_hash {
 				oid = SCP_FW_HASH_OID;
@@ -67,7 +67,7 @@
 			image-id = <SOC_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 			soc_fw_content_pk: soc_fw_content_pk {
 				oid = SOC_FW_CONTENT_CERT_PK_OID;
 			};
@@ -77,7 +77,7 @@
 			image-id = <SOC_FW_CONTENT_CERT_ID>;
 			parent = <&soc_fw_key_cert>;
 			signing-key = <&soc_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			soc_fw_hash: soc_fw_hash {
 				oid = SOC_AP_FW_HASH_OID;
@@ -91,7 +91,7 @@
 			image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_content_pk: tos_fw_content_pk {
 				oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -102,7 +102,7 @@
 			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
 			parent = <&trusted_os_fw_key_cert>;
 			signing-key = <&tos_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_hash: tos_fw_hash {
 				oid = TRUSTED_OS_FW_HASH_OID;
@@ -122,7 +122,7 @@
 			root-certificate;
 			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
 			signing-key = <&prot_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_world_bl_hash: nt_world_bl_hash {
 				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -137,7 +137,7 @@
 			image-id = <SIP_SP_CONTENT_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			sp_pkg1_hash: sp_pkg1_hash {
 				oid = SP_PKG1_HASH_OID;
@@ -157,7 +157,7 @@
 			root-certificate;
 			image-id = <PLAT_SP_CONTENT_CERT_ID>;
 			signing-key = <&prot_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			sp_pkg5_hash: sp_pkg5_hash {
 				oid = SP_PKG5_HASH_OID;
@@ -296,12 +296,12 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 
-	trusted_nv_counter: trusted_nv_counter {
+	trusted_nv_ctr: trusted_nv_ctr {
 		id  = <TRUSTED_NV_CTR_ID>;
 		oid = TRUSTED_FW_NVCOUNTER_OID;
 	};
 
-	non_trusted_nv_counter: non_trusted_nv_counter {
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
 		id  = <NON_TRUSTED_NV_CTR_ID>;
 		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
 	};
diff --git a/fdts/stm32mp1-cot-descriptors.dtsi b/fdts/stm32mp1-cot-descriptors.dtsi
index eb632ff..05326be 100644
--- a/fdts/stm32mp1-cot-descriptors.dtsi
+++ b/fdts/stm32mp1-cot-descriptors.dtsi
@@ -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
  */
@@ -15,7 +15,7 @@
 		stm32mp_cfg_cert: stm32mp_cfg_cert {
 			root-certificate;
 			image-id = <STM32MP_CONFIG_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			hw_config_hash: hw_config_hash {
 				oid = HW_CONFIG_HASH_OID;
@@ -29,7 +29,7 @@
 		trusted_key_cert: trusted_key_cert {
 			root-certificate;
 			image-id = <TRUSTED_KEY_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			trusted_world_pk: trusted_world_pk {
 				oid = TRUSTED_WORLD_PK_OID;
@@ -43,7 +43,7 @@
 			image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_content_pk: tos_fw_content_pk {
 				oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -54,7 +54,7 @@
 			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
 			parent = <&trusted_os_fw_key_cert>;
 			signing-key = <&tos_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_hash: tos_fw_hash {
 				oid = TRUSTED_OS_FW_HASH_OID;
@@ -74,7 +74,7 @@
 			image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&non_trusted_world_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_fw_content_pk: nt_fw_content_pk {
 				oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
@@ -85,7 +85,7 @@
 			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
 			parent = <&non_trusted_fw_key_cert>;
 			signing-key = <&nt_fw_content_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_world_bl_hash: nt_world_bl_hash {
 				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -144,12 +144,12 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 
-	trusted_nv_counter: trusted_nv_counter {
+	trusted_nv_ctr: trusted_nv_ctr {
 		id  = <TRUSTED_NV_CTR_ID>;
 		oid = TRUSTED_FW_NVCOUNTER_OID;
 	};
 
-	non_trusted_nv_counter: non_trusted_nv_counter {
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
 		id  = <NON_TRUSTED_NV_CTR_ID>;
 		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
 	};
diff --git a/fdts/tbbr_cot_descriptors.dtsi b/fdts/tbbr_cot_descriptors.dtsi
index d11e2be..b3c0ca7 100644
--- a/fdts/tbbr_cot_descriptors.dtsi
+++ b/fdts/tbbr_cot_descriptors.dtsi
@@ -4,7 +4,12 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#if USE_TBBR_DEFS
 #include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
 #include <common/tbbr/tbbr_img_def.h>
 #include <common/nv_cntr_ids.h>
 
@@ -15,7 +20,7 @@
 		trusted_boot_fw_cert: trusted_boot_fw_cert {
 			root-certificate;
 			image-id =<TRUSTED_BOOT_FW_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tb_fw_hash: tb_fw_hash {
 				oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -34,7 +39,7 @@
 		trusted_key_cert: trusted_key_cert {
 			root-certificate;
 			image-id = <TRUSTED_KEY_CERT_ID>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			trusted_world_pk: trusted_world_pk {
 				oid = TRUSTED_WORLD_PK_OID;
@@ -48,7 +53,7 @@
 			image-id = <SCP_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			scp_fw_content_pk: scp_fw_content_pk {
 				oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -59,7 +64,7 @@
 			image-id = <SCP_FW_CONTENT_CERT_ID>;
 			parent = <&scp_fw_key_cert>;
 			signing-key = <&scp_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			scp_fw_hash: scp_fw_hash {
 				oid = SCP_FW_HASH_OID;
@@ -70,7 +75,7 @@
 			image-id = <SOC_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 			soc_fw_content_pk: soc_fw_content_pk {
 				oid = SOC_FW_CONTENT_CERT_PK_OID;
 			};
@@ -80,7 +85,7 @@
 			image-id = <SOC_FW_CONTENT_CERT_ID>;
 			parent = <&soc_fw_key_cert>;
 			signing-key = <&soc_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			soc_fw_hash: soc_fw_hash {
 				oid = SOC_AP_FW_HASH_OID;
@@ -94,7 +99,7 @@
 			image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_content_pk: tos_fw_content_pk {
 				oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -105,7 +110,7 @@
 			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
 			parent = <&trusted_os_fw_key_cert>;
 			signing-key = <&tos_fw_content_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			tos_fw_hash: tos_fw_hash {
 				oid = TRUSTED_OS_FW_HASH_OID;
@@ -125,7 +130,7 @@
 			image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&non_trusted_world_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_fw_content_pk: nt_fw_content_pk {
 				oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
@@ -136,7 +141,7 @@
 			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
 			parent = <&non_trusted_fw_key_cert>;
 			signing-key = <&nt_fw_content_pk>;
-			antirollback-counter = <&non_trusted_nv_counter>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
 
 			nt_world_bl_hash: nt_world_bl_hash {
 				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -151,7 +156,7 @@
 			image-id = <SIP_SP_CONTENT_CERT_ID>;
 			parent = <&trusted_key_cert>;
 			signing-key = <&trusted_world_pk>;
-			antirollback-counter = <&trusted_nv_counter>;
+			antirollback-counter = <&trusted_nv_ctr>;
 
 			sp_pkg1_hash: sp_pkg1_hash {
 				oid = SP_PKG1_HASH_OID;
@@ -302,12 +307,12 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 
-	trusted_nv_counter: trusted_nv_counter {
+	trusted_nv_ctr: trusted_nv_ctr {
 		id  = <TRUSTED_NV_CTR_ID>;
 		oid = TRUSTED_FW_NVCOUNTER_OID;
 	};
 
-	non_trusted_nv_counter: non_trusted_nv_counter {
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
 		id  = <NON_TRUSTED_NV_CTR_ID>;
 		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
 	};
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 52ed2b9..d8ad881 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -24,6 +24,9 @@
 #define MIDR_PN_MASK		U(0xfff)
 #define MIDR_PN_SHIFT		U(0x4)
 
+/* Extracts the CPU part number from MIDR for checking CPU match */
+#define EXTRACT_PARTNUM(x)     ((x >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+
 /*******************************************************************************
  * MPIDR macros
  ******************************************************************************/
diff --git a/include/common/feat_detect.h b/include/common/feat_detect.h
index 788dfb3..b85e1ce 100644
--- a/include/common/feat_detect.h
+++ b/include/common/feat_detect.h
@@ -11,8 +11,9 @@
 void detect_arch_features(void);
 
 /* Macro Definitions */
-#define FEAT_STATE_DISABLED	0
-#define FEAT_STATE_ALWAYS	1
-#define FEAT_STATE_CHECK	2
+#define FEAT_STATE_DISABLED		0
+#define FEAT_STATE_ALWAYS		1
+#define FEAT_STATE_CHECK		2
+#define FEAT_STATE_CHECK_ASYMMETRIC	3
 
 #endif /* FEAT_DETECT_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
index b95cd32..de633ae 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
@@ -87,4 +87,12 @@
 #define S32CC_CLK_XBAR_DIV4			S32CC_ARCH_CLK(11)
 #define S32CC_CLK_XBAR_DIV6			S32CC_ARCH_CLK(12)
 
+/* Periph PLL */
+#define S32CC_CLK_PERIPH_PLL_MUX		S32CC_ARCH_CLK(13)
+#define S32CC_CLK_PERIPH_PLL_VCO		S32CC_ARCH_CLK(14)
+
+#define S32CC_CLK_MC_CGM0_MUX8			S32CC_ARCH_CLK(15)
+#define S32CC_CLK_LINFLEX_BAUD			S32CC_ARCH_CLK(16)
+#define S32CC_CLK_LINFLEX			S32CC_ARCH_CLK(17)
+
 #endif /* S32CC_CLK_IDS_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
index 703713b..a6d58cc 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -30,6 +30,7 @@
 	S32CC_SIRC,
 	S32CC_ARM_PLL,
 	S32CC_ARM_DFS,
+	S32CC_PERIPH_PLL,
 	S32CC_CGM0,
 	S32CC_CGM1,
 };
diff --git a/include/lib/cpus/aarch64/cortex_a520.h b/include/lib/cpus/aarch64/cortex_a520.h
index ed3401d..11ddea9 100644
--- a/include/lib/cpus/aarch64/cortex_a520.h
+++ b/include/lib/cpus/aarch64/cortex_a520.h
@@ -28,4 +28,15 @@
 #define CORTEX_A520_CPUPWRCTLR_EL1				S3_0_C15_C2_7
 #define CORTEX_A520_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
 
+#ifndef __ASSEMBLER__
+#if ERRATA_A520_2938996
+long  check_erratum_cortex_a520_2938996(long cpu_rev);
+#else
+static inline long  check_erratum_cortex_a520_2938996(long cpu_rev)
+{
+       return 0;
+}
+#endif /* ERRATA_A520_2938996 */
+#endif /* __ASSEMBLER__ */
+
 #endif /* CORTEX_A520_H */
diff --git a/include/lib/cpus/aarch64/cortex_a720.h b/include/lib/cpus/aarch64/cortex_a720.h
index fb27f79..129c1ee 100644
--- a/include/lib/cpus/aarch64/cortex_a720.h
+++ b/include/lib/cpus/aarch64/cortex_a720.h
@@ -23,6 +23,11 @@
 #define CORTEX_A720_CPUACTLR2_EL1				S3_0_C15_C1_1
 
 /*******************************************************************************
+ * CPU Auxiliary Control register 4 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A720_CPUACTLR4_EL1				S3_0_C15_C1_3
+
+/*******************************************************************************
  * CPU Extended Control register specific definitions
  ******************************************************************************/
 #define CORTEX_A720_CPUECTLR_EL1				S3_0_C15_C1_4
diff --git a/include/lib/cpus/aarch64/cortex_x4.h b/include/lib/cpus/aarch64/cortex_x4.h
index 433687b..4b6af8b 100644
--- a/include/lib/cpus/aarch64/cortex_x4.h
+++ b/include/lib/cpus/aarch64/cortex_x4.h
@@ -28,4 +28,21 @@
  ******************************************************************************/
 #define CORTEX_X4_CPUACTLR3_EL1				S3_0_C15_C1_2
 
+/*******************************************************************************
+ * CPU Auxiliary control register 5 specific definitions
+ ******************************************************************************/
+#define CORTEX_X4_CPUACTLR5_EL1				S3_0_C15_C8_0
+#define CORTEX_X4_CPUACTLR5_EL1_BIT_14			(ULL(1) << 14)
+
+#ifndef __ASSEMBLER__
+#if ERRATA_X4_2726228
+long check_erratum_cortex_x4_2726228(long cpu_rev);
+#else
+static inline long check_erratum_cortex_x4_2726228(long cpu_rev)
+{
+       return 0;
+}
+#endif /* ERRATA_X4_2726228 */
+#endif /* __ASSEMBLER__ */
+
 #endif /* CORTEX_X4_H */
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index 2080898..a8eb84c 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -25,12 +25,21 @@
 #define ERRATUM_MITIGATED	ERRATUM_CHOSEN + ERRATUM_CHOSEN_SIZE
 #define ERRATUM_ENTRY_SIZE	ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
 
+/* Errata status */
+#define ERRATA_NOT_APPLIES	0
+#define ERRATA_APPLIES		1
+#define ERRATA_MISSING		2
+
 #ifndef __ASSEMBLER__
 #include <lib/cassert.h>
 
 void print_errata_status(void);
 void errata_print_msg(unsigned int status, const char *cpu, const char *id);
 
+#if ERRATA_A520_2938996 || ERRATA_X4_2726228
+unsigned int check_if_affected_core(void);
+#endif
+
 /*
  * NOTE that this structure will be different on AArch32 and AArch64. The
  * uintptr_t will reflect the change and the alignment will be correct in both.
@@ -74,11 +83,6 @@
 
 #endif /* __ASSEMBLER__ */
 
-/* Errata status */
-#define ERRATA_NOT_APPLIES	0
-#define ERRATA_APPLIES		1
-#define ERRATA_MISSING		2
-
 /* Macro to get CPU revision code for checking errata version compatibility. */
 #define CPU_REV(r, p)		((r << 4) | p)
 
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 7c10506..87f1541 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -7,9 +7,18 @@
 #ifndef CONTEXT_H
 #define CONTEXT_H
 
-#include <lib/el3_runtime/context_el1.h>
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 #include <lib/el3_runtime/context_el2.h>
+#else
+/**
+ * El1 context is required either when:
+ * IMAGE_BL1 || ((!CTX_INCLUDE_EL2_REGS) && IMAGE_BL31)
+ */
+#include <lib/el3_runtime/context_el1.h>
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
+
 #include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/simd_ctx.h>
 #include <lib/utils_def.h>
 
 /*******************************************************************************
@@ -82,60 +91,11 @@
  #define CTX_EL3STATE_END	U(0x50) /* Align to the next 16 byte boundary */
 #endif /* FFH_SUPPORT */
 
-/*******************************************************************************
- * Constants that allow assembler code to access members of and the 'fp_regs'
- * structure at their correct offsets.
- ******************************************************************************/
-# define CTX_FPREGS_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
-#if CTX_INCLUDE_FPREGS
-#define CTX_FP_Q0		U(0x0)
-#define CTX_FP_Q1		U(0x10)
-#define CTX_FP_Q2		U(0x20)
-#define CTX_FP_Q3		U(0x30)
-#define CTX_FP_Q4		U(0x40)
-#define CTX_FP_Q5		U(0x50)
-#define CTX_FP_Q6		U(0x60)
-#define CTX_FP_Q7		U(0x70)
-#define CTX_FP_Q8		U(0x80)
-#define CTX_FP_Q9		U(0x90)
-#define CTX_FP_Q10		U(0xa0)
-#define CTX_FP_Q11		U(0xb0)
-#define CTX_FP_Q12		U(0xc0)
-#define CTX_FP_Q13		U(0xd0)
-#define CTX_FP_Q14		U(0xe0)
-#define CTX_FP_Q15		U(0xf0)
-#define CTX_FP_Q16		U(0x100)
-#define CTX_FP_Q17		U(0x110)
-#define CTX_FP_Q18		U(0x120)
-#define CTX_FP_Q19		U(0x130)
-#define CTX_FP_Q20		U(0x140)
-#define CTX_FP_Q21		U(0x150)
-#define CTX_FP_Q22		U(0x160)
-#define CTX_FP_Q23		U(0x170)
-#define CTX_FP_Q24		U(0x180)
-#define CTX_FP_Q25		U(0x190)
-#define CTX_FP_Q26		U(0x1a0)
-#define CTX_FP_Q27		U(0x1b0)
-#define CTX_FP_Q28		U(0x1c0)
-#define CTX_FP_Q29		U(0x1d0)
-#define CTX_FP_Q30		U(0x1e0)
-#define CTX_FP_Q31		U(0x1f0)
-#define CTX_FP_FPSR		U(0x200)
-#define CTX_FP_FPCR		U(0x208)
-#if CTX_INCLUDE_AARCH32_REGS
-#define CTX_FP_FPEXC32_EL2	U(0x210)
-#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 /* CTX_INCLUDE_AARCH32_REGS */
-#else
-#define CTX_FPREGS_END		U(0)
-#endif /* CTX_INCLUDE_FPREGS */
 
 /*******************************************************************************
  * Registers related to CVE-2018-3639
  ******************************************************************************/
-#define CTX_CVE_2018_3639_OFFSET	(CTX_FPREGS_OFFSET + CTX_FPREGS_END)
+#define CTX_CVE_2018_3639_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
 #define CTX_CVE_2018_3639_DISABLE	U(0)
 #define CTX_CVE_2018_3639_END		U(0x10) /* Align to the next 16 byte boundary */
 
@@ -230,9 +190,6 @@
 /* Constants to determine the size of individual context structures */
 #define CTX_GPREG_ALL		(CTX_GPREGS_END >> DWORD_SHIFT)
 
-#if CTX_INCLUDE_FPREGS
-# define CTX_FPREG_ALL		(CTX_FPREGS_END >> DWORD_SHIFT)
-#endif
 #define CTX_EL3STATE_ALL	(CTX_EL3STATE_END >> DWORD_SHIFT)
 #define CTX_CVE_2018_3639_ALL	(CTX_CVE_2018_3639_END >> DWORD_SHIFT)
 
@@ -253,15 +210,6 @@
 DEFINE_REG_STRUCT(gp_regs, CTX_GPREG_ALL);
 
 /*
- * AArch64 floating point register context structure for preserving
- * the floating point state during switches from one security state to
- * another.
- */
-#if CTX_INCLUDE_FPREGS
-DEFINE_REG_STRUCT(fp_regs, CTX_FPREG_ALL);
-#endif
-
-/*
  * Miscellaneous registers used by EL3 firmware to maintain its state
  * across exception entries and exits
  */
@@ -300,9 +248,6 @@
 	gp_regs_t gpregs_ctx;
 	el3_state_t el3state_ctx;
 
-#if CTX_INCLUDE_FPREGS
-	fp_regs_t fpregs_ctx;
-#endif
 	cve_2018_3639_t cve_2018_3639_ctx;
 
 #if ERRATA_SPECULATIVE_AT
@@ -313,10 +258,16 @@
 	pauth_t pauth_ctx;
 #endif
 
-	el1_sysregs_t el1_sysregs_ctx;
-
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 	el2_sysregs_t el2_sysregs_ctx;
+#else
+	/* El1 context should be included only either for IMAGE_BL1,
+	 * or for IMAGE_BL31 when CTX_INCLUDE_EL2_REGS=0:
+	 * When SPMD_SPM_AT_SEL2=1, SPMC at S-EL2 takes care of saving
+	 * and restoring EL1 registers. In this case, BL31 at EL3 can
+	 * exclude save and restore of EL1 context registers.
+	 */
+	el1_sysregs_t el1_sysregs_ctx;
 #endif
 
 } cpu_context_t;
@@ -335,13 +286,13 @@
 
 /* Macros to access members of the 'cpu_context_t' structure */
 #define get_el3state_ctx(h)	(&((cpu_context_t *) h)->el3state_ctx)
-#if CTX_INCLUDE_FPREGS
-# define get_fpregs_ctx(h)	(&((cpu_context_t *) h)->fpregs_ctx)
-#endif
+
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
+#define get_el2_sysregs_ctx(h)	(&((cpu_context_t *) h)->el2_sysregs_ctx)
+#else
 #define get_el1_sysregs_ctx(h)	(&((cpu_context_t *) h)->el1_sysregs_ctx)
-#if CTX_INCLUDE_EL2_REGS
-# define get_el2_sysregs_ctx(h)	(&((cpu_context_t *) h)->el2_sysregs_ctx)
 #endif
+
 #define get_gpregs_ctx(h)	(&((cpu_context_t *) h)->gpregs_ctx)
 #define get_cve_2018_3639_ctx(h)	(&((cpu_context_t *) h)->cve_2018_3639_ctx)
 
@@ -364,10 +315,6 @@
 CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx),
 	assert_core_context_el3state_offset_mismatch);
 
-#if CTX_INCLUDE_FPREGS
-CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx),
-	assert_core_context_fp_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);
@@ -422,10 +369,73 @@
  * Function prototypes
  ******************************************************************************/
 #if CTX_INCLUDE_FPREGS
-void fpregs_context_save(fp_regs_t *regs);
-void fpregs_context_restore(fp_regs_t *regs);
+void fpregs_context_save(simd_regs_t *regs);
+void fpregs_context_restore(simd_regs_t *regs);
 #endif
 
+/*******************************************************************************
+ * The next four inline functions are required for IMAGE_BL1, as well as for
+ * IMAGE_BL31 for the below combinations.
+ * ============================================================================
+ * | ERRATA_SPECULATIVE_AT| CTX_INCLUDE_EL2_REGS |   Combination              |
+ * ============================================================================
+ * |       0              |       0              |   Valid (EL1 ctx)          |
+ * |______________________|______________________|____________________________|
+ * |                      |                      | Invalid (No Errata/EL1 Ctx)|
+ * |       0              |       1              | Hence commented out.       |
+ * |______________________|______________________|____________________________|
+ * |                      |                      |                            |
+ * |       1              |       0              |   Valid (Errata ctx)       |
+ * |______________________|______________________|____________________________|
+ * |                      |                      |                            |
+ * |       1              |       1              |   Valid (Errata ctx)       |
+ * |______________________|______________________|____________________________|
+ * ============================================================================
+ ******************************************************************************/
+#if (IMAGE_BL1 || ((ERRATA_SPECULATIVE_AT) || (!CTX_INCLUDE_EL2_REGS)))
+
+static inline void write_ctx_sctlr_el1_reg_errata(cpu_context_t *ctx, u_register_t val)
+{
+#if (ERRATA_SPECULATIVE_AT)
+	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
+		      CTX_ERRATA_SPEC_AT_SCTLR_EL1, val);
+#else
+	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1, val);
+#endif /* ERRATA_SPECULATIVE_AT */
+}
+
+static inline void write_ctx_tcr_el1_reg_errata(cpu_context_t *ctx, u_register_t val)
+{
+#if (ERRATA_SPECULATIVE_AT)
+	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
+		      CTX_ERRATA_SPEC_AT_TCR_EL1, val);
+#else
+	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), tcr_el1, val);
+#endif /* ERRATA_SPECULATIVE_AT */
+}
+
+static inline u_register_t read_ctx_sctlr_el1_reg_errata(cpu_context_t *ctx)
+{
+#if (ERRATA_SPECULATIVE_AT)
+	return read_ctx_reg(get_errata_speculative_at_ctx(ctx),
+		      CTX_ERRATA_SPEC_AT_SCTLR_EL1);
+#else
+	return read_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1);
+#endif /* ERRATA_SPECULATIVE_AT */
+}
+
+static inline u_register_t read_ctx_tcr_el1_reg_errata(cpu_context_t *ctx)
+{
+#if (ERRATA_SPECULATIVE_AT)
+	return read_ctx_reg(get_errata_speculative_at_ctx(ctx),
+		      CTX_ERRATA_SPEC_AT_TCR_EL1);
+#else
+	return read_el1_ctx_common(get_el1_sysregs_ctx(ctx), tcr_el1);
+#endif /* ERRATA_SPECULATIVE_AT */
+}
+
+#endif /* (IMAGE_BL1 || ((ERRATA_SPECULATIVE_AT) || (!CTX_INCLUDE_EL2_REGS))) */
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* CONTEXT_H */
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
index ca1ea4e..14c1fb6 100644
--- a/include/lib/el3_runtime/context_el2.h
+++ b/include/lib/el3_runtime/context_el2.h
@@ -13,7 +13,6 @@
  * 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;
@@ -359,7 +358,6 @@
 #define write_el2_ctx_mpam(ctx, reg, val)
 #endif /* CTX_INCLUDE_MPAM_REGS */
 
-#endif /* CTX_INCLUDE_EL2_REGS */
 /******************************************************************************/
 
 #endif /* __ASSEMBLER__ */
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
index 7451b85..70dbd46 100644
--- a/include/lib/el3_runtime/context_mgmt.h
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -44,15 +44,17 @@
 void cm_manage_extensions_el3(void);
 void manage_extensions_nonsecure_per_world(void);
 void cm_el3_arch_init_per_world(per_world_context_t *per_world_ctx);
+void cm_handle_asymmetric_features(void);
 #endif
 
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 void cm_el2_sysregs_context_save(uint32_t security_state);
 void cm_el2_sysregs_context_restore(uint32_t security_state);
-#endif
-
+#else
 void cm_el1_sysregs_context_save(uint32_t security_state);
 void cm_el1_sysregs_context_restore(uint32_t security_state);
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
+
 void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint);
 void cm_set_elr_spsr_el3(uint32_t security_state,
 			uintptr_t entrypoint, uint32_t spsr);
@@ -95,6 +97,7 @@
 void cm_set_next_context(void *context);
 static inline void cm_manage_extensions_el3(void) {}
 static inline void manage_extensions_nonsecure_per_world(void) {}
+static inline void cm_handle_asymmetric_features(void) {}
 #endif /* __aarch64__ */
 
 #endif /* CONTEXT_MGMT_H */
diff --git a/include/lib/el3_runtime/simd_ctx.h b/include/lib/el3_runtime/simd_ctx.h
new file mode 100644
index 0000000..fdbe24f
--- /dev/null
+++ b/include/lib/el3_runtime/simd_ctx.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SIMD_CTX_H
+#define SIMD_CTX_H
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the 'simd_context'
+ * structure at their correct offsets.
+ ******************************************************************************/
+
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+#if CTX_INCLUDE_SVE_REGS
+#define SIMD_VECTOR_LEN_BYTES	(SVE_VECTOR_LEN / 8) /* Length of vector in bytes */
+#elif CTX_INCLUDE_FPREGS
+#define SIMD_VECTOR_LEN_BYTES	U(16) /* 128 bits fixed vector length for FPU */
+#endif /* CTX_INCLUDE_SVE_REGS */
+
+#define CTX_SIMD_VECTORS	U(0)
+/* there are 32 vector registers, each of size SIMD_VECTOR_LEN_BYTES */
+#define CTX_SIMD_FPSR		(CTX_SIMD_VECTORS + (32 * SIMD_VECTOR_LEN_BYTES))
+#define CTX_SIMD_FPCR		(CTX_SIMD_FPSR + 8)
+
+#if CTX_INCLUDE_FPREGS && CTX_INCLUDE_AARCH32_REGS
+#define CTX_SIMD_FPEXC32	(CTX_SIMD_FPCR + 8)
+#define CTX_SIMD_PREDICATES	(CTX_SIMD_FPEXC32 + 16)
+#else
+#define CTX_SIMD_PREDICATES      (CTX_SIMD_FPCR + 8)
+#endif /* CTX_INCLUDE_FPREGS && CTX_INCLUDE_AARCH32_REGS */
+
+/*
+ * Each predicate register is 1/8th the size of a vector register and there are 16
+ * predicate registers
+ */
+#define CTX_SIMD_FFR		(CTX_SIMD_PREDICATES + (16 * (SIMD_VECTOR_LEN_BYTES / 8)))
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+#include <lib/cassert.h>
+
+/*
+ * Please don't change order of fields in this struct as that may violate
+ * alignment requirements and affect how assembly code accesses members of this
+ * struct.
+ */
+typedef struct {
+	uint8_t vectors[32][SIMD_VECTOR_LEN_BYTES];
+	uint8_t fpsr[8];
+	uint8_t fpcr[8];
+#if CTX_INCLUDE_FPREGS && CTX_INCLUDE_AARCH32_REGS
+	/* 16 bytes to align to next 16 byte boundary when CTX_INCLUDE_SVE_REGS is 0 */
+	uint8_t fpexc32_el2[16];
+#endif
+#if CTX_INCLUDE_SVE_REGS
+	/* FFR and each of predicates is one-eigth of the SVE vector length */
+	uint8_t predicates[16][SIMD_VECTOR_LEN_BYTES / 8];
+	uint8_t ffr[SIMD_VECTOR_LEN_BYTES / 8];
+	/* SMCCCv1.3 FID[16] hint bit state recorded on EL3 entry */
+	bool hint;
+#endif /* CTX_INCLUDE_SVE_REGS */
+} __aligned(16) simd_regs_t;
+
+CASSERT(CTX_SIMD_VECTORS == __builtin_offsetof(simd_regs_t, vectors),
+		assert_vectors_mismatch);
+
+CASSERT(CTX_SIMD_FPSR == __builtin_offsetof(simd_regs_t, fpsr),
+		assert_fpsr_mismatch);
+
+CASSERT(CTX_SIMD_FPCR == __builtin_offsetof(simd_regs_t, fpcr),
+		assert_fpcr_mismatch);
+
+#if CTX_INCLUDE_FPREGS && CTX_INCLUDE_AARCH32_REGS
+CASSERT(CTX_SIMD_FPEXC32 == __builtin_offsetof(simd_regs_t, fpexc32_el2),
+		assert_fpex32_mismtatch);
+#endif
+
+#if CTX_INCLUDE_SVE_REGS
+CASSERT(CTX_SIMD_PREDICATES == __builtin_offsetof(simd_regs_t, predicates),
+		assert_predicates_mismatch);
+
+CASSERT(CTX_SIMD_FFR == __builtin_offsetof(simd_regs_t, ffr),
+		assert_ffr_mismatch);
+#endif
+
+void simd_ctx_save(uint32_t security_state, bool hint_sve);
+void simd_ctx_restore(uint32_t security_state);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
+
+#endif /* SIMD_CTX_H */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
index 947c905..2979efb 100644
--- a/include/lib/extensions/sve.h
+++ b/include/lib/extensions/sve.h
@@ -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
  */
@@ -10,6 +10,7 @@
 #include <context.h>
 
 #if (ENABLE_SME_FOR_NS || ENABLE_SVE_FOR_NS)
+
 void sve_init_el2_unused(void);
 void sve_enable_per_world(per_world_context_t *per_world_ctx);
 void sve_disable_per_world(per_world_context_t *per_world_ctx);
@@ -25,4 +26,9 @@
 }
 #endif /* ( ENABLE_SME_FOR_NS | ENABLE_SVE_FOR_NS ) */
 
+#if CTX_INCLUDE_SVE_REGS
+void sve_context_save(simd_regs_t *regs);
+void sve_context_restore(simd_regs_t *regs);
+#endif
+
 #endif /* SVE_H */
diff --git a/lib/cpus/aarch64/cortex_a520.S b/lib/cpus/aarch64/cortex_a520.S
index 74ecbf7..b8f1468 100644
--- a/lib/cpus/aarch64/cortex_a520.S
+++ b/lib/cpus/aarch64/cortex_a520.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
  */
@@ -11,6 +11,9 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+/* .global erratum_cortex_a520_2938996_wa */
+.global check_erratum_cortex_a520_2938996
+
 /* Hardware handled coherency */
 #if HW_ASSISTED_COHERENCY == 0
 #error "Cortex A520 must be compiled with HW_ASSISTED_COHERENCY enabled"
@@ -32,6 +35,25 @@
 workaround_reset_end cortex_a520, ERRATUM(2858100)
 
 check_erratum_ls cortex_a520, ERRATUM(2858100), CPU_REV(0, 1)
+
+workaround_runtime_start cortex_a520, ERRATUM(2938996), ERRATA_A520_2938996, CORTEX_A520_MIDR
+workaround_runtime_end cortex_a520, ERRATUM(2938996)
+
+check_erratum_custom_start cortex_a520, ERRATUM(2938996)
+
+       /* This erratum needs to be enabled for r0p0 and r0p1.
+        * Check if revision is less than or equal to r0p1.
+        */
+
+#if ERRATA_A520_2938996
+       mov     x1, #1
+       b       cpu_rev_var_ls
+#else
+       mov     x0, #ERRATA_MISSING
+#endif
+       ret
+check_erratum_custom_end cortex_a520, ERRATUM(2938996)
+
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
 	 * ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a720.S b/lib/cpus/aarch64/cortex_a720.S
index 53a1b78..9cc3cbc 100644
--- a/lib/cpus/aarch64/cortex_a720.S
+++ b/lib/cpus/aarch64/cortex_a720.S
@@ -26,6 +26,18 @@
         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(2792132), ERRATA_A720_2792132
+        sysreg_bit_set CORTEX_A720_CPUACTLR2_EL1, BIT(26)
+workaround_reset_end cortex_a720, ERRATUM(2792132)
+
+check_erratum_ls cortex_a720, ERRATUM(2792132), CPU_REV(0, 1)
+
+workaround_reset_start cortex_a720, ERRATUM(2844092), ERRATA_A720_2844092
+        sysreg_bit_set CORTEX_A720_CPUACTLR4_EL1, BIT(11)
+workaround_reset_end cortex_a720, ERRATUM(2844092)
+
+check_erratum_ls cortex_a720, ERRATUM(2844092), CPU_REV(0, 1)
+
 workaround_reset_start cortex_a720, ERRATUM(2926083), ERRATA_A720_2926083
 /* Erratum 2926083 workaround is required only if SPE is enabled */
 #if ENABLE_SPE_FOR_NS != 0
diff --git a/lib/cpus/aarch64/cortex_x4.S b/lib/cpus/aarch64/cortex_x4.S
index 20f1ae1..7c9a5a4 100644
--- a/lib/cpus/aarch64/cortex_x4.S
+++ b/lib/cpus/aarch64/cortex_x4.S
@@ -22,10 +22,30 @@
 #error "Cortex X4 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+.global check_erratum_cortex_x4_2726228
+
 #if WORKAROUND_CVE_2022_23960
         wa_cve_2022_23960_bhb_vector_table CORTEX_X4_BHB_LOOP_COUNT, cortex_x4
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+workaround_runtime_start cortex_x4, ERRATUM(2726228), ERRATA_X4_2726228, CORTEX_X4_MIDR
+workaround_runtime_end cortex_x4, ERRATUM(2726228)
+
+check_erratum_custom_start cortex_x4, ERRATUM(2726228)
+
+	/* This erratum needs to be enabled for r0p0 and r0p1.
+	 * Check if revision is less than or equal to r0p1.
+	 */
+
+#if ERRATA_X4_2726228
+	mov	x1, #1
+	b	cpu_rev_var_ls
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+check_erratum_custom_end cortex_x4, ERRATUM(2726228)
+
 workaround_runtime_start cortex_x4, ERRATUM(2740089), ERRATA_X4_2740089
 	/* dsb before isb of power down sequence */
 	dsb	sy
@@ -39,6 +59,16 @@
 
 check_erratum_ls cortex_x4, ERRATUM(2763018), CPU_REV(0, 1)
 
+workaround_reset_start cortex_x4, ERRATUM(2816013), ERRATA_X4_2816013
+	mrs x1, id_aa64pfr1_el1
+	ubfx x2, x1, ID_AA64PFR1_EL1_MTE_SHIFT, #4
+	cbz x2, #1f
+	sysreg_bit_set CORTEX_X4_CPUACTLR5_EL1, BIT(14)
+1:
+workaround_reset_end cortex_x4, ERRATUM(2816013)
+
+check_erratum_ls cortex_x4, ERRATUM(2816013), CPU_REV(0, 1)
+
 workaround_reset_start cortex_x4, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index f736b5a..c55597a 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -823,6 +823,10 @@
 # cpu and is fixed in r0p1.
 CPU_FLAG_LIST += ERRATA_X4_2701112
 
+# Flag to apply erratum 2726228 workaround during warmboot. This erratum
+# applies to all revisions <= r0p1 of the Cortex-X4 cpu, it is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_X4_2726228
+
 # Flag to apply erratum 2740089 workaround during powerdown. This erratum
 # applies to all revisions <= r0p1 of the Cortex-X4 cpu, it is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_X4_2740089
@@ -831,6 +835,10 @@
 # to revisions r0p0 and r0p1 of the Cortex-X4 cpu. It is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_X4_2763018
 
+# Flag to apply erratum 2816013 workaround on reset. This erratum applies
+# to revisions r0p0 and r0p1 of the Cortex-X4 cpu. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_X4_2816013
+
 # 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
@@ -892,6 +900,10 @@
 # applies to revision r0p0 and r0p1 of the Cortex-A520 cpu and is still open.
 CPU_FLAG_LIST += ERRATA_A520_2858100
 
+# Flag to apply erratum 2938996 workaround during reset. This erratum
+# applies to revision r0p0 and r0p1 of the Cortex-A520 cpu and is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_A520_2938996
+
 # Flag to apply erratum 2331132 workaround during reset. This erratum applies
 # to revisions r0p0, r0p1 and r0p2. It is still open.
 CPU_FLAG_LIST += ERRATA_V2_2331132
@@ -952,6 +964,14 @@
 # only to revision r0p0, r1p0 and r1p1. It is fixed in r1p2.
 CPU_FLAG_LIST += ERRATA_A715_2728106
 
+# Flag to apply erratum 2792132 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_A720_2792132
+
+# Flag to apply erratum 2844092 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_A720_2844092
+
 # Flag to apply erratum 2926083 workaround during reset. This erratum applies
 # to revisions r0p0 and r0p1. It is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_A720_2926083
diff --git a/lib/cpus/errata_common.c b/lib/cpus/errata_common.c
new file mode 100644
index 0000000..9801245
--- /dev/null
+++ b/lib/cpus/errata_common.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Runtime C routines for errata workarounds and common routines */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <cortex_a520.h>
+#include <cortex_x4.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
+
+#if ERRATA_A520_2938996 || ERRATA_X4_2726228
+unsigned int check_if_affected_core(void)
+{
+	uint32_t midr_val = read_midr();
+	long rev_var  = cpu_get_rev_var();
+
+	if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_A520_MIDR)) {
+		return check_erratum_cortex_a520_2938996(rev_var);
+	} else if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_X4_MIDR)) {
+		return check_erratum_cortex_x4_2726228(rev_var);
+	}
+
+	return ERRATA_NOT_APPLIES;
+}
+#endif
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 62895ff..ab9d4b6 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -9,12 +9,18 @@
 #include <assert_macros.S>
 #include <context.h>
 #include <el3_common_macros.S>
+#include <platform_def.h>
 
 #if CTX_INCLUDE_FPREGS
 	.global	fpregs_context_save
 	.global	fpregs_context_restore
 #endif /* CTX_INCLUDE_FPREGS */
 
+#if CTX_INCLUDE_SVE_REGS
+	.global sve_context_save
+	.global sve_context_restore
+#endif /* CTX_INCLUDE_SVE_REGS */
+
 #if ERRATA_SPECULATIVE_AT
 	.global save_and_update_ptw_el1_sys_regs
 #endif /* ERRATA_SPECULATIVE_AT */
@@ -23,6 +29,36 @@
 	.global	restore_gp_pmcr_pauth_regs
 	.global	el3_exit
 
+/* Following macros will be used if any of CTX_INCLUDE_FPREGS or CTX_INCLUDE_SVE_REGS is enabled */
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+.macro fpregs_state_save base:req hold:req
+	mrs	\hold, fpsr
+	str	\hold, [\base, #CTX_SIMD_FPSR]
+
+	mrs	\hold, fpcr
+	str	\hold, [\base, #CTX_SIMD_FPCR]
+
+#if CTX_INCLUDE_AARCH32_REGS && CTX_INCLUDE_FPREGS
+	mrs	\hold, fpexc32_el2
+	str	\hold, [\base, #CTX_SIMD_FPEXC32]
+#endif
+.endm
+
+.macro fpregs_state_restore base:req hold:req
+	ldr	\hold, [\base, #CTX_SIMD_FPSR]
+	msr	fpsr, \hold
+
+	ldr	\hold, [\base, #CTX_SIMD_FPCR]
+	msr	fpcr, \hold
+
+#if CTX_INCLUDE_AARCH32_REGS && CTX_INCLUDE_FPREGS
+	ldr	\hold, [\base, #CTX_SIMD_FPEXC32]
+	msr	fpexc32_el2, \hold
+#endif
+.endm
+
+#endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
+
 /* ------------------------------------------------------------------
  * The following function follows the aapcs_64 strictly to use
  * x9-x17 (temporary caller-saved registers according to AArch64 PCS)
@@ -39,33 +75,25 @@
  */
 #if CTX_INCLUDE_FPREGS
 func fpregs_context_save
-	stp	q0, q1, [x0, #CTX_FP_Q0]
-	stp	q2, q3, [x0, #CTX_FP_Q2]
-	stp	q4, q5, [x0, #CTX_FP_Q4]
-	stp	q6, q7, [x0, #CTX_FP_Q6]
-	stp	q8, q9, [x0, #CTX_FP_Q8]
-	stp	q10, q11, [x0, #CTX_FP_Q10]
-	stp	q12, q13, [x0, #CTX_FP_Q12]
-	stp	q14, q15, [x0, #CTX_FP_Q14]
-	stp	q16, q17, [x0, #CTX_FP_Q16]
-	stp	q18, q19, [x0, #CTX_FP_Q18]
-	stp	q20, q21, [x0, #CTX_FP_Q20]
-	stp	q22, q23, [x0, #CTX_FP_Q22]
-	stp	q24, q25, [x0, #CTX_FP_Q24]
-	stp	q26, q27, [x0, #CTX_FP_Q26]
-	stp	q28, q29, [x0, #CTX_FP_Q28]
-	stp	q30, q31, [x0, #CTX_FP_Q30]
+	stp	q0, q1, [x0], #32
+	stp	q2, q3, [x0], #32
+	stp	q4, q5, [x0], #32
+	stp	q6, q7, [x0], #32
+	stp	q8, q9, [x0], #32
+	stp	q10, q11, [x0], #32
+	stp	q12, q13, [x0], #32
+	stp	q14, q15, [x0], #32
+	stp	q16, q17, [x0], #32
+	stp	q18, q19, [x0], #32
+	stp	q20, q21, [x0], #32
+	stp	q22, q23, [x0], #32
+	stp	q24, q25, [x0], #32
+	stp	q26, q27, [x0], #32
+	stp	q28, q29, [x0], #32
+	stp	q30, q31, [x0], #32
 
-	mrs	x9, fpsr
-	str	x9, [x0, #CTX_FP_FPSR]
+	fpregs_state_save x0, x9
 
-	mrs	x10, fpcr
-	str	x10, [x0, #CTX_FP_FPCR]
-
-#if CTX_INCLUDE_AARCH32_REGS
-	mrs	x11, fpexc32_el2
-	str	x11, [x0, #CTX_FP_FPEXC32_EL2]
-#endif /* CTX_INCLUDE_AARCH32_REGS */
 	ret
 endfunc fpregs_context_save
 
@@ -84,51 +112,196 @@
  * ------------------------------------------------------------------
  */
 func fpregs_context_restore
-	ldp	q0, q1, [x0, #CTX_FP_Q0]
-	ldp	q2, q3, [x0, #CTX_FP_Q2]
-	ldp	q4, q5, [x0, #CTX_FP_Q4]
-	ldp	q6, q7, [x0, #CTX_FP_Q6]
-	ldp	q8, q9, [x0, #CTX_FP_Q8]
-	ldp	q10, q11, [x0, #CTX_FP_Q10]
-	ldp	q12, q13, [x0, #CTX_FP_Q12]
-	ldp	q14, q15, [x0, #CTX_FP_Q14]
-	ldp	q16, q17, [x0, #CTX_FP_Q16]
-	ldp	q18, q19, [x0, #CTX_FP_Q18]
-	ldp	q20, q21, [x0, #CTX_FP_Q20]
-	ldp	q22, q23, [x0, #CTX_FP_Q22]
-	ldp	q24, q25, [x0, #CTX_FP_Q24]
-	ldp	q26, q27, [x0, #CTX_FP_Q26]
-	ldp	q28, q29, [x0, #CTX_FP_Q28]
-	ldp	q30, q31, [x0, #CTX_FP_Q30]
+	ldp	q0, q1, [x0], #32
+	ldp	q2, q3, [x0], #32
+	ldp	q4, q5, [x0], #32
+	ldp	q6, q7, [x0], #32
+	ldp	q8, q9, [x0], #32
+	ldp	q10, q11, [x0], #32
+	ldp	q12, q13, [x0], #32
+	ldp	q14, q15, [x0], #32
+	ldp	q16, q17, [x0], #32
+	ldp	q18, q19, [x0], #32
+	ldp	q20, q21, [x0], #32
+	ldp	q22, q23, [x0], #32
+	ldp	q24, q25, [x0], #32
+	ldp	q26, q27, [x0], #32
+	ldp	q28, q29, [x0], #32
+	ldp	q30, q31, [x0], #32
 
-	ldr	x9, [x0, #CTX_FP_FPSR]
-	msr	fpsr, x9
+	fpregs_state_restore x0, x9
 
-	ldr	x10, [x0, #CTX_FP_FPCR]
-	msr	fpcr, x10
+	ret
+endfunc fpregs_context_restore
+#endif /* CTX_INCLUDE_FPREGS */
+
+#if CTX_INCLUDE_SVE_REGS
+/*
+ * Helper macros for SVE predicates save/restore operations.
+ */
+.macro sve_predicate_op op:req reg:req
+	\op p0, [\reg, #0, MUL VL]
+	\op p1, [\reg, #1, MUL VL]
+	\op p2, [\reg, #2, MUL VL]
+	\op p3, [\reg, #3, MUL VL]
+	\op p4, [\reg, #4, MUL VL]
+	\op p5, [\reg, #5, MUL VL]
+	\op p6, [\reg, #6, MUL VL]
+	\op p7, [\reg, #7, MUL VL]
+	\op p8, [\reg, #8, MUL VL]
+	\op p9, [\reg, #9, MUL VL]
+	\op p10, [\reg, #10, MUL VL]
+	\op p11, [\reg, #11, MUL VL]
+	\op p12, [\reg, #12, MUL VL]
+	\op p13, [\reg, #13, MUL VL]
+	\op p14, [\reg, #14, MUL VL]
+	\op p15, [\reg, #15, MUL VL]
+.endm
 
-#if CTX_INCLUDE_AARCH32_REGS
-	ldr	x11, [x0, #CTX_FP_FPEXC32_EL2]
-	msr	fpexc32_el2, x11
-#endif /* CTX_INCLUDE_AARCH32_REGS */
+.macro sve_vectors_op op:req reg:req
+	\op z0, [\reg, #0, MUL VL]
+	\op z1, [\reg, #1, MUL VL]
+	\op z2, [\reg, #2, MUL VL]
+	\op z3, [\reg, #3, MUL VL]
+	\op z4, [\reg, #4, MUL VL]
+	\op z5, [\reg, #5, MUL VL]
+	\op z6, [\reg, #6, MUL VL]
+	\op z7, [\reg, #7, MUL VL]
+	\op z8, [\reg, #8, MUL VL]
+	\op z9, [\reg, #9, MUL VL]
+	\op z10, [\reg, #10, MUL VL]
+	\op z11, [\reg, #11, MUL VL]
+	\op z12, [\reg, #12, MUL VL]
+	\op z13, [\reg, #13, MUL VL]
+	\op z14, [\reg, #14, MUL VL]
+	\op z15, [\reg, #15, MUL VL]
+	\op z16, [\reg, #16, MUL VL]
+	\op z17, [\reg, #17, MUL VL]
+	\op z18, [\reg, #18, MUL VL]
+	\op z19, [\reg, #19, MUL VL]
+	\op z20, [\reg, #20, MUL VL]
+	\op z21, [\reg, #21, MUL VL]
+	\op z22, [\reg, #22, MUL VL]
+	\op z23, [\reg, #23, MUL VL]
+	\op z24, [\reg, #24, MUL VL]
+	\op z25, [\reg, #25, MUL VL]
+	\op z26, [\reg, #26, MUL VL]
+	\op z27, [\reg, #27, MUL VL]
+	\op z28, [\reg, #28, MUL VL]
+	\op z29, [\reg, #29, MUL VL]
+	\op z30, [\reg, #30, MUL VL]
+	\op z31, [\reg, #31, MUL VL]
+.endm
 
-	/*
-	 * No explict ISB required here as ERET to
-	 * switch to secure EL1 or non-secure world
-	 * covers it
-	 */
+/* ------------------------------------------------------------------
+ * The following function follows the aapcs_64 strictly to use x9-x17
+ * (temporary caller-saved registers according to AArch64 PCS) to
+ * restore SVE register context. It assumes that 'x0' is
+ * pointing to a 'sve_regs_t' structure to which the register context
+ * will be saved.
+ * ------------------------------------------------------------------
+ */
+func sve_context_save
+.arch_extension sve
+	/* Temporarily enable SVE */
+	mrs	x10, cptr_el3
+	orr	x11, x10, #CPTR_EZ_BIT
+	bic	x11, x11, #TFP_BIT
+	msr	cptr_el3, x11
+	isb
+
+	/* zcr_el3 */
+	mrs	x12, S3_6_C1_C2_0
+	mov	x13, #((SVE_VECTOR_LEN >> 7) - 1)
+	msr	S3_6_C1_C2_0, x13
+	isb
+
+	/* Predicate registers */
+	mov x13, #CTX_SIMD_PREDICATES
+	add	x9, x0, x13
+	sve_predicate_op str, x9
+
+	/* Save FFR after predicates */
+	mov x13, #CTX_SIMD_FFR
+	add	x9, x0, x13
+	rdffr   p0.b
+	str	p0, [x9]
+
+	/* Save vector registers */
+	mov x13, #CTX_SIMD_VECTORS
+	add	x9, x0, x13
+	sve_vectors_op  str, x9
+
+	/* Restore SVE enablement */
+	msr	S3_6_C1_C2_0, x12 /* zcr_el3 */
+	msr	cptr_el3, x10
+	isb
+.arch_extension nosve
+
+	/* Save FPSR, FPCR and FPEXC32 */
+	fpregs_state_save x0, x9
 
 	ret
-endfunc fpregs_context_restore
-#endif /* CTX_INCLUDE_FPREGS */
+endfunc sve_context_save
+
+/* ------------------------------------------------------------------
+ * The following function follows the aapcs_64 strictly to use x9-x17
+ * (temporary caller-saved registers according to AArch64 PCS) to
+ * restore SVE register context. It assumes that 'x0' is pointing to
+ * a 'sve_regs_t' structure from where the register context will be
+ * restored.
+ * ------------------------------------------------------------------
+ */
+func sve_context_restore
+.arch_extension sve
+	/* Temporarily enable SVE for EL3 */
+	mrs	x10, cptr_el3
+	orr	x11, x10, #CPTR_EZ_BIT
+	bic	x11, x11, #TFP_BIT
+	msr	cptr_el3, x11
+	isb
+
+	/* zcr_el3 */
+	mrs	x12, S3_6_C1_C2_0
+	mov	x13, #((SVE_VECTOR_LEN >> 7) - 1)
+	msr	S3_6_C1_C2_0, x13
+	isb
+
+	/* Restore FFR register before predicates */
+	mov x13, #CTX_SIMD_FFR
+	add	x9, x0, x13
+	ldr	p0, [x9]
+	wrffr	p0.b
+
+	/* Restore predicate registers */
+	mov x13, #CTX_SIMD_PREDICATES
+	add	x9, x0, x13
+	sve_predicate_op ldr, x9
+
+	/* Restore vector registers */
+	mov x13, #CTX_SIMD_VECTORS
+	add	x9, x0, x13
+	sve_vectors_op	ldr, x9
+
+	/* Restore SVE enablement */
+	msr	S3_6_C1_C2_0, x12 /* zcr_el3 */
+	msr	cptr_el3, x10
+	isb
+.arch_extension nosve
+
+	/* Restore FPSR, FPCR and FPEXC32 */
+	fpregs_state_restore x0, x9
+	ret
+endfunc sve_context_restore
+#endif /* CTX_INCLUDE_SVE_REGS */
 
 	/*
 	 * Set SCR_EL3.EA bit to enable SErrors at EL3
 	 */
 	.macro enable_serror_at_el3
-	mrs     x8, scr_el3
-	orr     x8, x8, #SCR_EA_BIT
-	msr     scr_el3, x8
+	mrs	x8, scr_el3
+	orr	x8, x8, #SCR_EA_BIT
+	msr	scr_el3, x8
 	.endm
 
 	/*
@@ -142,13 +315,13 @@
 	 * always enable DIT in EL3
 	 */
 #if ENABLE_FEAT_DIT
-#if ENABLE_FEAT_DIT == 2
+#if ENABLE_FEAT_DIT >= 2
 	mrs	x8, id_aa64pfr0_el1
 	and	x8, x8, #(ID_AA64PFR0_DIT_MASK << ID_AA64PFR0_DIT_SHIFT)
 	cbz	x8, 1f
 #endif
-	mov     x8, #DIT_BIT
-	msr     DIT, x8
+	mov	x8, #DIT_BIT
+	msr	DIT, x8
 1:
 #endif /* ENABLE_FEAT_DIT */
 	.endm /* set_unset_pstate_bits */
@@ -166,8 +339,7 @@
 
 	.macro	restore_mpam3_el3
 #if ENABLE_FEAT_MPAM
-#if ENABLE_FEAT_MPAM == 2
-
+#if ENABLE_FEAT_MPAM >= 2
 	mrs x8, id_aa64pfr0_el1
 	lsr x8, x8, #(ID_AA64PFR0_MPAM_SHIFT)
 	and x8, x8, #(ID_AA64PFR0_MPAM_MASK)
diff --git a/lib/el3_runtime/aarch64/context_debug.c b/lib/el3_runtime/aarch64/context_debug.c
index 9ffa297..b37bcb7 100644
--- a/lib/el3_runtime/aarch64/context_debug.c
+++ b/lib/el3_runtime/aarch64/context_debug.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
  */
@@ -28,19 +28,11 @@
 	return state_names[security_state_idx];
 }
 
-#if CTX_INCLUDE_EL2_REGS
 #define PRINT_MEM_USAGE_SEPARATOR()					\
 	do {								\
 		printf("+-----------+-----------+-----------"		\
-			"+-----------+-----------+-----------+\n");	\
-	} while (false)
-#else
-#define PRINT_MEM_USAGE_SEPARATOR()					\
-	do {								\
-		printf("+-----------+-----------"			\
 		"+-----------+-----------+-----------+\n");		\
 	} while (false)
-#endif /* CTX_INCLUDE_EL2_REGS */
 
 #define NAME_PLACEHOLDER_LEN 14
 
@@ -49,6 +41,11 @@
 		putchar('-');						\
 	}
 
+#define PRINT_SINGLE_MEM_USAGE_SEP_BLOCK()				\
+	do {								\
+		printf("+-----------");					\
+	} while (false)
+
 /********************************************************************************
  * This function prints the allocated memory for a specific security state.
  * Values are grouped by exception level and core. The memory usage for the
@@ -57,64 +54,119 @@
 static size_t report_allocated_memory(unsigned int security_state_idx)
 {
 	size_t core_total = 0U;
+	size_t gp_total = 0U;
 	size_t el3_total = 0U;
-#if CTX_INCLUDE_EL2_REGS
-	size_t el2_total = 0U;
-#endif /* CTX_INCLUDE_EL2_REGS */
-	size_t el1_total = 0U;
 	size_t other_total = 0U;
 	size_t total = 0U;
 	size_t per_world_ctx_size = 0U;
 
+#if CTX_INCLUDE_EL2_REGS
+	size_t el2_total = 0U;
+#else
+	size_t el1_total = 0U;
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+#if CTX_INCLUDE_PAUTH_REGS
+	size_t pauth_total = 0U;
+	PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+#endif
+
 	PRINT_MEM_USAGE_SEPARATOR();
-	printf("|    Core   |    EL3    ");
+
+	printf("|    Core   |     GP    |    EL3    ");
 #if CTX_INCLUDE_EL2_REGS
 	printf("|    EL2    ");
+#else
+	printf("|    EL1    ");
 #endif /* CTX_INCLUDE_EL2_REGS */
-	printf("|    EL1    |   Other   |   Total   |\n");
+
+#if CTX_INCLUDE_PAUTH_REGS
+	printf("|   PAUTH   ");
+#endif
+
+	printf("|   Other   |   Total   |\n");
 
 	/* Compute memory usage for each core's context */
 	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
 		size_t size_other = 0U;
 		size_t el3_size = 0U;
+		size_t gp_size = 0U;
 #if CTX_INCLUDE_EL2_REGS
 		size_t el2_size = 0U;
-#endif /* CTX_INCLUDE_EL2_REGS */
+#else
 		size_t el1_size = 0U;
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+#if CTX_INCLUDE_PAUTH_REGS
+		size_t pauth_size = 0U;
+		PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+#endif
 
 		PRINT_MEM_USAGE_SEPARATOR();
+
 		cpu_context_t *ctx = (cpu_context_t *)cm_get_context_by_index(i,
 			security_state_idx);
 		core_total = sizeof(*ctx);
 		el3_size = sizeof(ctx->el3state_ctx);
-#if CTX_INCLUDE_EL2_REGS
-		el2_size = sizeof(ctx->el2_sysregs_ctx);
-#endif /* CTX_INCLUDE_EL2_REGS */
-		el1_size = sizeof(ctx->el1_sysregs_ctx);
+		gp_size = sizeof(ctx->gpregs_ctx);
+		size_other = core_total - (el3_size + gp_size);
+		printf("| %9u | %8luB | %8luB ", i, gp_size, el3_size);
 
-		size_other = core_total - el3_size - el1_size;
-		printf("| %9u | %8luB ", i, el3_size);
 #if CTX_INCLUDE_EL2_REGS
+		el2_size = sizeof(ctx->el2_sysregs_ctx);
 		size_other -= el2_size;
+		el2_total += el2_size;
 		printf("| %8luB ", el2_size);
+#else
+		el1_size = sizeof(ctx->el1_sysregs_ctx);
+		size_other -= el1_size;
+		el1_total += el1_size;
+		printf("| %8luB ", el1_size);
 #endif /* CTX_INCLUDE_EL2_REGS */
-		printf("| %8luB | %8luB | %8luB |\n", el1_size, size_other, core_total);
 
+#if CTX_INCLUDE_PAUTH_REGS
+		pauth_size = sizeof(ctx->pauth_ctx);
+		size_other -= pauth_size;
+		pauth_total += pauth_size;
+		printf("| %8luB ", pauth_size);
+#endif
+		printf("| %8luB | %8luB |\n", size_other, core_total);
+
+		gp_total += gp_size;
 		el3_total += el3_size;
-#if CTX_INCLUDE_EL2_REGS
-		el2_total += el2_size;
-#endif /* CTX_INCLUDE_EL2_REGS */
-		el1_total += el1_size;
 		other_total += size_other;
 		total += core_total;
 	}
+
+#if CTX_INCLUDE_PAUTH_REGS
+	PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+#endif
+
 	PRINT_MEM_USAGE_SEPARATOR();
+
+#if CTX_INCLUDE_PAUTH_REGS
+	PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+#endif
+
 	PRINT_MEM_USAGE_SEPARATOR();
-	printf("|    All    | %8luB ", el3_total);
+
+	printf("|    All    | %8luB | %8luB ", gp_total, el3_total);
+
 #if CTX_INCLUDE_EL2_REGS
 	printf("| %8luB ", el2_total);
+#else
+	printf("| %8luB ", el1_total);
 #endif /* CTX_INCLUDE_EL2_REGS */
-	printf("| %8luB | %8luB | %8luB |\n", el1_total, other_total, total);
+
+#if CTX_INCLUDE_PAUTH_REGS
+	printf("| %8luB ", pauth_total);
+#endif
+
+	printf("| %8luB | %8luB |\n", other_total, total);
+
+#if CTX_INCLUDE_PAUTH_REGS
+	PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+#endif
 	PRINT_MEM_USAGE_SEPARATOR();
 	printf("\n");
 
@@ -146,18 +198,10 @@
 
 		printf("Memory usage for %s:\n", context_name);
 		total += report_allocated_memory(i);
-			printf("------------------------"
-#if CTX_INCLUDE_EL2_REGS
-				"------"
-#endif /* CTX_INCLUDE_EL2_REGS */
-			      );
+			printf("------------------------");
 			len = NAME_PLACEHOLDER_LEN - printf("End %s", context_name);
 			PRINT_DASH(len);
-			printf(
-#if CTX_INCLUDE_EL2_REGS
-				"------"
-#endif /* CTX_INCLUDE_EL2_REGS */
-				"-----------------------\n\n");
+			printf("-----------------------\n\n");
 	}
 
 	printf("Total context memory allocated: %luB\n\n", total);
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 15db9e5..6f3b51a 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -19,6 +19,8 @@
 #include <common/debug.h>
 #include <context.h>
 #include <drivers/arm/gicv3.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
 #include <lib/el3_runtime/context_mgmt.h>
 #include <lib/el3_runtime/cpu_data.h>
 #include <lib/el3_runtime/pubsub_events.h>
@@ -49,6 +51,7 @@
 static void manage_extensions_secure(cpu_context_t *ctx);
 static void manage_extensions_secure_per_world(void);
 
+#if ((IMAGE_BL1) || (IMAGE_BL31 && (!CTX_INCLUDE_EL2_REGS)))
 static void setup_el1_context(cpu_context_t *ctx, const struct entry_point_info *ep)
 {
 	u_register_t sctlr_elx, actlr_elx;
@@ -94,11 +97,7 @@
 #endif
 
 	/* Store the initialised SCTLR_EL1 value in the cpu_context */
-#if (ERRATA_SPECULATIVE_AT)
-	write_ctx_reg(get_errata_speculative_at_ctx(ctx), CTX_ERRATA_SPEC_AT_SCTLR_EL1, sctlr_elx);
-#else
-	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1, sctlr_elx);
-#endif /* ERRATA_SPECULATIVE_AT */
+	write_ctx_sctlr_el1_reg_errata(ctx, sctlr_elx);
 
 	/*
 	 * Base the context ACTLR_EL1 on the current value, as it is
@@ -110,6 +109,7 @@
 	actlr_elx = read_actlr_el1();
 	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), actlr_el1, actlr_elx);
 }
+#endif /* (IMAGE_BL1) || (IMAGE_BL31 && (!CTX_INCLUDE_EL2_REGS)) */
 
 /******************************************************************************
  * This function performs initializations that are specific to SECURE state
@@ -142,7 +142,7 @@
 	 * Initialize EL1 context registers unless SPMC is running
 	 * at S-EL2.
 	 */
-#if !SPMD_SPM_AT_SEL2
+#if (!SPMD_SPM_AT_SEL2)
 	setup_el1_context(ctx, ep);
 #endif
 
@@ -158,7 +158,6 @@
 	if (!has_secure_perworld_init) {
 		manage_extensions_secure_per_world();
 	}
-
 }
 
 #if ENABLE_RME
@@ -262,11 +261,8 @@
 #endif
 	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
 
-	/* Initialize EL1 context registers */
-	setup_el1_context(ctx, ep);
-
 	/* Initialize EL2 context registers */
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 
 	/*
 	 * Initialize SCTLR_EL2 context register with reset value.
@@ -299,8 +295,10 @@
 		write_el2_ctx_fgt(get_el2_sysregs_ctx(ctx), hfgwtr_el2,
 			HFGWTR_EL2_INIT_VAL);
 	}
-
-#endif /* CTX_INCLUDE_EL2_REGS */
+#else
+	/* Initialize EL1 context registers */
+	setup_el1_context(ctx, ep);
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 
 	manage_extensions_nonsecure(ctx);
 }
@@ -331,7 +329,7 @@
 	 * to boot correctly. However, there are very few registers where this
 	 * is not true and some values need to be recreated.
 	 */
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 	el2_sysregs_t *el2_ctx = get_el2_sysregs_ctx(ctx);
 
 	/*
@@ -347,7 +345,7 @@
 	 * and it may contain access control bits (e.g. CLUSTERPMUEN bit).
 	 */
 	write_el2_ctx_common(el2_ctx, actlr_el2, read_actlr_el2());
-#endif /* CTX_INCLUDE_EL2_REGS */
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 
 	/* Start with a clean SCR_EL3 copy as all relevant values are set */
 	scr_el3 = SCR_RESET_VAL;
@@ -1089,11 +1087,14 @@
 			}
 		}
 	}
+#if (!CTX_INCLUDE_EL2_REGS)
+	/* Restore EL1 system registers, only when CTX_INCLUDE_EL2_REGS=0 */
 	cm_el1_sysregs_context_restore(security_state);
+#endif
 	cm_set_next_eret_context(security_state);
 }
 
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 
 static void el2_sysregs_context_save_fgt(el2_sysregs_t *ctx)
 {
@@ -1521,7 +1522,46 @@
 		write_gcspr_el2(read_el2_ctx_gcs(el2_sysregs_ctx, gcspr_el2));
 	}
 }
-#endif /* CTX_INCLUDE_EL2_REGS */
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
+
+#if IMAGE_BL31
+/*********************************************************************************
+* This function allows Architecture features asymmetry among cores.
+* TF-A assumes that all the cores in the platform has architecture feature parity
+* and hence the context is setup on different core (e.g. primary sets up the
+* context for secondary cores).This assumption may not be true for systems where
+* cores are not conforming to same Arch version or there is CPU Erratum which
+* requires certain feature to be be disabled only on a given core.
+*
+* This function is called on secondary cores to override any disparity in context
+* setup by primary, this would be called during warmboot path.
+*********************************************************************************/
+void cm_handle_asymmetric_features(void)
+{
+#if ENABLE_SPE_FOR_NS == FEAT_STATE_CHECK_ASYMMETRIC
+	cpu_context_t *spe_ctx = cm_get_context(NON_SECURE);
+
+	assert(spe_ctx != NULL);
+
+	if (is_feat_spe_supported()) {
+		spe_enable(spe_ctx);
+	} else {
+		spe_disable(spe_ctx);
+	}
+#endif
+#if ERRATA_A520_2938996 || ERRATA_X4_2726228
+	cpu_context_t *trbe_ctx = cm_get_context(NON_SECURE);
+
+	assert(trbe_ctx != NULL);
+
+	if (check_if_affected_core() == ERRATA_APPLIES) {
+		if (is_feat_trbe_supported()) {
+			trbe_disable(trbe_ctx);
+		}
+	}
+#endif
+}
+#endif
 
 /*******************************************************************************
  * This function is used to exit to Non-secure world. If CTX_INCLUDE_EL2_REGS
@@ -1531,7 +1571,19 @@
  ******************************************************************************/
 void cm_prepare_el3_exit_ns(void)
 {
-#if CTX_INCLUDE_EL2_REGS
+#if IMAGE_BL31
+	/*
+	 * Check and handle Architecture feature asymmetry among cores.
+	 *
+	 * In warmboot path secondary cores context is initialized on core which
+	 * did CPU_ON SMC call, if there is feature asymmetry in these cores handle
+	 * it in this function call.
+	 * For Symmetric cores this is an empty function.
+	 */
+	cm_handle_asymmetric_features();
+#endif
+
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 #if ENABLE_ASSERTIONS
 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
 	assert(ctx != NULL);
@@ -1542,15 +1594,19 @@
 			(el_implemented(2U) != EL_IMPL_NONE));
 #endif /* ENABLE_ASSERTIONS */
 
-	/* Restore EL2 and EL1 sysreg contexts */
+	/* Restore EL2 sysreg contexts */
 	cm_el2_sysregs_context_restore(NON_SECURE);
-	cm_el1_sysregs_context_restore(NON_SECURE);
 	cm_set_next_eret_context(NON_SECURE);
 #else
 	cm_prepare_el3_exit(NON_SECURE);
-#endif /* CTX_INCLUDE_EL2_REGS */
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 }
 
+#if ((IMAGE_BL1) || (IMAGE_BL31 && (!CTX_INCLUDE_EL2_REGS)))
+/*******************************************************************************
+ * The next set of six functions are used by runtime services to save and restore
+ * EL1 context on the 'cpu_context' structure for the specified security state.
+ ******************************************************************************/
 static void el1_sysregs_context_save(el1_sysregs_t *ctx)
 {
 	write_el1_ctx_common(ctx, spsr_el1, read_spsr_el1());
@@ -1742,9 +1798,8 @@
 }
 
 /*******************************************************************************
- * The next four functions are used by runtime services to save and restore
- * EL1 context on the 'cpu_context' structure for the specified security
- * state.
+ * The next couple of functions are used by runtime services to save and restore
+ * EL1 context on the 'cpu_context' structure for the specified security state.
  ******************************************************************************/
 void cm_el1_sysregs_context_save(uint32_t security_state)
 {
@@ -1780,6 +1835,8 @@
 #endif
 }
 
+#endif /* ((IMAGE_BL1) || (IMAGE_BL31 && (!CTX_INCLUDE_EL2_REGS))) */
+
 /*******************************************************************************
  * This function populates ELR_EL3 member of 'cpu_context' pertaining to the
  * given security state with the given entrypoint
diff --git a/lib/el3_runtime/simd_ctx.c b/lib/el3_runtime/simd_ctx.c
new file mode 100644
index 0000000..f7a87df
--- /dev/null
+++ b/lib/el3_runtime/simd_ctx.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/el3_runtime/aarch64/context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/simd_ctx.h>
+#include <lib/extensions/sve.h>
+#include <plat/common/platform.h>
+
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+
+/* SIMD context managed for Secure and Normal Worlds. */
+#define SIMD_CTXT_COUNT	2
+
+#if SEPARATE_SIMD_SECTION
+__section(".simd_context")
+#else
+__section(".bss.simd_context")
+#endif
+static simd_regs_t simd_context[SIMD_CTXT_COUNT][PLATFORM_CORE_COUNT];
+
+void simd_ctx_save(uint32_t security_state, bool hint_sve)
+{
+	simd_regs_t *regs;
+
+	if (security_state != NON_SECURE && security_state != SECURE) {
+		ERROR("Unsupported security state specified for SIMD context: %u\n",
+		      security_state);
+		panic();
+	}
+
+	regs = &simd_context[security_state][plat_my_core_pos()];
+
+#if CTX_INCLUDE_SVE_REGS
+	regs->hint = hint_sve;
+
+	if (hint_sve) {
+		/*
+		 * Hint bit denoting absence of SVE live state. Hence, only
+		 * save FP context.
+		 */
+		fpregs_context_save(regs);
+	} else {
+		sve_context_save(regs);
+	}
+#elif CTX_INCLUDE_FPREGS
+	fpregs_context_save(regs);
+#endif
+}
+
+void simd_ctx_restore(uint32_t security_state)
+{
+	simd_regs_t *regs;
+
+	if (security_state != NON_SECURE && security_state != SECURE) {
+		ERROR("Unsupported security state specified for SIMD context: %u\n",
+		      security_state);
+		panic();
+	}
+
+	regs = &simd_context[security_state][plat_my_core_pos()];
+
+#if CTX_INCLUDE_SVE_REGS
+	if (regs->hint) {
+		fpregs_context_restore(regs);
+	} else {
+		sve_context_restore(regs);
+	}
+#elif CTX_INCLUDE_FPREGS
+	fpregs_context_restore(regs);
+#endif
+}
+#endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
diff --git a/lib/extensions/pmuv3/aarch64/pmuv3.c b/lib/extensions/pmuv3/aarch64/pmuv3.c
index 71aa303..f9e32ca 100644
--- a/lib/extensions/pmuv3/aarch64/pmuv3.c
+++ b/lib/extensions/pmuv3/aarch64/pmuv3.c
@@ -23,13 +23,13 @@
 
 void pmuv3_enable(cpu_context_t *ctx)
 {
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 	u_register_t mdcr_el2_val;
 
 	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 */
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 }
 
 static u_register_t mtpmu_disable_el3(u_register_t mdcr_el3)
diff --git a/lib/romlib/Makefile b/lib/romlib/Makefile
index 9859ce1..29fbf78 100644
--- a/lib/romlib/Makefile
+++ b/lib/romlib/Makefile
@@ -45,7 +45,7 @@
 
 .PHONY: all clean distclean
 
-all: $(BUILD_DIR)/romlib.bin $(LIB_DIR)/libwrappers.a
+all: $(BUILD_DIR)/romlib.bin $(BUILD_DIR)/romlib.ldflags $(LIB_DIR)/libwrappers.a
 
 %.o: %.s | $$(@D)/
 	$(s)echo "  AS      $@"
@@ -89,6 +89,10 @@
 	$(s)echo "  TBL     $@"
 	$(q)$(ROMLIB_GEN) gentbl --output $@ --bti=$(ENABLE_BTI) $<
 
+$(BUILD_DIR)/romlib.ldflags: ../../$(PLAT_DIR)/jmptbl.i
+	$(s)echo "  LDFLAGS $@"
+	$(q)$(ROMLIB_GEN) link-flags $< > $@
+
 clean:
 	$(q)rm -f $(BUILD_DIR)/*
 
diff --git a/lib/romlib/romlib_generator.py b/lib/romlib/romlib_generator.py
index 0682dd4..8d2e88d 100755
--- a/lib/romlib/romlib_generator.py
+++ b/lib/romlib/romlib_generator.py
@@ -182,6 +182,22 @@
                 template_name = "jmptbl_entry_" + item["type"] + bti + ".S"
                 output_file.write(self.build_template(template_name, item, True))
 
+class LinkArgs(RomlibApplication):
+    """ Generates the link arguments to wrap functions. """
+
+    def __init__(self, prog):
+        RomlibApplication.__init__(self, prog)
+        self.args.add_argument("file", help="Input file")
+
+    def main(self):
+        index_file_parser = IndexFileParser()
+        index_file_parser.parse(self.config.file)
+
+        fns = [item["function_name"] for item in index_file_parser.items
+               if not item["patch"] and item["type"] != "reserved"]
+
+        print(" ".join("-Wl,--wrap " + f for f in fns))
+
 class WrapperGenerator(RomlibApplication):
     """
     Generates a wrapper function for each entry in the index file except for the ones that contain
@@ -214,21 +230,19 @@
             if item["type"] == "reserved" or item["patch"]:
                 continue
 
-            asm = self.config.b + "/" + item["function_name"] + ".s"
-            if self.config.list:
-                # Only listing files
-                files.append(asm)
-            else:
-                with open(asm, "w") as asm_file:
-                    # The jump instruction is 4 bytes but BTI requires and extra instruction so
-                    # this makes it 8 bytes per entry.
-                    function_offset = item_index * (8 if self.config.bti else 4)
+            if not self.config.list:
+                # The jump instruction is 4 bytes but BTI requires and extra instruction so
+                # this makes it 8 bytes per entry.
+                function_offset = item_index * (8 if self.config.bti else 4)
 
-                    item["function_offset"] = function_offset
-                    asm_file.write(self.build_template("wrapper" + bti + ".S", item))
+                item["function_offset"] = function_offset
+                files.append(self.build_template("wrapper" + bti + ".S", item))
 
         if self.config.list:
-            print(" ".join(files))
+            print(self.config.b + "/wrappers.s")
+        else:
+            with open(self.config.b + "/wrappers.s", "w") as asm_file:
+                asm_file.write("\n".join(files))
 
 class VariableGenerator(RomlibApplication):
     """ Generates the jump table global variable with the absolute address in ROM. """
@@ -258,7 +272,8 @@
 
 if __name__ == "__main__":
     APPS = {"genvar": VariableGenerator, "pre": IndexPreprocessor,
-            "gentbl": TableGenerator, "genwrappers": WrapperGenerator}
+            "gentbl": TableGenerator, "genwrappers": WrapperGenerator,
+            "link-flags": LinkArgs}
 
     if len(sys.argv) < 2 or sys.argv[1] not in APPS:
         print("usage: romlib_generator.py [%s] [args]" % "|".join(APPS.keys()), file=sys.stderr)
diff --git a/lib/romlib/templates/wrapper.S b/lib/romlib/templates/wrapper.S
index 734a68a..576474a 100644
--- a/lib/romlib/templates/wrapper.S
+++ b/lib/romlib/templates/wrapper.S
@@ -3,8 +3,9 @@
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
-	.globl	${function_name}
-${function_name}:
+	.section .text.__wrap_${function_name}
+	.globl	__wrap_${function_name}
+__wrap_${function_name}:
 	ldr	x17, =jmptbl
 	mov	x16, #${function_offset}
 	ldr	x17, [x17]
diff --git a/lib/romlib/templates/wrapper_bti.S b/lib/romlib/templates/wrapper_bti.S
index ba9b11c..0dc316c 100644
--- a/lib/romlib/templates/wrapper_bti.S
+++ b/lib/romlib/templates/wrapper_bti.S
@@ -3,8 +3,9 @@
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
-	.globl	${function_name}
-${function_name}:
+	.section .text.__wrap_${function_name}
+	.globl	__wrap_${function_name}
+__wrap_${function_name}:
 	bti	jc
 	ldr	x17, =jmptbl
 	mov	x16, #${function_offset}
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 7050916..f523074 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -465,6 +465,10 @@
         $(patsubst %.S,$(BUILD_DIR)/%,$(1))
 endef
 
+ifeq ($(USE_ROMLIB),1)
+WRAPPER_FLAGS := @${BUILD_PLAT}/romlib/romlib.ldflags
+endif
+
 # MAKE_BL macro defines the targets and options to build each BL image.
 # Arguments:
 #   $(1) = BL stage
@@ -514,11 +518,11 @@
 		--map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/${1}.scat \
 		$(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) $(OBJS)
 else ifeq ($($(ARCH)-ld-id),gnu-gcc)
-	$$(q)$($(ARCH)-ld) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_LDFLAGS) -Wl,-Map=$(MAPFILE) \
+	$$(q)$($(ARCH)-ld) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $$(WRAPPER_FLAGS) $(BL_LDFLAGS) -Wl,-Map=$(MAPFILE) \
 		$(addprefix -Wl$(comma)--script$(comma),$(LINKER_SCRIPTS)) -Wl,--script,$(DEFAULT_LINKER_SCRIPT) \
 		$(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS)
 else
-	$$(q)$($(ARCH)-ld) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_LDFLAGS) -Map=$(MAPFILE) \
+	$$(q)$($(ARCH)-ld) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $$(WRAPPER_FLAGS) $(BL_LDFLAGS) -Map=$(MAPFILE) \
 		$(addprefix -T ,$(LINKER_SCRIPTS)) --script $(DEFAULT_LINKER_SCRIPT) \
 		$(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS)
 endif
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 368d26d..290a6fe 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -63,6 +63,9 @@
 # Include FP registers in cpu context
 CTX_INCLUDE_FPREGS		:= 0
 
+# Include SVE registers in cpu context
+CTX_INCLUDE_SVE_REGS		:= 0
+
 # Debug build
 DEBUG				:= 0
 
@@ -237,6 +240,10 @@
 # region, platform Makefile is free to override this value.
 SEPARATE_BL2_NOLOAD_REGION	:= 0
 
+# Put SIMD context data structures in a separate memory region. Platforms
+# have the choice to put it outside of default BSS region of EL3 firmware.
+SEPARATE_SIMD_SECTION		:= 0
+
 # If the BL31 image initialisation code is recalimed after use for the secondary
 # cores stack
 RECLAIM_INIT_CODE		:= 0
diff --git a/plat/arm/board/fvp/fdts/fvp_cactus_sp_manifest.dts b/plat/arm/board/fvp/fdts/fvp_cactus_sp_manifest.dts
new file mode 100644
index 0000000..de804e0
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_cactus_sp_manifest.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * that will be consumed by EL3 SPMC.
+ *
+ */
+
+/dts-v1/;
+
+/ {
+	compatible = "arm,ffa-manifest-1.0";
+	#address-cells = <2>;
+	#size-cells = <1>;
+
+	/* Properties */
+	ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+	id = <0x8001>;
+	uuid = <0x1e67b5b4 0xe14f904a 0x13fb1fb8 0xcbdae1da>;
+	messaging-method = <3>; /* Direct messaging only */
+	exception-level = <2>; /* S-EL1 */
+	execution-state = <0>; /* AARCH64 */
+	execution-ctx-count = <8>;
+	/* Boot protocol */
+	gp-register-num = <0>;
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index 9fba4af..bf0e7f3 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -99,12 +99,17 @@
 
 	memory@2 {
 		device_type = "device-memory";
-		reg = <0x0 0x1c090000 0x0 0x40000>, /* UART */
+		reg = <0x0 0x1c0b0000 0x0 0x20000>, /* UART 2-3 */
 		      <0x0 0x2bfe0000 0x0 0x20000>, /* SMMUv3TestEngine */
 		      <0x0 0x2a490000 0x0 0x20000>, /* SP805 Trusted Watchdog */
 		      <0x0 0x1c130000 0x0 0x10000>; /* Virtio block device */
 	};
 
+	memory@3 {
+		device_type = "ns-device-memory";
+		reg = <0x0 0x1c090000 0x0 0x20000>; /* UART 0-1 */
+	};
+
 
 #if MEASURED_BOOT
 #include "event_log.dtsi"
diff --git a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
index b1d3bc1..f5d7f65 100644
--- a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
@@ -117,16 +117,16 @@
 
 #if defined(ARM_COT_cca)
 /* FVP does not support the CCA NV Counter so use the Trusted one. */
-&cca_nv_counter {
+&cca_nv_ctr {
 	reg = <TFW_NVCTR_BASE>;
 };
 #endif
 
-&trusted_nv_counter {
+&trusted_nv_ctr {
 	reg = <TFW_NVCTR_BASE>;
 };
 
-&non_trusted_nv_counter {
+&non_trusted_nv_ctr {
 	reg = <NTFW_CTR_BASE>;
 };
 #endif
diff --git a/plat/arm/board/fvp/include/plat.ld.S b/plat/arm/board/fvp/include/plat.ld.S
index 7c8bf06..2f99999 100644
--- a/plat/arm/board/fvp/include/plat.ld.S
+++ b/plat/arm/board/fvp/include/plat.ld.S
@@ -1,12 +1,38 @@
 /*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #ifndef PLAT_LD_S
 #define PLAT_LD_S
 
-#include <plat/arm/common/arm_tzc_dram.ld.S>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+    EL3_SEC_DRAM (rw): ORIGIN = ARM_EL3_TZC_DRAM1_BASE, LENGTH = ARM_EL3_TZC_DRAM1_SIZE
+}
+
+SECTIONS
+{
+	. = ARM_EL3_TZC_DRAM1_BASE;
+	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)
+#if SEPARATE_SIMD_SECTION
+	. = ALIGN(16);
+	*(.simd_context)
+#endif
+	__EL3_SEC_DRAM_UNALIGNED_END__ = .;
+
+	. = ALIGN(PAGE_SIZE);
+	__EL3_SEC_DRAM_END__ = .;
+	} >EL3_SEC_DRAM
+}
 
 #if RECLAIM_INIT_CODE
 #include <plat/arm/common/arm_reclaim_init.ld.S>
diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i
index dc8032f..077283e 100644
--- a/plat/arm/board/fvp/jmptbl.i
+++ b/plat/arm/board/fvp/jmptbl.i
@@ -36,7 +36,6 @@
 fdt     fdt_get_name
 fdt     fdt_get_alias
 fdt     fdt_node_offset_by_phandle
-fdt     fdt_subnode_offset
 fdt     fdt_add_subnode
 mbedtls mbedtls_asn1_get_alg
 mbedtls mbedtls_asn1_get_alg_null
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index cef7bdf..340eb38 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -47,6 +47,10 @@
 ifeq (${CTX_INCLUDE_FPREGS}, 0)
       ENABLE_SME_FOR_NS		:= 2
       ENABLE_SME2_FOR_NS	:= 2
+else
+      ENABLE_SVE_FOR_NS		:= 0
+      ENABLE_SME_FOR_NS		:= 0
+      ENABLE_SME2_FOR_NS	:= 0
 endif
 endif
 
diff --git a/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
index cf1eb6f..dcee92c 100644
--- a/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
+++ b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
@@ -73,29 +73,14 @@
 						  mair_el1);
 	cpu_info->ErrCtxEl1Reg[5]  = read_midr_el1();
 	cpu_info->ErrCtxEl1Reg[6]  = read_mpidr_el1();
-
-#if (ERRATA_SPECULATIVE_AT)
-	cpu_info->ErrCtxEl1Reg[7]  = read_ctx_reg(get_errata_speculative_at_ctx(ctx),
-						  CTX_ERRATA_SPEC_AT_SCTLR_EL1);
-#else
-	cpu_info->ErrCtxEl1Reg[7]  = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
-						  sctlr_el1);
-#endif /* ERRATA_SPECULATIVE_AT */
-
+	cpu_info->ErrCtxEl1Reg[7] = read_ctx_sctlr_el1_reg_errata(ctx);
 	cpu_info->ErrCtxEl1Reg[8]  = read_ctx_reg(get_gpregs_ctx(ctx),
 						  CTX_GPREG_SP_EL0);
 	cpu_info->ErrCtxEl1Reg[9]  = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
 						  sp_el1);
 	cpu_info->ErrCtxEl1Reg[10] = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
 						  spsr_el1);
-#if (ERRATA_SPECULATIVE_AT)
-	cpu_info->ErrCtxEl1Reg[11]  = read_ctx_reg(get_errata_speculative_at_ctx(ctx),
-						   CTX_ERRATA_SPEC_AT_TCR_EL1);
-#else
-	cpu_info->ErrCtxEl1Reg[11] = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
-						  tcr_el1);
-#endif /* ERRATA_SPECULATIVE_AT */
-
+	cpu_info->ErrCtxEl1Reg[11] = read_ctx_tcr_el1_reg_errata(ctx);
 	cpu_info->ErrCtxEl1Reg[12] = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
 						  tpidr_el0);
 	cpu_info->ErrCtxEl1Reg[13] = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
@@ -107,7 +92,7 @@
 	cpu_info->ErrCtxEl1Reg[16] = read_el1_ctx_common(get_el1_sysregs_ctx(ctx),
 						  ttbr1_el1);
 
-#if CTX_INCLUDE_EL2_REGS
+#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
 	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),
@@ -140,7 +125,7 @@
 						vttbr_el2);
 	cpu_info->ErrCtxEl2Reg[15]  = read_el2_ctx_common(get_el2_sysregs_ctx(ctx),
 						esr_el2);
-#endif /* CTX_INCLUDE_EL2_REGS */
+#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 
 	cpu_info->ErrCtxEl3Reg[0]   = read_ctx_reg(get_el3state_ctx(ctx),
 						   CTX_ELR_EL3);
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
index 7d770f5..da96730 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
@@ -21,12 +21,6 @@
 override ARM_ARCH_MAJOR			:= 8
 override ARM_ARCH_MINOR			:= 7
 
-# Image flags
-override NEED_BL1			:= yes
-override NEED_BL2			:= yes
-override NEED_BL32			:= no
-override NEED_RMM			:= no
-
 # Misc options
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index fb70500..1a7289a 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -34,6 +34,7 @@
 ENABLE_MPMM			:=	1
 ENABLE_MPMM_FCONF		:=	1
 ENABLE_FEAT_MTE2	        :=	2
+ENABLE_SPE_FOR_NS		:=	3
 
 CTX_INCLUDE_AARCH32_REGS	:=	0
 
@@ -109,6 +110,9 @@
 
 # CPU libraries for TARGET_PLATFORM=2
 ifeq (${TARGET_PLATFORM}, 2)
+ERRATA_A520_2938996	:=	1
+ERRATA_X4_2726228	:=	1
+
 TC_CPU_SOURCES	+=	lib/cpus/aarch64/cortex_a520.S \
 			lib/cpus/aarch64/cortex_a720.S \
 			lib/cpus/aarch64/cortex_x4.S
@@ -116,6 +120,8 @@
 
 # CPU libraries for TARGET_PLATFORM=3
 ifeq (${TARGET_PLATFORM}, 3)
+ERRATA_A520_2938996	:=	1
+
 TC_CPU_SOURCES	+=	lib/cpus/aarch64/cortex_a520.S \
 			lib/cpus/aarch64/cortex_a725.S \
 			lib/cpus/aarch64/cortex_x925.S
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 2c1888d..dff0135 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -377,30 +377,38 @@
         ifneq (${COT_DESC_IN_DTB},0)
             BL2_SOURCES	+=	lib/fconf/fconf_cot_getter.c
         else
-            BL2_SOURCES	+=	drivers/auth/tbbr/tbbr_cot_common.c
 	    # Juno has its own TBBR CoT file for BL2
-            ifneq (${PLAT},juno)
-                BL2_SOURCES	+=	drivers/auth/tbbr/tbbr_cot_bl2.c
+            ifeq (${PLAT},juno)
+                BL2_SOURCES	+=	drivers/auth/tbbr/tbbr_cot_common.c
             endif
         endif
     else ifeq (${COT},dualroot)
-        BL1_SOURCES	+=	drivers/auth/dualroot/cot.c
+        BL1_SOURCES	+=	drivers/auth/dualroot/bl1_cot.c
         ifneq (${COT_DESC_IN_DTB},0)
             BL2_SOURCES	+=	lib/fconf/fconf_cot_getter.c
-        else
-            BL2_SOURCES	+=	drivers/auth/dualroot/cot.c
         endif
     else ifeq (${COT},cca)
-        BL1_SOURCES	+=	drivers/auth/cca/cot.c
+        BL1_SOURCES	+=	drivers/auth/cca/bl1_cot.c
         ifneq (${COT_DESC_IN_DTB},0)
             BL2_SOURCES	+=	lib/fconf/fconf_cot_getter.c
-        else
-            BL2_SOURCES	+=	drivers/auth/cca/cot.c
         endif
     else
         $(error Unknown chain of trust ${COT})
     endif
 
+    ifeq (${COT_DESC_IN_DTB},0)
+      ifeq (${COT},dualroot)
+        COTDTPATH := fdts/dualroot_cot_descriptors.dtsi
+      else ifeq (${COT},cca)
+        COTDTPATH := fdts/cca_cot_descriptors.dtsi
+      else ifeq (${COT},tbbr)
+        ifneq (${PLAT},juno)
+          COTDTPATH := fdts/tbbr_cot_descriptors.dtsi
+        endif
+      endif
+      bl2: cot-dt2c
+    endif
+
     BL1_SOURCES		+=	${AUTH_SOURCES}					\
 				bl1/tbbr/tbbr_img_desc.c			\
 				plat/arm/common/arm_bl1_fwu.c			\
@@ -472,3 +480,17 @@
     bl31: tl
   endif
 endif
+
+cot-dt2c:
+ifneq ($(COTDTPATH),)
+  $(info COT CONVERSION FOR ${COTDTPATH})
+  toolpath := $(shell which cot-dt2c)
+  ifeq (${toolpath},)
+    output := $(shell make -C ./${CERTCONVPATH} install)
+    $(info install output ${output})
+    toolpath := $(shell which cot-dt2c)
+  endif
+  output := $(shell ${toolpath} convert-to-c ${COTDTPATH} ${BUILD_PLAT}/bl2_cot.c)
+  $(info ${output})
+  BL2_SOURCES += ${BUILD_PLAT}/bl2_cot.c
+endif
diff --git a/plat/intel/soc/agilex/bl2_plat_setup.c b/plat/intel/soc/agilex/bl2_plat_setup.c
index 61c0ef2..36820b2 100644
--- a/plat/intel/soc/agilex/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex/bl2_plat_setup.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
- * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -30,6 +31,7 @@
 #include "socfpga_reset_manager.h"
 #include "socfpga_ros.h"
 #include "socfpga_system_manager.h"
+#include "socfpga_vab.h"
 #include "wdt/watchdog.h"
 
 static struct mmc_device_info mmc_info;
@@ -112,7 +114,10 @@
 
 	setup_page_tables(bl_regions, agilex_plat_mmap);
 
-	enable_mmu_el3(0);
+	/*
+	 * TODO: mmu enable in latest phase
+	 */
+	// enable_mmu_el3(0);
 
 	dw_mmc_params_t params = EMMC_INIT_PARAMS(0x100000, get_mmc_clk());
 
@@ -173,6 +178,20 @@
 
 	assert(bl_mem_params);
 
+#if SOCFPGA_SECURE_VAB_AUTH
+	/*
+	 * VAB Authentication start here.
+	 * If failed to authenticate, shall not proceed to process BL31 and hang.
+	 */
+	int ret = 0;
+
+	ret = socfpga_vab_init(image_id);
+	if (ret < 0) {
+		ERROR("SOCFPGA VAB Authentication failed\n");
+		wfi();
+	}
+#endif
+
 	switch (image_id) {
 	case BL33_IMAGE_ID:
 		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
@@ -191,4 +210,3 @@
 void bl2_platform_setup(void)
 {
 }
-
diff --git a/plat/intel/soc/agilex/platform.mk b/plat/intel/soc/agilex/platform.mk
index 6780845..21cc6a3 100644
--- a/plat/intel/soc/agilex/platform.mk
+++ b/plat/intel/soc/agilex/platform.mk
@@ -1,6 +1,7 @@
 #
 # Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
-# Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+# Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+# Copyright (c) 2024, Altera Corporation. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -27,6 +28,7 @@
 			plat/intel/soc/common/aarch64/platform_common.c \
 			plat/intel/soc/common/aarch64/plat_helpers.S	\
 			plat/intel/soc/common/drivers/ccu/ncore_ccu.c	\
+			plat/intel/soc/common/lib/sha/sha.c				\
 			plat/intel/soc/common/socfpga_delay_timer.c
 
 BL2_SOURCES     +=	\
@@ -49,6 +51,7 @@
 		plat/intel/soc/common/socfpga_image_load.c		\
 		plat/intel/soc/common/socfpga_ros.c			\
 		plat/intel/soc/common/socfpga_storage.c			\
+		plat/intel/soc/common/socfpga_vab.c				\
 		plat/intel/soc/common/soc/socfpga_emac.c		\
 		plat/intel/soc/common/soc/socfpga_firewall.c	\
 		plat/intel/soc/common/soc/socfpga_handoff.c		\
@@ -78,9 +81,20 @@
 		plat/intel/soc/common/soc/socfpga_mailbox.c		\
 		plat/intel/soc/common/soc/socfpga_reset_manager.c
 
+# Don't have the Linux kernel as a BL33 image by default
+ARM_LINUX_KERNEL_AS_BL33	:=	0
+$(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33))
+$(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
 $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
 
+# Configs for VAB Authentication
+SOCFPGA_SECURE_VAB_AUTH  := 	0
+$(eval $(call assert_boolean,SOCFPGA_SECURE_VAB_AUTH))
+$(eval $(call add_define,SOCFPGA_SECURE_VAB_AUTH))
+
 PROGRAMMABLE_RESET_ADDRESS	:= 0
 RESET_TO_BL2			:= 1
 BL2_INV_DCACHE			:= 0
 USE_COHERENT_MEM		:= 1
+
+HANDLE_EA_EL3_FIRST_NS			:= 1
\ No newline at end of file
diff --git a/plat/intel/soc/agilex5/bl2_plat_setup.c b/plat/intel/soc/agilex5/bl2_plat_setup.c
index c74d799..265ee57 100644
--- a/plat/intel/soc/agilex5/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl2_plat_setup.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,6 +36,7 @@
 #include "socfpga_private.h"
 #include "socfpga_reset_manager.h"
 #include "socfpga_ros.h"
+#include "socfpga_vab.h"
 #include "wdt/watchdog.h"
 
 
@@ -165,6 +167,20 @@
 
 	assert(bl_mem_params);
 
+#if SOCFPGA_SECURE_VAB_AUTH
+	/*
+	 * VAB Authentication start here.
+	 * If failed to authenticate, shall not proceed to process BL31 and hang.
+	 */
+	int ret = 0;
+
+	ret = socfpga_vab_init(image_id);
+	if (ret < 0) {
+		ERROR("SOCFPGA VAB Authentication failed\n");
+		wfi();
+	}
+#endif
+
 	switch (image_id) {
 	case BL33_IMAGE_ID:
 		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
diff --git a/plat/intel/soc/agilex5/include/socfpga_plat_def.h b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
index acdbe17..9bfc304 100644
--- a/plat/intel/soc/agilex5/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,7 +22,7 @@
 #define PLAT_PRIMARY_CPU_A76					0x200
 #define PLAT_CLUSTER_ID_MPIDR_AFF_SHIFT				MPIDR_AFF2_SHIFT
 #define PLAT_CPU_ID_MPIDR_AFF_SHIFT				MPIDR_AFF1_SHIFT
-#define PLAT_L2_RESET_REQ			0xB007C0DE
+#define PLAT_L2_RESET_REQ					0xB007C0DE
 
 /* System Counter */
 /* TODO: Update back to 400MHz.
@@ -31,7 +32,7 @@
 #define PLAT_SYS_COUNTER_FREQ_IN_MHZ				(400)
 
 /* FPGA config helpers */
-#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR				0x400000
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR				0x80400000
 #define INTEL_SIP_SMC_FPGA_CONFIG_SIZE				0x2000000
 
 /* QSPI Setting */
@@ -101,7 +102,7 @@
 /*******************************************************************************
  * WDT related constants
  ******************************************************************************/
-#define WDT_BASE			(0x10D00200)
+#define WDT_BASE						(0x10D00200)
 
 /*******************************************************************************
  * GIC related constants
@@ -116,13 +117,13 @@
 /*******************************************************************************
  * SDMMC related pointer function
  ******************************************************************************/
-#define SDMMC_READ_BLOCKS	sdmmc_read_blocks
-#define SDMMC_WRITE_BLOCKS	sdmmc_write_blocks
+#define SDMMC_READ_BLOCKS					sdmmc_read_blocks
+#define SDMMC_WRITE_BLOCKS					sdmmc_write_blocks
 
 /*******************************************************************************
  * sysmgr.boot_scratch_cold6 & 7 (64bit) are used to indicate L2 reset
  * is done and HPS should trigger warm reset via RMR_EL3.
  ******************************************************************************/
-#define L2_RESET_DONE_REG			0x10D12218
+#define L2_RESET_DONE_REG					0x10D12218
 
 #endif /* PLAT_SOCFPGA_DEF_H */
diff --git a/plat/intel/soc/agilex5/platform.mk b/plat/intel/soc/agilex5/platform.mk
index 7302164..409c7b1 100644
--- a/plat/intel/soc/agilex5/platform.mk
+++ b/plat/intel/soc/agilex5/platform.mk
@@ -1,6 +1,7 @@
 #
 # Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
 # Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+# Copyright (c) 2024, Altera Corporation. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -8,6 +9,7 @@
 PLAT_INCLUDES		:=	\
 			-Iplat/intel/soc/agilex5/include/		\
 			-Iplat/intel/soc/common/drivers/		\
+			-Iplat/intel/soc/common/lib/sha/		\
 			-Iplat/intel/soc/common/include/
 
 # GIC-600 configuration
@@ -33,6 +35,7 @@
 			plat/intel/soc/common/drivers/sdmmc/sdmmc.c			\
 			plat/intel/soc/common/drivers/ddr/ddr.c			\
 			plat/intel/soc/common/drivers/nand/nand.c			\
+			plat/intel/soc/common/lib/sha/sha.c				\
 			plat/intel/soc/common/socfpga_delay_timer.c
 
 BL2_SOURCES		+=	\
@@ -107,6 +110,11 @@
 $(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
 $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
 
+# Configs for VAB Authentication
+SOCFPGA_SECURE_VAB_AUTH  := 	0
+$(eval $(call assert_boolean,SOCFPGA_SECURE_VAB_AUTH))
+$(eval $(call add_define,SOCFPGA_SECURE_VAB_AUTH))
+
 PROGRAMMABLE_RESET_ADDRESS	:= 0
 RESET_TO_BL2			:= 1
-BL2_INV_DCACHE			:= 0
+BL2_INV_DCACHE			:= 0
\ No newline at end of file
diff --git a/plat/intel/soc/common/include/socfpga_vab.h b/plat/intel/soc/common/include/socfpga_vab.h
index f6081df..4587d7f 100644
--- a/plat/intel/soc/common/include/socfpga_vab.h
+++ b/plat/intel/soc/common/include/socfpga_vab.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,10 +8,28 @@
 #ifndef SOCFPGA_VAB_H
 #define SOCFPGA_VAB_H
 
-
 #include <stdlib.h>
 #include "socfpga_fcs.h"
 
+/* Macros */
+#define IS_BYTE_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
+#define BYTE_ALIGN(x, a)		__ALIGN_MASK((x), (typeof(x))(a)-1)
+#define __ALIGN_MASK(x, mask)		(((x)+(mask))&~(mask))
+#define VAB_CERT_HEADER_SIZE		sizeof(struct fcs_hps_vab_certificate_header)
+#define VAB_CERT_MAGIC_OFFSET		offsetof(struct fcs_hps_vab_certificate_header, d)
+#define VAB_CERT_FIT_SHA384_OFFSET	offsetof(struct fcs_hps_vab_certificate_data, fcs_sha384[0])
+#define SDM_CERT_MAGIC_NUM		0x25D04E7F
+#define CHUNKSZ_PER_WD_RESET		(256 * 1024)
+#define CCERT_CMD_TEST_PGM_MASK		0x80000000 //TODO: ATF FDT location
+
+/* SHA related return Macro */
+#define ENOVABCERT			1 /* VAB certificate not available */
+#define EIMGERR				2 /* Image format/size not valid */
+#define ETIMEOUT			3 /* Execution timeout */
+#define EPROCESS			4 /* Process error */
+#define EKEYREJECTED			5 /* Key was rejected by service */
+#define EINITREJECTED			6 /* VAB init was rejected */
+
 struct fcs_hps_vab_certificate_data {
 	uint32_t vab_cert_magic_num;			/* offset 0x10 */
 	uint32_t flags;
@@ -27,28 +46,9 @@
 	/* keychain starts at offset 0x50 */
 };
 
-/* Macros */
-#define IS_BYTE_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
-#define BYTE_ALIGN(x, a)		__ALIGN_MASK((x), (typeof(x))(a)-1)
-#define __ALIGN_MASK(x, mask)		(((x)+(mask))&~(mask))
-#define VAB_CERT_HEADER_SIZE		sizeof(struct fcs_hps_vab_certificate_header)
-#define VAB_CERT_MAGIC_OFFSET		offsetof(struct fcs_hps_vab_certificate_header, d)
-#define VAB_CERT_FIT_SHA384_OFFSET	offsetof(struct fcs_hps_vab_certificate_data, fcs_sha384[0])
-#define SDM_CERT_MAGIC_NUM		0x25D04E7F
-#define CHUNKSZ_PER_WD_RESET		(256 * 1024)
-
-/* SHA related return Macro */
-#define ENOVABIMG		1 /* VAB certificate not available */
-#define EIMGERR		2 /* Image format/size not valid */
-#define ETIMEOUT		3 /* Execution timeout */
-#define EPROCESS		4 /* Process error */
-#define EKEYREJECTED		5/* Key was rejected by service */
-
 /* Function Definitions */
-static size_t get_img_size(uint8_t *img_buf, size_t img_buf_sz);
-int socfpga_vendor_authentication(void **p_image, size_t *p_size);
-static uint32_t get_unaligned_le32(const void *p);
-void sha384_csum_wd(const unsigned char *input, unsigned int ilen,
-unsigned char *output, unsigned int chunk_sz);
-
+size_t get_img_size(uint8_t *img_buf, size_t img_buf_sz);
+uint32_t get_unaligned_le32(const void *p);
+int socfpga_vab_authentication(void **p_image, size_t *p_size);
+int socfpga_vab_init(unsigned int image_id);
 #endif
diff --git a/plat/intel/soc/common/lib/sha/sha.c b/plat/intel/soc/common/lib/sha/sha.c
new file mode 100644
index 0000000..9a6adc6
--- /dev/null
+++ b/plat/intel/soc/common/lib/sha/sha.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "sha.h"
+#include "wdt/watchdog.h"
+
+/* SHA384 certificate ID */
+#define SHA384_H0	0xcbbb9d5dc1059ed8ULL
+#define SHA384_H1	0x629a292a367cd507ULL
+#define SHA384_H2	0x9159015a3070dd17ULL
+#define SHA384_H3	0x152fecd8f70e5939ULL
+#define SHA384_H4	0x67332667ffc00b31ULL
+#define SHA384_H5	0x8eb44a8768581511ULL
+#define SHA384_H6	0xdb0c2e0d64f98fa7ULL
+#define SHA384_H7	0x47b5481dbefa4fa4ULL
+
+/* SHA512 certificate ID */
+#define SHA512_H0	0x6a09e667f3bcc908ULL
+#define SHA512_H1	0xbb67ae8584caa73bULL
+#define SHA512_H2	0x3c6ef372fe94f82bULL
+#define SHA512_H3	0xa54ff53a5f1d36f1ULL
+#define SHA512_H4	0x510e527fade682d1ULL
+#define SHA512_H5	0x9b05688c2b3e6c1fULL
+#define SHA512_H6	0x1f83d9abfb41bd6bULL
+#define SHA512_H7	0x5be0cd19137e2179ULL
+
+void sha384_init(sha512_context *ctx)
+{
+	ctx->state[0] = SHA384_H0;
+	ctx->state[1] = SHA384_H1;
+	ctx->state[2] = SHA384_H2;
+	ctx->state[3] = SHA384_H3;
+	ctx->state[4] = SHA384_H4;
+	ctx->state[5] = SHA384_H5;
+	ctx->state[6] = SHA384_H6;
+	ctx->state[7] = SHA384_H7;
+	ctx->count[0] = ctx->count[1] = 0;
+}
+
+void sha384_update(sha512_context *ctx, const uint8_t *input, uint32_t length)
+{
+	sha512_base_do_update(ctx, input, length);
+}
+
+void sha384_finish(sha512_context *ctx, uint8_t digest[SHA384_SUM_LEN])
+{
+	int i;
+
+	sha512_base_do_finalize(ctx);
+	for (i = 0; i < SHA384_SUM_LEN / sizeof(uint64_t); i++)
+		PUT_UINT64_BE(ctx->state[i], digest, i * 8);
+}
+
+void sha384_start(const unsigned char *input, unsigned int len,
+					unsigned char *output, unsigned int chunk_sz)
+{
+	/* TODO: Shall trigger watchdog for each chuck byte. */
+	sha512_context ctx;
+	const unsigned char *end;
+	unsigned char *curr;
+	int chunk;
+
+	sha384_init(&ctx);
+
+	curr = (unsigned char *)input;
+	end = input + len;
+	while (curr < end) {
+		chunk = end - curr;
+		if (chunk > chunk_sz) {
+			chunk = chunk_sz;
+		}
+		sha384_update(&ctx, curr, chunk);
+		curr += chunk;
+		watchdog_sw_rst();
+	}
+
+	sha384_finish(&ctx, output);
+}
+
+/* SHA512 Start Here */
+void sha512_init(sha512_context *ctx)
+{
+	ctx->state[0] = SHA512_H0;
+	ctx->state[1] = SHA512_H1;
+	ctx->state[2] = SHA512_H2;
+	ctx->state[3] = SHA512_H3;
+	ctx->state[4] = SHA512_H4;
+	ctx->state[5] = SHA512_H5;
+	ctx->state[6] = SHA512_H6;
+	ctx->state[7] = SHA512_H7;
+	ctx->count[0] = ctx->count[1] = 0;
+}
+
+void sha512_update(sha512_context *ctx, const uint8_t *input, uint32_t length)
+{
+	sha512_base_do_update(ctx, input, length);
+}
+
+void sha512_finish(sha512_context *ctx, uint8_t digest[SHA512_SUM_LEN])
+{
+	int i;
+
+	sha512_base_do_finalize(ctx);
+	for (i = 0; i < SHA512_SUM_LEN / sizeof(uint64_t); i++)
+		PUT_UINT64_BE(ctx->state[i], digest, i * 8);
+}
+
+void sha512_start(const unsigned char *input, unsigned int len, unsigned char *output)
+{
+	/* TODO: Shall trigger watchdog for each chuck byte. */
+	sha512_context ctx;
+
+	sha384_init(&ctx);
+	sha512_update(&ctx, input, len);
+	sha512_finish(&ctx, output);
+}
+
+void sha512_transform(uint64_t *state, const uint8_t *input)
+{
+	uint64_t a, b, c, d, e, f, g, h, t1, t2;
+
+	int i;
+	uint64_t W[16];
+
+	/* load the state into our registers */
+	a = state[0];   b = state[1];   c = state[2];   d = state[3];
+	e = state[4];   f = state[5];   g = state[6];   h = state[7];
+
+	/* now iterate */
+	for (i = 0 ; i < 80; i += 8) {
+		if (!(i & 8)) {
+			int j;
+
+			if (i < 16) {
+				/* load the input */
+				for (j = 0; j < 16; j++)
+					LOAD_OP(i + j, W, input);
+			} else {
+				for (j = 0; j < 16; j++) {
+					BLEND_OP(i + j, W);
+				}
+			}
+		}
+
+		t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i & 15)];
+		t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
+		t1 = g + e1(d) + Ch(d, e, f) + sha512_K[i+1] + W[(i & 15) + 1];
+		t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
+		t1 = f + e1(c) + Ch(c, d, e) + sha512_K[i+2] + W[(i & 15) + 2];
+		t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
+		t1 = e + e1(b) + Ch(b, c, d) + sha512_K[i+3] + W[(i & 15) + 3];
+		t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
+		t1 = d + e1(a) + Ch(a, b, c) + sha512_K[i+4] + W[(i & 15) + 4];
+		t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
+		t1 = c + e1(h) + Ch(h, a, b) + sha512_K[i+5] + W[(i & 15) + 5];
+		t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
+		t1 = b + e1(g) + Ch(g, h, a) + sha512_K[i+6] + W[(i & 15) + 6];
+		t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
+		t1 = a + e1(f) + Ch(f, g, h) + sha512_K[i+7] + W[(i & 15) + 7];
+		t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1 + t2;
+	}
+
+	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+	/* erase our data */
+	a = b = c = d = e = f = g = h = t1 = t2 = 0;
+}
+
+void sha512_block_fn(sha512_context *sst, const uint8_t *src,
+				    int blocks)
+{
+	while (blocks--) {
+		sha512_transform(sst->state, src);
+		src += SHA512_BLOCK_SIZE;
+	}
+}
+
+
+void sha512_base_do_finalize(sha512_context *sctx)
+{
+	const int bit_offset = SHA512_BLOCK_SIZE - sizeof(uint64_t[2]);
+	uint64_t *bits = (uint64_t *)(sctx->buf + bit_offset);
+	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
+
+	sctx->buf[partial++] = 0x80;
+	if (partial > bit_offset) {
+		memset(sctx->buf + partial, 0x0, SHA512_BLOCK_SIZE - partial);
+		partial = 0;
+
+		sha512_block_fn(sctx, sctx->buf, 1);
+	}
+
+	memset(sctx->buf + partial, 0x0, bit_offset - partial);
+	bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
+	bits[1] = cpu_to_be64(sctx->count[0] << 3);
+
+	sha512_block_fn(sctx, sctx->buf, 1);
+}
+
+void sha512_base_do_update(sha512_context *sctx,
+					const uint8_t *data,
+					unsigned int len)
+{
+	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
+
+	sctx->count[0] += len;
+	if (sctx->count[0] < len)
+		sctx->count[1]++;
+
+	if (((partial + len) >= SHA512_BLOCK_SIZE)) {
+		int blocks;
+
+		if (partial) {
+			int p = SHA512_BLOCK_SIZE - partial;
+
+			memcpy(sctx->buf + partial, data, p);
+			data += p;
+			len -= p;
+
+			sha512_block_fn(sctx, sctx->buf, 1);
+		}
+
+		blocks = len / SHA512_BLOCK_SIZE;
+		len %= SHA512_BLOCK_SIZE;
+
+		if (blocks) {
+			sha512_block_fn(sctx, data, blocks);
+			data += blocks * SHA512_BLOCK_SIZE;
+		}
+		partial = 0;
+	}
+	if (len)
+		memcpy(sctx->buf + partial, data, len);
+}
diff --git a/plat/intel/soc/common/lib/sha/sha.h b/plat/intel/soc/common/lib/sha/sha.h
new file mode 100644
index 0000000..41b5fa8
--- /dev/null
+++ b/plat/intel/soc/common/lib/sha/sha.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_SHA_H
+#define SOCFPGA_SHA_H
+
+#include <stdlib.h>
+
+
+#define SHA384_SUM_LEN			48
+#define SHA384_DER_LEN			19
+#define SHA512_SUM_LEN			64
+#define SHA512_DER_LEN			19
+#define SHA512_BLOCK_SIZE		128
+
+
+/* MACRO Function */
+#define GET_UINT64_BE(n, b, i) {	\
+	(n) = ((unsigned long long) (b)[(i)] << 56) |\
+	((unsigned long long) (b)[(i) + 1] << 48) |\
+	((unsigned long long) (b)[(i) + 2] << 40) |\
+	((unsigned long long) (b)[(i) + 3] << 32) |\
+	((unsigned long long) (b)[(i) + 4] << 24) |\
+	((unsigned long long) (b)[(i) + 5] << 16) |\
+	((unsigned long long) (b)[(i) + 6] <<  8) |\
+	((unsigned long long) (b)[(i) + 7]);\
+}
+
+#define PUT_UINT64_BE(n, b, i) {	\
+	(b)[(i)] = (unsigned char) ((n) >> 56);\
+	(b)[(i) + 1] = (unsigned char) ((n) >> 48);\
+	(b)[(i) + 2] = (unsigned char) ((n) >> 40);\
+	(b)[(i) + 3] = (unsigned char) ((n) >> 32);\
+	(b)[(i) + 4] = (unsigned char) ((n) >> 24);\
+	(b)[(i) + 5] = (unsigned char) ((n) >> 16);\
+	(b)[(i) + 6] = (unsigned char) ((n) >>  8);\
+	(b)[(i) + 7] = (unsigned char) ((n));\
+}
+
+#define e0(x)		(ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39))
+#define e1(x)		(ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41))
+#define s0(x)		(ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
+#define s1(x)		(ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6))
+
+/* Inline Function Definitions */
+/* ror64() to rotate its right in 64 bits. */
+static inline uint64_t ror64(uint64_t input, unsigned int shift)
+{
+	return (input >> (shift & 63)) | (input << ((-shift) & 63));
+}
+
+static inline uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
+{
+	return z ^ (x & (y ^ z));
+}
+
+static inline uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
+{
+	return (x & y) | (z & (x | y));
+}
+
+static inline void LOAD_OP(int I, uint64_t *W, const uint8_t *input)
+{
+	GET_UINT64_BE(W[I], input, I*8);
+}
+
+static inline void BLEND_OP(int I, uint64_t *W)
+{
+	W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]);
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+inline uint32_t le32_to_cpue(const uint32_t *p)
+{
+	return (uint32_t)*p;
+}
+#else
+inline uint32_t le32_to_cpue(const uint32_t *p)
+{
+	return swab32(*p);
+}
+#endif
+
+static const uint64_t sha512_K[80] = {
+	0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+	0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+	0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+	0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+	0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+	0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+	0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+	0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+	0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+	0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+	0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+	0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+	0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+	0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+	0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+	0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+	0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+	0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+	0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+	0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+	0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+	0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+	0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+	0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+	0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+	0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+	0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+#define	__cpu_to_le64(x)	((__force __le64)(__u64)(x))
+
+#define _uswap_64(x, sfx)	\
+	((((x) & 0xff00000000000000##sfx) >> 56) |\
+	(((x) & 0x00ff000000000000##sfx) >> 40) |\
+	(((x) & 0x0000ff0000000000##sfx) >> 24) |\
+	(((x) & 0x000000ff00000000##sfx) >>  8) |\
+	(((x) & 0x00000000ff000000##sfx) <<  8) |\
+	(((x) & 0x0000000000ff0000##sfx) << 24) |\
+	(((x) & 0x000000000000ff00##sfx) << 40) |\
+	(((x) & 0x00000000000000ff##sfx) << 56))
+
+#if defined(__GNUC__)
+#define uswap_64(x)		_uswap_64(x, ull)
+#else
+#define uswap_64(x)		_uswap_64(x)
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be64(x)		uswap_64(x)
+#else
+#define cpu_to_be64(x)		(x)
+#endif
+
+typedef struct {
+	uint64_t state[SHA512_SUM_LEN / 8];
+	uint64_t count[2];
+	uint8_t buf[SHA512_BLOCK_SIZE];
+} sha512_context;
+
+/* Function Definitions */
+/* SHA384 Start Here */
+void sha384_init(sha512_context *ctx);
+void sha384_update(sha512_context *ctx, const uint8_t *input, uint32_t length);
+void sha384_finish(sha512_context *ctx, uint8_t digest[SHA384_SUM_LEN]);
+void sha384_start(const unsigned char *input, unsigned int len,
+			unsigned char *output, unsigned int chunk_sz);
+/* SHA512 Start Here */
+void sha512_init(sha512_context *ctx);
+void sha512_update(sha512_context *ctx, const uint8_t *input, uint32_t length);
+void sha512_finish(sha512_context *ctx, uint8_t digest[SHA512_SUM_LEN]);
+void sha512_start(const unsigned char *input, unsigned int len,
+			unsigned char *output);
+void sha512_transform(uint64_t *state, const uint8_t *input);
+void sha512_block_fn(sha512_context *sst, const uint8_t *src, int blocks);
+void sha512_base_do_finalize(sha512_context *sctx);
+void sha512_base_do_update(sha512_context *sctx, const uint8_t *data,
+				unsigned int len);
+
+#endif
diff --git a/plat/intel/soc/common/socfpga_vab.c b/plat/intel/soc/common/socfpga_vab.c
index e16610c..d1734c8 100644
--- a/plat/intel/soc/common/socfpga_vab.c
+++ b/plat/intel/soc/common/socfpga_vab.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,18 +9,23 @@
 #include <assert.h>
 #include <errno.h>
 
+#include "../lib/sha/sha.h"
+
 #include <arch_helpers.h>
+#include <common/bl_common.h>
 #include <common/debug.h>
+#include <common/desc_image_load.h>
 #include <common/tbbr/tbbr_img_def.h>
 #include <drivers/delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/utils.h>
+#include <plat/common/platform.h>
 #include <tools_share/firmware_image_package.h>
 
 #include "socfpga_mailbox.h"
 #include "socfpga_vab.h"
 
-static size_t get_img_size(uint8_t *img_buf, size_t img_buf_sz)
+size_t get_img_size(uint8_t *img_buf, size_t img_buf_sz)
 {
 	uint8_t *img_buf_end = img_buf + img_buf_sz;
 	uint32_t cert_sz = get_unaligned_le32(img_buf_end - sizeof(uint32_t));
@@ -35,9 +41,33 @@
 	return 0;
 }
 
+int socfpga_vab_init(unsigned int image_id)
+{
+	int ret = 0;
+	size_t image_size;
+	void *image_base_ptr;
+	/*
+	 * Get information about the images to load.
+	 */
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+	assert(bl_mem_params);
 
+	if (bl_mem_params == NULL) {
+		ERROR("SOCFPGA VAB Init failed\n");
+		return -EINITREJECTED;
+	}
+
+	if ((image_id == BL31_IMAGE_ID) || (image_id == BL33_IMAGE_ID)) {
+		image_base_ptr = (void *)bl_mem_params->image_info.image_base;
+		image_size = bl_mem_params->image_info.image_size;
+		ret = socfpga_vab_authentication(&image_base_ptr, &image_size);
+	}
+
+	return ret;
+}
 
-int socfpga_vendor_authentication(void **p_image, size_t *p_size)
+int socfpga_vab_authentication(void **p_image, size_t *p_size)
 {
 	int retry_count = 20;
 	uint8_t hash384[FCS_SHA384_WORD_SIZE];
@@ -46,51 +76,46 @@
 	uint8_t *cert_hash_ptr, *mbox_relocate_data_addr;
 	uint32_t resp = 0, resp_len = 1;
 	int ret = 0;
+	uint8_t u8_buf_static[MBOX_DATA_MAX_LEN];
+
+	mbox_relocate_data_addr = u8_buf_static;
 
 	img_addr = (uintptr_t)*p_image;
 	img_sz = get_img_size((uint8_t *)img_addr, *p_size);
 
 	if (!img_sz) {
-		NOTICE("VAB certificate not found in image!\n");
-		return -ENOVABIMG;
+		ERROR("VAB certificate not found in image!\n");
+		return -ENOVABCERT;
 	}
 
 	if (!IS_BYTE_ALIGNED(img_sz, sizeof(uint32_t))) {
-		NOTICE("Image size (%d bytes) not aliged to 4 bytes!\n", img_sz);
+		ERROR("Image size (%d bytes) not aliged to 4 bytes!\n", img_sz);
 		return -EIMGERR;
 	}
 
 	/* Generate HASH384 from the image */
-	/* TODO: This part need to cross check !!!!!! */
-	sha384_csum_wd((uint8_t *)img_addr, img_sz, hash384, CHUNKSZ_PER_WD_RESET);
-	cert_hash_ptr = (uint8_t *)(img_addr + img_sz +
-	VAB_CERT_MAGIC_OFFSET + VAB_CERT_FIT_SHA384_OFFSET);
+	sha384_start((uint8_t *)img_addr, img_sz, hash384, CHUNKSZ_PER_WD_RESET);
+	cert_hash_ptr = (uint8_t *)(img_addr + img_sz + VAB_CERT_MAGIC_OFFSET +
+								VAB_CERT_FIT_SHA384_OFFSET);
 
 	/*
 	 * Compare the SHA384 found in certificate against the SHA384
 	 * calculated from image
 	 */
 	if (memcmp(hash384, cert_hash_ptr, FCS_SHA384_WORD_SIZE)) {
-		NOTICE("SHA384 does not match!\n");
+		ERROR("SHA384 does not match!\n");
 		return -EKEYREJECTED;
 	}
 
-
 	mbox_data_addr = img_addr + img_sz - sizeof(uint32_t);
 	/* Size in word (32bits) */
 	mbox_data_sz = (BYTE_ALIGN(*p_size - img_sz, sizeof(uint32_t))) >> 2;
 
-	NOTICE("mbox_data_addr = %lx    mbox_data_sz = %d\n", mbox_data_addr, mbox_data_sz);
-
-	/* TODO: This part need to cross check !!!!!! */
-	// mbox_relocate_data_addr = (uint8_t *)malloc(mbox_data_sz * sizeof(uint32_t));
-	// if (!mbox_relocate_data_addr) {
-		// NOTICE("Cannot allocate memory for VAB certificate relocation!\n");
-		// return -ENOMEM;
-	// }
+	VERBOSE("mbox_data_addr = %lx    mbox_data_sz = %d\n", mbox_data_addr, mbox_data_sz);
 
 	memcpy(mbox_relocate_data_addr, (uint8_t *)mbox_data_addr, mbox_data_sz * sizeof(uint32_t));
-	*(uint32_t *)mbox_relocate_data_addr = 0;
+
+	*((unsigned int *)mbox_relocate_data_addr) = CCERT_CMD_TEST_PGM_MASK;
 
 	do {
 		/* Invoke SMC call to ATF to send the VAB certificate to SDM */
@@ -109,7 +134,6 @@
 	/* Free the relocate certificate memory space */
 	zeromem((void *)&mbox_relocate_data_addr, sizeof(uint32_t));
 
-
 	/* Exclude the size of the VAB certificate from image size */
 	*p_size = img_sz;
 
@@ -121,40 +145,32 @@
 		 /* 0x85 = Not allowed under current security setting */
 		if (ret == MBOX_RESP_ERR(0x85)) {
 			/* SDM bypass authentication */
-			NOTICE("Image Authentication bypassed at address\n");
+			ERROR("Image Authentication bypassed at address\n");
 			return 0;
 		}
-		NOTICE("VAB certificate authentication failed in SDM\n");
+		ERROR("VAB certificate authentication failed in SDM\n");
 		/* 0x1FF = The device is busy */
 		if (ret == MBOX_RESP_ERR(0x1FF)) {
-			NOTICE("Operation timed out\n");
+			ERROR("Operation timed out\n");
 			return -ETIMEOUT;
 		} else if (ret == MBOX_WRONG_ID) {
-			NOTICE("No such process\n");
+			ERROR("No such process\n");
 			return -EPROCESS;
 		}
+		return -EAUTH;
 	} else {
 		/* If Certificate Process Status has error */
 		if (resp) {
-			NOTICE("VAB certificate execution format error\n");
+			ERROR("VAB certificate execution format error\n");
 			return -EIMGERR;
 		}
 	}
 
-	NOTICE("Image Authentication bypassed at address\n");
+	NOTICE("%s 0x%lx (%d bytes)\n", "Image Authentication passed at address", img_addr, img_sz);
 	return ret;
-
-}
-
-static uint32_t get_unaligned_le32(const void *p)
-{
-	/* TODO: Temp for testing */
-	//return le32_to_cpup((__le32 *)p);
-	return 0;
 }
 
-void sha384_csum_wd(const unsigned char *input, unsigned int ilen,
-		unsigned char *output, unsigned int chunk_sz)
+uint32_t get_unaligned_le32(const void *p)
 {
-	/* TODO: Update sha384 start, update and finish */
+	return le32_to_cpue((uint32_t *)p);
 }
diff --git a/plat/nxp/s32/s32g274ardb2/include/platform_def.h b/plat/nxp/s32/s32g274ardb2/include/platform_def.h
index bdfeee2..1a4c495 100644
--- a/plat/nxp/s32/s32g274ardb2/include/platform_def.h
+++ b/plat/nxp/s32/s32g274ardb2/include/platform_def.h
@@ -54,8 +54,7 @@
 /* Console settings */
 #define UART_BASE			UL(0x401C8000)
 #define UART_BAUDRATE			U(115200)
-/* FIRC clock */
-#define UART_CLOCK_HZ			U(48000000)
+#define UART_CLOCK_HZ			U(125000000)
 
 #define S32G_FIP_BASE			UL(0x34100000)
 #define S32G_FIP_SIZE			UL(0x100000)
diff --git a/plat/nxp/s32/s32g274ardb2/plat_helpers.S b/plat/nxp/s32/s32g274ardb2/plat_helpers.S
index 193c884..10c0035 100644
--- a/plat/nxp/s32/s32g274ardb2/plat_helpers.S
+++ b/plat/nxp/s32/s32g274ardb2/plat_helpers.S
@@ -38,6 +38,8 @@
 
 /* void plat_crash_console_flush(void); */
 func plat_crash_console_flush
+	mov_imm	x0, UART_BASE
+	b	console_linflex_core_flush
 	ret
 endfunc plat_crash_console_flush
 
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
index c38cdef..68d1db2 100644
--- a/plat/xilinx/common/include/pm_common.h
+++ b/plat/xilinx/common/include/pm_common.h
@@ -18,7 +18,6 @@
 
 #if IPI_CRC_CHECK
 #define PAYLOAD_ARG_CNT         8U
-#define RET_PAYLOAD_ARG_CNT	7U
 #define IPI_W0_TO_W6_SIZE       28U
 #define PAYLOAD_CRC_POS         7U
 #define CRC_INIT_VALUE          0x4F4EU
@@ -26,8 +25,8 @@
 #define CRC_POLYNOM             0x8005U
 #else
 #define PAYLOAD_ARG_CNT		7U
-#define RET_PAYLOAD_ARG_CNT	6U
 #endif
+#define RET_PAYLOAD_ARG_CNT	6U
 #define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
 
 #define TZ_VERSION_MAJOR	1
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index b431a6c..193c5dc 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -503,8 +503,8 @@
 				  void *handle, uint32_t security_flag)
 {
 	enum pm_ret_status ret;
-	uint32_t buf[PAYLOAD_ARG_CNT] = {0};
-	uint32_t payload[PAYLOAD_ARG_CNT] = {0};
+	uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0U};
+	uint32_t payload[PAYLOAD_ARG_CNT] = {0U};
 	uint32_t module_id;
 
 	module_id = (api_id & MODULE_ID_MASK) >> 8U;
@@ -514,7 +514,7 @@
 			 pm_arg[4], pm_arg[5]);
 
 	ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
-			       PAYLOAD_ARG_CNT);
+			       RET_PAYLOAD_ARG_CNT);
 
 	SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
 		 (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
diff --git a/services/spd/pncd/pncd_common.c b/services/spd/pncd/pncd_common.c
index 6fdb629..8e89491 100644
--- a/services/spd/pncd/pncd_common.c
+++ b/services/spd/pncd/pncd_common.c
@@ -67,8 +67,9 @@
 	/* Apply the Secure EL1 system register context and switch to it */
 	assert(cm_get_context(SECURE) == &pnc_ctx->cpu_ctx);
 	cm_el1_sysregs_context_restore(SECURE);
+
 #if CTX_INCLUDE_FPREGS
-	fpregs_context_restore(get_fpregs_ctx(cm_get_context(SECURE)));
+	simd_ctx_restore(SECURE);
 #endif
 	cm_set_next_eret_context(SECURE);
 
@@ -90,8 +91,9 @@
 	/* Save the Secure EL1 system register context */
 	assert(cm_get_context(SECURE) == &pnc_ctx->cpu_ctx);
 	cm_el1_sysregs_context_save(SECURE);
+
 #if CTX_INCLUDE_FPREGS
-	fpregs_context_save(get_fpregs_ctx(cm_get_context(SECURE)));
+	simd_ctx_save(SECURE, false);
 #endif
 
 	assert(pnc_ctx->c_rt_ctx != 0);
diff --git a/services/spd/pncd/pncd_main.c b/services/spd/pncd/pncd_main.c
index 99c4aa1..cc1c1f2 100644
--- a/services/spd/pncd/pncd_main.c
+++ b/services/spd/pncd/pncd_main.c
@@ -55,8 +55,9 @@
 	assert(sec_state_is_valid(security_state));
 
 	cm_el1_sysregs_context_save((uint32_t) security_state);
+
 #if CTX_INCLUDE_FPREGS
-	fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state)));
+	simd_ctx_save((uint32_t)security_state, false);
 #endif
 }
 
@@ -72,8 +73,9 @@
 
 	/* Restore state */
 	cm_el1_sysregs_context_restore((uint32_t) security_state);
+
 #if CTX_INCLUDE_FPREGS
-	fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state)));
+	simd_ctx_restore((uint32_t)security_state);
 #endif
 
 	cm_set_next_eret_context((uint32_t) security_state);
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
index f2048a3..aae2d9a 100644
--- a/services/spd/trusty/trusty.c
+++ b/services/spd/trusty/trusty.c
@@ -118,8 +118,10 @@
 	 * when it's needed the PSCI caller has preserved FP context before
 	 * going here.
 	 */
-	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
-		fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state)));
+	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME) {
+		simd_ctx_save(security_state, false);
+	}
+
 	cm_el1_sysregs_context_save(security_state);
 
 	ctx->saved_security_state = security_state;
@@ -128,8 +130,9 @@
 	assert(ctx->saved_security_state == ((security_state == 0U) ? 1U : 0U));
 
 	cm_el1_sysregs_context_restore(security_state);
-	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
-		fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state)));
+	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME) {
+		simd_ctx_restore(security_state);
+	}
 
 	cm_set_next_eret_context(security_state);
 
@@ -320,7 +323,7 @@
 	ep_info = bl31_plat_get_next_image_ep_info(SECURE);
 	assert(ep_info != NULL);
 
-	fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+	simd_ctx_save(NON_SECURE, false);
 	cm_el1_sysregs_context_save(NON_SECURE);
 
 	cm_set_context(&ctx->cpu_ctx, SECURE);
@@ -337,7 +340,7 @@
 	}
 
 	cm_el1_sysregs_context_restore(SECURE);
-	fpregs_context_restore(get_fpregs_ctx(cm_get_context(SECURE)));
+	simd_ctx_restore(SECURE);
 	cm_set_next_eret_context(SECURE);
 
 	ctx->saved_security_state = ~0U; /* initial saved state is invalid */
@@ -346,7 +349,7 @@
 	(void)trusty_context_switch_helper(&ctx->saved_sp, &zero_args);
 
 	cm_el1_sysregs_context_restore(NON_SECURE);
-	fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+	simd_ctx_restore(NON_SECURE);
 	cm_set_next_eret_context(NON_SECURE);
 
 	return 1;
diff --git a/services/std_svc/errata_abi/cpu_errata_info.h b/services/std_svc/errata_abi/cpu_errata_info.h
index 61e1076..d688431 100644
--- a/services/std_svc/errata_abi/cpu_errata_info.h
+++ b/services/std_svc/errata_abi/cpu_errata_info.h
@@ -8,6 +8,7 @@
 #define ERRATA_CPUSPEC_H
 
 #include <stdint.h>
+#include <arch.h>
 #include <arch_helpers.h>
 
 #if __aarch64__
@@ -31,8 +32,6 @@
 /* Default values for unused memory in the array */
 #define UNDEF_ERRATA		{UINT_MAX, UCHAR_MAX, UCHAR_MAX}
 
-#define EXTRACT_PARTNUM(x)	((x >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
-
 #define RXPX_RANGE(x, y, z)	(((x >= y) && (x <= z)) ? true : false)
 
 /*
diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c
index e8beae1..4360832 100644
--- a/services/std_svc/spm/el3_spmc/spmc_setup.c
+++ b/services/std_svc/spm/el3_spmc/spmc_setup.c
@@ -322,14 +322,7 @@
 	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), mair_el1,
 		      mmu_cfg_params[MMU_CFG_MAIR]);
 
-	/* Store the initialised SCTLR_EL1 value in the cpu_context */
-#if (ERRATA_SPECULATIVE_AT)
-	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
-		      CTX_ERRATA_SPEC_AT_TCR_EL1, mmu_cfg_params[MMU_CFG_TCR]);
-#else
-	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), tcr_el1,
-		      mmu_cfg_params[MMU_CFG_TCR]);
-#endif /* ERRATA_SPECULATIVE_AT */
+	write_ctx_tcr_el1_reg_errata(ctx, mmu_cfg_params[MMU_CFG_TCR]);
 
 	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), ttbr0_el1,
 		      mmu_cfg_params[MMU_CFG_TTBR0]);
@@ -340,12 +333,7 @@
 	u_register_t sctlr_el1_val;
 
 	/* Setup SCTLR_EL1 */
-#if (ERRATA_SPECULATIVE_AT)
-	sctlr_el1_val = read_ctx_reg(get_errata_speculative_at_ctx(ctx),
-				 CTX_ERRATA_SPEC_AT_SCTLR_EL1);
-#else
-	sctlr_el1_val = read_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1);
-#endif /* ERRATA_SPECULATIVE_AT */
+	sctlr_el1_val = read_ctx_sctlr_el1_reg_errata(ctx);
 
 	sctlr_el1_val |=
 		/*SCTLR_EL1_RES1 |*/
@@ -381,12 +369,7 @@
 	);
 
 	/* Store the initialised SCTLR_EL1 value in the cpu_context */
-#if (ERRATA_SPECULATIVE_AT)
-	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
-		      CTX_ERRATA_SPEC_AT_SCTLR_EL1, sctlr_el1_val);
-#else
-	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1, sctlr_el1_val);
-#endif /* ERRATA_SPECULATIVE_AT */
+	write_ctx_sctlr_el1_reg_errata(ctx, sctlr_el1_val);
 }
 
 static void spmc_el0_sp_setup_system_registers(struct secure_partition_desc *sp,
diff --git a/services/std_svc/spm/spm_mm/spm_mm_main.c b/services/std_svc/spm/spm_mm/spm_mm_main.c
index 1ff7bb7..34e2c00 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_main.c
+++ b/services/std_svc/spm/spm_mm/spm_mm_main.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
  */
@@ -13,6 +13,7 @@
 #include <common/debug.h>
 #include <common/runtime_svc.h>
 #include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/simd_ctx.h>
 #include <lib/smccc.h>
 #include <lib/spinlock.h>
 #include <lib/utils.h>
@@ -190,13 +191,13 @@
 	uint64_t rc;
 	sp_context_t *sp_ptr = &sp_ctx;
 
-#if CTX_INCLUDE_FPREGS
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
 	/*
-	 * SP runs to completion, no need to restore FP registers of secure context.
-	 * Save FP registers only for non secure context.
+	 * SP runs to completion, no need to restore FP/SVE registers of secure context.
+	 * Save FP/SVE registers only for non secure context.
 	 */
-	fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
-#endif
+	simd_ctx_save(NON_SECURE, false);
+#endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
 
 	/* Wait until the Secure Partition is idle and set it to busy. */
 	sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
@@ -216,13 +217,13 @@
 	assert(sp_ptr->state == SP_STATE_BUSY);
 	sp_state_set(sp_ptr, SP_STATE_IDLE);
 
-#if CTX_INCLUDE_FPREGS
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
 	/*
-	 * SP runs to completion, no need to save FP registers of secure context.
-	 * Restore only non secure world FP registers.
+	 * SP runs to completion, no need to save FP/SVE registers of secure context.
+	 * Restore only non secure world FP/SVE registers.
 	 */
-	fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
-#endif
+	simd_ctx_restore(NON_SECURE);
+#endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
 
 	return rc;
 }
diff --git a/services/std_svc/spm/spm_mm/spm_mm_setup.c b/services/std_svc/spm/spm_mm/spm_mm_setup.c
index bb9c7a9..de05459 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_setup.c
+++ b/services/std_svc/spm/spm_mm/spm_mm_setup.c
@@ -124,26 +124,13 @@
 
 	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), mair_el1,
 		      mmu_cfg_params[MMU_CFG_MAIR]);
-
-	/* Store the initialised SCTLR_EL1 value in the cpu_context */
-#if (ERRATA_SPECULATIVE_AT)
-	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
-		      CTX_ERRATA_SPEC_AT_TCR_EL1, mmu_cfg_params[MMU_CFG_TCR]);
-#else
-	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), tcr_el1,
-		      mmu_cfg_params[MMU_CFG_TCR]);
-#endif /* ERRATA_SPECULATIVE_AT */
+	write_ctx_tcr_el1_reg_errata(ctx, mmu_cfg_params[MMU_CFG_TCR]);
 
 	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), ttbr0_el1,
 		      mmu_cfg_params[MMU_CFG_TTBR0]);
 
 	/* Setup SCTLR_EL1 */
-#if (ERRATA_SPECULATIVE_AT)
-	sctlr_el1_val = read_ctx_reg(get_errata_speculative_at_ctx(ctx),
-				 CTX_ERRATA_SPEC_AT_SCTLR_EL1);
-#else
-	sctlr_el1_val = read_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1);
-#endif /* ERRATA_SPECULATIVE_AT */
+	sctlr_el1_val = read_ctx_sctlr_el1_reg_errata(ctx);
 
 	sctlr_el1_val |=
 		/*SCTLR_EL1_RES1 |*/
@@ -180,12 +167,7 @@
 	);
 
 	/* Store the initialised SCTLR_EL1 value in the cpu_context */
-#if (ERRATA_SPECULATIVE_AT)
-	write_ctx_reg(get_errata_speculative_at_ctx(ctx),
-		      CTX_ERRATA_SPEC_AT_SCTLR_EL1, sctlr_el1_val);
-#else
-	write_el1_ctx_common(get_el1_sysregs_ctx(ctx), sctlr_el1, sctlr_el1_val);
-#endif /* ERRATA_SPECULATIVE_AT */
+	write_ctx_sctlr_el1_reg_errata(ctx, sctlr_el1_val);
 
 	/*
 	 * Setup other system registers
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index e3d7fbd..0a246f3 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -215,6 +215,14 @@
 	cm_el2_sysregs_context_save(NON_SECURE);
 #else
 	cm_el1_sysregs_context_save(NON_SECURE);
+
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	/*
+	 * The hint bit denoting absence of SVE live state is effectively false
+	 * in this scenario where execution was trapped to EL3 due to FIQ.
+	 */
+	simd_ctx_save(NON_SECURE, false);
+#endif
 #endif
 
 	/* Convey the event to the SPMC through the FFA_INTERRUPT interface. */
@@ -230,7 +238,14 @@
 	/* Mark current core as handling a secure interrupt. */
 	ctx->secure_interrupt_ongoing = true;
 
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	simd_ctx_restore(SECURE);
+#endif
 	rc = spmd_spm_core_sync_entry(ctx);
+
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	simd_ctx_save(SECURE, false);
+#endif
 	if (rc != 0ULL) {
 		ERROR("%s failed (%" PRId64 ") on CPU%u\n", __func__, rc, plat_my_core_pos());
 	}
@@ -241,6 +256,10 @@
 	cm_el2_sysregs_context_restore(NON_SECURE);
 #else
 	cm_el1_sysregs_context_restore(NON_SECURE);
+
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	simd_ctx_restore(NON_SECURE);
+#endif
 #endif
 	cm_set_next_eret_context(NON_SECURE);
 
@@ -678,6 +697,10 @@
 	cm_el2_sysregs_context_save(secure_state_in);
 #else
 	cm_el1_sysregs_context_save(secure_state_in);
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	/* Forward the hint bit denoting the absence of SVE live state. */
+	simd_ctx_save(secure_state_in, (!secure_origin && (is_sve_hint_set(flags) == true)));
+#endif
 #endif
 
 	/* Restore outgoing security state */
@@ -685,6 +708,9 @@
 	cm_el2_sysregs_context_restore(secure_state_out);
 #else
 	cm_el1_sysregs_context_restore(secure_state_out);
+#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	simd_ctx_restore(secure_state_out);
+#endif
 #endif
 	cm_set_next_eret_context(secure_state_out);
 
diff --git a/tools/cot_dt2c/Makefile b/tools/cot_dt2c/Makefile
new file mode 100644
index 0000000..ad8d9f5
--- /dev/null
+++ b/tools/cot_dt2c/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+##* Variables
+SHELL := /usr/bin/env bash
+PYTHON := python
+PYTHONPATH := `pwd`
+
+.PHONY: dist
+dist: clean
+	poetry build
+
+#* Installation
+.PHONY: dev-install
+dev-install:
+	pip3 install mypy
+	pip3 install pytest
+	pip install -r requirements.txt
+	poetry lock -n && poetry export --without-hashes > requirements.txt
+	poetry install -n
+	-poetry run mypy --install-types --non-interactive ./
+
+.PHONY: install
+install: dist
+	pip install mypy
+	pip install pytest
+	pip install -r requirements.txt
+	pip install dist/*.whl
+
+clean-test: ## remove test and coverage artifacts
+	rm -fr .tox/
+	rm -f .coverage
+	rm -fr htmlcov/
+
+clean-pyc: ## remove Python file artifacts
+	find . -name '*.pyc' -exec rm -f {} +
+	find . -name '*.pyo' -exec rm -f {} +
+	find . -name '*~' -exec rm -f {} +
+	find . -name '__pycache__' -exec rm -fr {} +
+	find . | grep -E ".pytest_cache" | xargs rm -rf
+	find . | grep -E ".mypy_cache" | xargs rm -rf
+
+
+clean-build: ## remove build artifacts
+	rm -fr build/
+	rm -fr dist/
+	rm -fr .eggs/
+	find . -name '*.egg-info' -exec rm -fr {} +
+	find . -name '*.egg' -exec rm -f {} +
+
+clean-tmp:
+	rm -rf ./tmp
+
+#* Cleaning
+.PHONY: clean clean-build clean-pyc clean-test
+clean: uninstall clean-build clean-pyc clean-test clean-tmp ## remove all build, test, coverage and Python artifacts
+
+uninstall:
+	pip uninstall -y cot-dt2c
+
+.PHONY: reinstall
+reinstall: clean install
+
+.PHONY: test
+test:
+	PYTHONPATH=$(PYTHONPATH) poetry run pytest -c pyproject.toml tests/
diff --git a/tools/cot_dt2c/cot_dt2c/LICENSE b/tools/cot_dt2c/cot_dt2c/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/LICENSE
@@ -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/tools/cot_dt2c/cot_dt2c/__init__.py b/tools/cot_dt2c/cot_dt2c/__init__.py
new file mode 100644
index 0000000..621c55a
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/__init__.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+# type: ignore[attr-defined]
+
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+
+if sys.version_info >= (3, 8):
+    from importlib import metadata as importlib_metadata
+else:
+    import importlib_metadata
+
+
+def get_version() -> str:
+    try:
+        return importlib_metadata.version(__name__)
+    except importlib_metadata.PackageNotFoundError:  # pragma: no cover
+        return "unknown"
+
+
+version: str = get_version()
diff --git a/tools/cot_dt2c/cot_dt2c/__main__.py b/tools/cot_dt2c/cot_dt2c/__main__.py
new file mode 100644
index 0000000..5aa4a92
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/__main__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+# type: ignore[attr-defined]
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+from cot_dt2c.cli import cli
+if __name__ == "__main__":
+    cli()
diff --git a/tools/cot_dt2c/cot_dt2c/cli.py b/tools/cot_dt2c/cot_dt2c/cli.py
new file mode 100644
index 0000000..d338430
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cli.py
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+from pathlib import Path
+from cot_dt2c.cot_dt2c import generateMain
+from cot_dt2c.cot_dt2c import validateMain
+from cot_dt2c.cot_dt2c import visualizeMain
+from cot_dt2c.dt_validator import dtValidatorMain
+
+import click
+
+@click.group()
+@click.version_option()
+def cli():
+    pass
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+@click.argument("outputfile", type=click.Path(dir_okay=True))
+def convert_to_c(inputfile, outputfile):
+    generateMain(inputfile, outputfile)
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+def validate_cot(inputfile):
+    validateMain(inputfile)
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+def visualize_cot(inputfile):
+    visualizeMain(inputfile)
+
+@cli.command()
+@click.argument("inputfiledir", type=click.Path(dir_okay=True))
+def validate_dt(inputfiledir):
+    dtValidatorMain(inputfiledir)
diff --git a/tools/cot_dt2c/cot_dt2c/cot_dt2c.py b/tools/cot_dt2c/cot_dt2c/cot_dt2c.py
new file mode 100644
index 0000000..4056aac
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cot_dt2c.py
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+from cot_dt2c.cot_parser import COT
+
+def generateMain(input, output=None):
+    cot = COT(input, output)
+    cot.generate_c_file()
+
+def validateMain(input):
+    cot = COT(input)
+    if not cot.validate_nodes():
+        print("not a valid CoT DT file")
+
+def visualizeMain(input):
+    cot = COT(input)
+    cot.tree_visualization()
+
+if __name__=="__main__":
+    if (len(sys.argv) < 2):
+        print("usage: python3 " + sys.argv[0] + " [dtsi file path] [optional output c file path]")
+        exit()
+    if len(sys.argv) == 3:
+        generateMain(sys.argv[1], sys.argv[2])
+    if len(sys.argv) == 2:
+        validateMain(sys.argv[1])
diff --git a/tools/cot_dt2c/cot_dt2c/cot_parser.py b/tools/cot_dt2c/cot_dt2c/cot_parser.py
new file mode 100644
index 0000000..c1d53e2
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cot_parser.py
@@ -0,0 +1,804 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+import re
+from cot_dt2c.pydevicetree.source.parser import ifdef_stack
+from cot_dt2c.pydevicetree.ast import CellArray, LabelReference
+from cot_dt2c.pydevicetree import *
+from pathlib import Path
+
+def extractNumber(s):
+    for i in s:
+        if i.isdigit():
+            return (int)(i)
+
+    return -1
+
+def removeNumber(s):
+    result = ''.join([i for i in s if not i.isdigit()])
+    return result
+
+class COT:
+    def __init__(self, inputfile: str, outputfile=None):
+        with open(inputfile, 'r') as f:
+            contents = f.read()
+        pos = contents.find("cot")
+        if pos == -1:
+            print("not a valid CoT DT file")
+            exit(1)
+
+        contents = contents[pos:]
+
+        try:
+            self.tree = Devicetree.parseStr(contents)
+        except:
+            print("not a valid CoT DT file")
+            exit(1)
+
+        self.output = outputfile
+        self.input = inputfile
+        self.has_root = False
+
+        # edge cases
+        certs = self.get_all_certificates()
+        for c in certs:
+            if self.if_root(c):
+                if not c.get_fields("signing-key"):
+                    c.properties.append(Property("signing-key", CellArray([LabelReference("subject_pk")])))
+
+    def print_cert_info(self, node:Node):
+        img_id = node.get_field("image-id").values[0].replace('"', "")
+        sign_key = self.get_sign_key(node)
+        nv = self.get_nv_ctr(node)
+
+        info = "<b>name:</b> {}<br><b>image-id:</b> {}<br>{}{}{}"\
+                .format(node.name, img_id, "<b>root-certificate</b><br>" if self.if_root(node) else "", \
+                     "<b>signing-key:</b> " + self.extract_label(sign_key) + "<br>" if sign_key else "", \
+                     "<b>nv counter:</b> " + self.extract_label(nv) + "<br>" if nv else "")
+        return info
+
+    def print_data_info(self, node:Node):
+        oid = node.get_field("oid")
+        info = "<b>name:</b> {}<br><b>oid:</b> {}<br>" \
+                .format(node.name, oid)
+
+        return info
+
+    def print_img_info(self, node:Node):
+        hash = self.extract_label(node.get_fields("hash"))
+        img_id = node.get_field("image-id").values[0].replace('"', "")
+        info = "<b>name:</b> {}<br><b>image-id:</b> {}<br><b>hash:</b> {}"\
+                .format(node.name, img_id, hash)
+
+        return info
+
+    def tree_width(self, parent_set, root):
+        ans = 1
+        stack = [root]
+
+        while stack:
+            tmp_stack = []
+            while stack:
+                cur_node = stack.pop()
+                child = parent_set[cur_node]
+                for c in child:
+                    tmp_stack.append(c)
+
+            stack = tmp_stack.copy()
+            ans = max(ans, len(tmp_stack))
+
+        return ans
+
+    def resolve_lay(self, parent_set, lay, name_idx, root, bounds, break_name):
+        child = parent_set[root]
+
+        if len(child) == 0:
+            return
+
+        width = []
+        total_width = 0
+        for c in child:
+            w = self.tree_width(parent_set, c)
+            width.append(w)
+            total_width += w
+
+        allow_width = bounds[1] - bounds[0]
+        interval = allow_width / total_width
+        start = bounds[0]
+        for i, c in enumerate(child):
+            end = start + interval * width[i]
+            new_bounds = [start, end]
+            lay[name_idx[c]][0] = start + (end - start) / 2
+            if end - start < 0.28:
+                break_name.add(c)
+            start = end
+            self.resolve_lay(parent_set, lay, name_idx, c, new_bounds, break_name)
+
+    def tree_visualization(self):
+        import igraph
+        from igraph import Graph, EdgeSeq
+        import collections
+
+        cert = self.get_certificates()
+        pk = self.get_rot_keys()
+        nv = self.get_nv_counters()
+        image = self.get_images()
+
+        certs = cert.children
+        if pk:
+            pks = pk.children
+        else:
+            pks = []
+        nvs = nv.children
+        images = image.children
+
+        root_name = "CoT"
+
+        G = Graph()
+        detail = []
+        lay = []
+        name_idx = {}
+        parent_set = collections.defaultdict(list)
+
+        G.add_vertex(root_name)
+        detail.append("CoT Root")
+        name_idx[root_name] = len(lay)
+        lay.append([0,0])
+
+        G.add_vertex(cert.name)
+        G.add_edge(root_name, cert.name)
+        detail.append("All Certificates")
+        name_idx[cert.name] = len(lay)
+        lay.append([0, 1])
+        parent_set[root_name].append(cert.name)
+
+        if pk:
+            G.add_vertex(pk.name)
+            detail.append("All Public Trusted Key")
+            G.add_edge(root_name, pk.name)
+            name_idx[pk.name] = len(lay)
+            lay.append([-2.0, 1])
+            parent_set[root_name].append(pk.name)
+
+        G.add_vertex(nv.name)
+        detail.append("All NV Counters")
+        G.add_edge(root_name, nv.name)
+        name_idx[nv.name] = len(lay)
+        lay.append([2.0, 1])
+        parent_set[root_name].append(nv.name)
+
+        if pks:
+            for i, p in enumerate(pks):
+                G.add_vertex(p.name)
+                detail.append(self.print_data_info(p))
+                G.add_edge(pk.name, p.name)
+                name_idx[p.name] = len(lay)
+                parent_set[pk.name].append(p.name)
+                lay.append([0, lay[name_idx[pk.name]][1] + 1])
+
+        for c in certs:
+            G.add_vertex(c.name)
+            detail.append(self.print_cert_info(c))
+            name_idx[c.name] = len(lay)
+            if self.if_root(c):
+                G.add_edge(cert.name, c.name)
+                parent_set[cert.name].append(c.name)
+                lay.append([0, 2])
+            else:
+                parent = self.extract_label(c.get_fields("parent"))
+                G.add_edge(parent, c.name)
+                parent_set[parent].append(c.name)
+                lay.append([0, lay[name_idx[parent]][1] + 1])
+
+        for idx, i in enumerate(images):
+            G.add_vertex(i.name)
+            detail.append(self.print_img_info(i))
+            parent = self.extract_label(i.get_fields("parent"))
+            G.add_edge(parent, i.name)
+            parent_set[parent].append(i.name)
+            name_idx[i.name] = len(lay)
+            lay.append([0, lay[name_idx[parent]][1] + 1])
+
+        for i, n in enumerate(nvs):
+            G.add_vertex(n.name)
+            detail.append(self.print_data_info(n))
+            G.add_edge(nv.name, n.name)
+            name_idx[n.name] = len(lay)
+            parent_set[nv.name].append(n.name)
+            lay.append([0, lay[name_idx[nv.name]][1] + 1])
+
+        break_name = set()
+        self.resolve_lay(parent_set, lay, name_idx, root_name, [-3, 3], break_name)
+        #lay = G.layout('rt')
+
+        numVertex = len(G.get_vertex_dataframe())
+        vertices = G.get_vertex_dataframe()
+        v_label = []
+
+        for i in vertices['name']:
+            if i in break_name and len(i) > 10:
+                middle = len(i) // 2
+                v_label.append(i[:middle] + "<br>" + i[middle:])
+            else:
+                v_label.append(i)
+
+        position = {k: lay[k] for k in range(numVertex)}
+        Y = [lay[k][1] for k in range(numVertex)]
+        M = max(Y)
+
+        es = EdgeSeq(G) # sequence of edges
+        E = [e.tuple for e in G.es] # list of edges
+
+        L = len(position)
+        Xn = [position[k][0] for k in range(L)]
+        Yn = [2*M-position[k][1] for k in range(L)]
+        Xe = []
+        Ye = []
+        for edge in E:
+            Xe += [position[edge[0]][0], position[edge[1]][0], None]
+            Ye += [2*M-position[edge[0]][1], 2*M-position[edge[1]][1], None]
+
+        labels = v_label
+
+        import plotly.graph_objects as go
+        fig = go.Figure()
+        fig.add_trace(go.Scatter(x = Xe,
+                        y = Ye,
+                        mode = 'lines',
+                        line = dict(color='rgb(210,210,210)', width=2),
+                        hoverinfo = 'none'
+                        ))
+        fig.add_trace(go.Scatter(x = Xn,
+                        y = Yn,
+                        mode = 'markers',
+                        name = 'detail',
+                        marker = dict(symbol = 'circle-dot',
+                                        size = 50,
+                                        color = 'rgba(135, 206, 250, 0.8)',    #'#DB4551',
+                                        line = dict(color='MediumPurple', width=3)
+                                        ),
+                        text=detail,
+                        hoverinfo='text',
+                        hovertemplate =
+                            '<b>Detail</b><br>'
+                            '%{text}',
+                        opacity=0.8
+                        ))
+
+        def make_annotations(pos, text, font_size=10, font_color='rgb(0,0,0)'):
+            L = len(pos)
+            if len(text) != L:
+                raise ValueError('The lists pos and text must have the same len')
+            annotations = []
+            for k in range(L):
+                annotations.append(
+                    dict(
+                        text = labels[k],
+                        x = pos[k][0], y = 2*M-position[k][1],
+                        xref = 'x1', yref = 'y1',
+                        font = dict(color = font_color, size = font_size),
+                        showarrow = False)
+                )
+            return annotations
+
+        axis = dict(showline=False, # hide axis line, grid, ticklabels and  title
+            zeroline=False,
+            showgrid=False,
+            showticklabels=False,
+            )
+
+        fig.update_layout(title= 'CoT Device Tree',
+                    annotations=make_annotations(position, v_label),
+                    font_size=12,
+                    showlegend=False,
+                    xaxis=axis,
+                    yaxis=axis,
+                    margin=dict(l=40, r=40, b=85, t=100),
+                    hovermode='closest',
+                    plot_bgcolor='rgb(248,248,248)'
+                    )
+
+        fig.show()
+
+        return
+
+    def if_root(self, node:Node) -> bool:
+        for p in node.properties:
+            if p.name == "root-certificate":
+                return True
+        return False
+
+    def get_sign_key(self, node:Node):
+        for p in node.properties:
+            if p.name == "signing-key":
+                return p.values
+
+        return None
+
+    def get_nv_ctr(self, node:Node):
+        for nv in node.properties:
+            if nv.name == "antirollback-counter":
+                return nv.values
+
+        return None
+
+    def extract_label(self, label) -> str:
+        if not label:
+            return label
+        return label[0].label.name
+
+    def get_auth_data(self, node:Node):
+        return node.children
+
+    def format_auth_data_val(self, node:Node, cert:Node):
+        type_desc = node.name
+        if "sp_pkg" in type_desc:
+            ptr = removeNumber(type_desc) + "_buf"
+        else:
+            ptr = type_desc + "_buf"
+        len = "(unsigned int)HASH_DER_LEN"
+        if "pk" in type_desc:
+            len = "(unsigned int)PK_DER_LEN"
+
+        # edge case
+        if not self.if_root(cert) and "key_cert" in cert.name:
+            if "content_pk" in ptr:
+                ptr = "content_pk_buf"
+
+        return type_desc, ptr, len
+
+    def get_node(self, nodes: list[Node], name: str) -> Node:
+        for i in nodes:
+            if i.name == name:
+                return i
+
+    def get_certificates(self) -> Node:
+        children = self.tree.children
+        for i in children:
+            if i.name == "cot":
+                return self.get_node(i.children, "manifests")
+
+    def get_images(self)-> Node:
+        children = self.tree.children
+        for i in children:
+            if i.name == "cot":
+                return self.get_node(i.children, "images")
+
+    def get_nv_counters(self) -> Node:
+        children = self.tree.children
+        return self.get_node(children, "non_volatile_counters")
+
+    def get_rot_keys(self) -> Node:
+        children = self.tree.children
+        return self.get_node(children, "rot_keys")
+
+    def get_all_certificates(self) -> Node:
+        cert = self.get_certificates()
+        return cert.children
+
+    def get_all_images(self) -> Node:
+        image = self.get_images()
+        return image.children
+
+    def get_all_nv_counters(self) -> Node:
+        nv = self.get_nv_counters()
+        return nv.children
+
+    def get_all_pks(self) -> Node:
+        pk = self.get_rot_keys()
+        if not pk:
+            return []
+        return pk.children
+
+    def validate_cert(self, node:Node) -> bool:
+        valid = True
+        if not node.has_field("image-id"):
+            print("{} missing mandatory attribute image-id".format(node.name))
+            valid = False
+
+        if not node.has_field("root-certificate"):
+            if not node.has_field("parent"):
+                print("{} missing mandatory attribute parent".format(node.name))
+                valid = False
+            else:
+                # check if refer to non existing parent
+                certs = self.get_all_certificates()
+                found = False
+                for c in certs:
+                    if c.name == self.extract_label(node.get_fields("parent")):
+                        found = True
+
+                if not found:
+                    print("{} refer to non existing parent".format(node.name))
+                    valid = False
+
+        else:
+            self.has_root = True
+
+        child = node.children
+        if child:
+            for c in child:
+                if not c.has_field("oid"):
+                    print("{} missing mandatory attribute oid".format(c.name))
+                    valid = False
+
+        return valid
+
+    def validate_img(self, node:Node) -> bool:
+        valid = True
+        if not node.has_field("image-id"):
+            print("{} missing mandatory attribute image-id".format(node.name))
+            valid = False
+
+        if not node.has_field("parent"):
+            print("{} missing mandatory attribute parent".format(node.name))
+            valid = False
+
+        if not node.has_field("hash"):
+            print("{} missing mandatory attribute hash".format(node.name))
+            valid = False
+
+        # check if refer to non existing parent
+        certs = self.get_all_certificates()
+        found = False
+        for c in certs:
+            if c.name == self.extract_label(node.get_fields("parent")):
+                found = True
+
+        if not found:
+            print("{} refer to non existing parent".format(node.name))
+            valid = False
+
+        return valid
+
+    def validate_nodes(self) -> bool:
+        valid = True
+
+        if ifdef_stack:
+            print("invalid ifdef macro")
+            valid = False
+
+        certs = self.get_all_certificates()
+        images = self.get_all_images()
+
+        for n in certs:
+            node_valid = self.validate_cert(n)
+            valid = valid and node_valid
+
+        for i in images:
+            node_valid = self.validate_img(i)
+            valid = valid and node_valid
+
+        if not self.has_root:
+            print("missing root certificate")
+
+        return valid
+
+    def extract_licence(self, f):
+        licence = []
+
+        licencereg = re.compile(r'/\*')
+        licenceendReg = re.compile(r'\*/')
+
+        licencePre = False
+
+        for line in f:
+            match = licencereg.search(line)
+            if match != None:
+                licence.append(line)
+                licencePre = True
+                continue
+
+            match = licenceendReg.search(line)
+            if match != None:
+                licence.append(line)
+                licencePre = False
+                return licence
+
+            if licencePre:
+                licence.append(line)
+            else:
+                return licence
+
+        return licence
+
+    def licence_to_c(self, licence, f):
+        if len(licence) != 0:
+            for i in licence:
+                f.write(i)
+
+        f.write("\n")
+        return
+
+    def extract_include(self, f):
+        include = []
+
+        for line in f:
+            if "cot" in line:
+                return include
+
+            if line != "" and "common" not in line and line != "\n":
+                include.append(line)
+
+        return include
+
+    def include_to_c(self, include, f):
+        f.write("#include <stddef.h>\n")
+        f.write("#include <mbedtls/version.h>\n")
+        f.write("#include <common/tbbr/cot_def.h>\n")
+        f.write("#include <drivers/auth/auth_mod.h>\n")
+        f.write("\n")
+        for i in include:
+            f.write(i)
+        f.write("\n")
+        f.write("#include <platform_def.h>\n\n")
+        return
+
+    def generate_header(self, input, output):
+        licence = self.extract_licence(input)
+        include = self.extract_include(input)
+        self.licence_to_c(licence, output)
+        self.include_to_c(include, output)
+
+    def all_cert_to_c(self, f):
+        certs = self.get_all_certificates()
+        for c in certs:
+            self.cert_to_c(c, f)
+
+        f.write("\n")
+
+    def cert_to_c(self, node: Node, f):
+        ifdef = node.get_fields("ifdef")
+        if ifdef:
+            for i in ifdef:
+                f.write("{}\n".format(i))
+
+        f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
+        f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+        f.write("\t.img_type = IMG_CERT,\n")
+
+        if not self.if_root(node):
+            f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+        else:
+            f.write("\t.parent = NULL,\n")
+
+        sign = self.get_sign_key(node)
+        nv_ctr = self.get_nv_ctr(node)
+
+        if sign or nv_ctr:
+            f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
+
+        if sign:
+            f.write("\t\t[0] = {\n")
+            f.write("\t\t\t.type = AUTH_METHOD_SIG,\n")
+            f.write("\t\t\t.param.sig = {\n")
+
+            f.write("\t\t\t\t.pk = &{},\n".format(self.extract_label(sign)))
+            f.write("\t\t\t\t.sig = &sig,\n")
+            f.write("\t\t\t\t.alg = &sig_alg,\n")
+            f.write("\t\t\t\t.data = &raw_data\n")
+            f.write("\t\t\t}\n")
+            f.write("\t\t}}{}\n".format("," if nv_ctr else ""))
+
+        if nv_ctr:
+            f.write("\t\t[1] = {\n")
+            f.write("\t\t\t.type = AUTH_METHOD_NV_CTR,\n")
+            f.write("\t\t\t.param.nv_ctr = {\n")
+
+            f.write("\t\t\t\t.cert_nv_ctr = &{},\n".format(self.extract_label(nv_ctr)))
+            f.write("\t\t\t\t.plat_nv_ctr = &{}\n".format(self.extract_label(nv_ctr)))
+
+            f.write("\t\t\t}\n")
+            f.write("\t\t}\n")
+
+        f.write("\t},\n")
+
+        auth_data = self.get_auth_data(node)
+        if auth_data:
+            f.write("\t.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {\n")
+
+            for i, d in enumerate(auth_data):
+                type_desc, ptr, data_len = self.format_auth_data_val(d, node)
+
+                f.write("\t\t[{}] = {{\n".format(i))
+                f.write("\t\t\t.type_desc = &{},\n".format(type_desc))
+                f.write("\t\t\t.data = {\n")
+
+                n = extractNumber(type_desc)
+                if "pkg" not in type_desc or n == -1:
+                    f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
+                else:
+                    f.write("\t\t\t\t.ptr = (void *){}[{}],\n".format(ptr, n-1))
+
+                f.write("\t\t\t\t.len = {}\n".format(data_len))
+                f.write("\t\t\t}\n")
+
+                f.write("\t\t}}{}\n".format("," if i != len(auth_data) - 1 else ""))
+
+            f.write("\t}\n")
+
+        f.write("};\n\n")
+
+        if ifdef:
+            for i in ifdef:
+                f.write("#endif\n")
+            f.write("\n")
+
+        return
+
+
+    def img_to_c(self, node:Node, f):
+        ifdef = node.get_fields("ifdef")
+        if ifdef:
+            for i in ifdef:
+                f.write("{}\n".format(i))
+
+        f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
+        f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+        f.write("\t.img_type = IMG_RAW,\n")
+        f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+        f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
+
+        f.write("\t\t[0] = {\n")
+        f.write("\t\t\t.type = AUTH_METHOD_HASH,\n")
+        f.write("\t\t\t.param.hash = {\n")
+        f.write("\t\t\t\t.data = &raw_data,\n")
+        f.write("\t\t\t\t.hash = &{}\n".format(node.get_field("hash").label.name))
+        f.write("\t\t\t}\n")
+
+        f.write("\t\t}\n")
+        f.write("\t}\n")
+        f.write("};\n\n")
+
+        if ifdef:
+            for i in ifdef:
+                f.write("#endif\n")
+            f.write("\n")
+
+        return
+
+    def all_img_to_c(self, f):
+        images = self.get_all_images()
+        for i in images:
+            self.img_to_c(i, f)
+
+        f.write("\n")
+
+    def nv_to_c(self, f):
+        nv_ctr = self.get_all_nv_counters()
+
+        for nv in nv_ctr:
+            f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(nv.name, nv.get_field("oid")))
+
+        f.write("\n")
+
+        return
+
+    def pk_to_c(self, f):
+        pks = self.get_all_pks()
+
+        for p in pks:
+            f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(p.name, p.get_field("oid")))
+
+        f.write("\n")
+        return
+
+    def buf_to_c(self, f):
+        certs = self.get_all_certificates()
+
+        buffers = {}
+
+        for c in certs:
+            auth_data = self.get_auth_data(c)
+            for a in auth_data:
+                type_desc, ptr, data_len = self.format_auth_data_val(a, c)
+                if ptr not in buffers:
+                    buffers[ptr] = c.get_fields("ifdef")
+
+        for key, values in buffers.items():
+            if values:
+                for i in values:
+                    f.write("{}\n".format(i))
+
+            if "sp_pkg_hash_buf" in key:
+                f.write("static unsigned char {}[MAX_SP_IDS][HASH_DER_LEN];\n".format(key))
+            elif "pk" in key:
+                f.write("static unsigned char {}[PK_DER_LEN];\n".format(key))
+            else:
+                f.write("static unsigned char {}[HASH_DER_LEN];\n".format(key))
+
+            if values:
+                for i in values:
+                    f.write("#endif\n")
+
+        f.write("\n")
+
+    def param_to_c(self, f):
+        f.write("static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, 0);\n")
+        f.write("static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG, 0);\n")
+        f.write("static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG_ALG, 0);\n")
+        f.write("static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_RAW_DATA, 0);\n")
+        f.write("\n")
+
+        certs = self.get_all_certificates()
+        for c in certs:
+            ifdef = c.get_fields("ifdef")
+            if ifdef:
+                for i in ifdef:
+                    f.write("{}\n".format(i))
+
+            hash = c.children
+            for h in hash:
+                name = h.name
+                oid = h.get_field("oid")
+
+                if "pk" in name and "pkg" not in name:
+                    f.write("static auth_param_type_desc_t {} = "\
+                        "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(name, oid))
+                elif "hash" in name:
+                    f.write("static auth_param_type_desc_t {} = "\
+                            "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_HASH, {});\n".format(name, oid))
+                elif "ctr" in name:
+                    f.write("static auth_param_type_desc_t {} = "\
+                            "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(name, oid))
+
+            if ifdef:
+                for i in ifdef:
+                    f.write("#endif\n")
+
+        f.write("\n")
+
+    def cot_to_c(self, f):
+        certs = self.get_all_certificates()
+        images = self.get_all_images()
+
+        f.write("static const auth_img_desc_t * const cot_desc[] = {\n")
+
+        for i, c in enumerate(certs):
+            ifdef = c.get_fields("ifdef")
+            if ifdef:
+                for i in ifdef:
+                    f.write("{}\n".format(i))
+
+            f.write("\t[{}]	=	&{}{}\n".format(c.get_field("image-id").values[0], c.name, ","))
+
+            if ifdef:
+                for i in ifdef:
+                    f.write("#endif\n")
+
+        for i, c in enumerate(images):
+            ifdef = c.get_fields("ifdef")
+            if ifdef:
+                for i in ifdef:
+                    f.write("{}\n".format(i))
+
+            f.write("\t[{}]	=	&{}{}\n".format(c.get_field("image-id").values[0], c.name, "," if i != len(images) - 1 else ""))
+
+            if ifdef:
+                for i in ifdef:
+                    f.write("#endif\n")
+
+        f.write("};\n\n")
+        f.write("REGISTER_COT(cot_desc);\n")
+        return
+
+    def generate_c_file(self):
+        filename = Path(self.output)
+        filename.parent.mkdir(exist_ok=True, parents=True)
+        output = open(self.output, 'w+')
+        input = open(self.input, "r")
+
+        self.generate_header(input, output)
+        self.buf_to_c(output)
+        self.param_to_c(output)
+        self.nv_to_c(output)
+        self.pk_to_c(output)
+        self.all_cert_to_c(output)
+        self.all_img_to_c(output)
+        self.cot_to_c(output)
+
+        return
diff --git a/tools/cot_dt2c/cot_dt2c/dt_validator.py b/tools/cot_dt2c/cot_dt2c/dt_validator.py
new file mode 100644
index 0000000..65e8ca2
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/dt_validator.py
@@ -0,0 +1,130 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+from os import path, walk, mkdir
+import subprocess
+from cot_dt2c.pydevicetree import *
+
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKCYAN = '\033[96m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+
+class DTTree:
+    def __init__(self, input):
+        self.input = input
+        self.test_dir = "./tmp"
+        self.logging_file = self.test_dir + "/result.log"
+
+    def dtValidate(self):
+        subprocess.run(["rm", "-rf", self.test_dir])
+
+        if not path.exists(self.test_dir):
+            mkdir(self.test_dir)
+
+        if path.isfile(self.input):
+            self.dtValidateFile(self.input, printInfo=True)
+            return
+
+        if path.isdir(self.input):
+            self.dtValidateFiles()
+            return
+
+    def dtValidateFile(self, input, printInfo=False):
+        valid, tree = self.dtParseFile(input, printInfo)
+
+        if not valid:
+            return False
+
+        if input.rfind("/") != -1:
+            filename = self.test_dir + input[input.rfind("/"):]
+        else:
+            filename = self.test_dir + "/" + input
+
+        f = open(filename, "w+")
+        if "/dts-v1/;" not in str(tree):
+            f.write("/dts-v1/;\n\n")
+        f.write(str(tree))
+        f.close()
+
+        if str(tree) == "":
+            return valid
+
+        return valid
+
+    def dtParseFile(self, input, printInfo=False):
+        with open(input, 'r') as f:
+            contents = f.read()
+
+        pos = contents.find("/ {")
+        if pos != -1:
+            contents = contents[pos:]
+
+        try:
+            tree = Devicetree.parseStr(contents)
+            if printInfo:
+                print(bcolors.OKGREEN + "{} parse tree successfully".format(input) + bcolors.ENDC)
+        except Exception as e:
+            if printInfo:
+                print(bcolors.FAIL + "{} parse tree failed:\t{}".format(input, str(e)) + bcolors.ENDC)
+            else:
+                f = open(self.logging_file, "a")
+                f.write("=====================================================================================\n")
+                f.write("{} result:\n".format(input))
+                f.write("{} INVALID:\t{}\n".format(input, str(e)))
+                f.close()
+            return False, None
+
+        return True, tree
+
+    def dtValidateFiles(self):
+        f = []
+        for (dirpath, dirnames, filenames) in walk(self.input):
+            f.extend(filenames)
+
+        allFile = len(f)
+        dtsiFile = 0
+        validFile = 0
+        invalidFile = 0
+
+        for i in f:
+            if (".dtsi" in i or ".dts" in i) and "cot" not in i and "fw-config" not in i:
+                dtsiFile += 1
+                valid = True
+
+                if self.input[-1] == "/":
+                    valid = self.dtValidateFile(self.input + i)
+                else:
+                    valid = self.dtValidateFile(self.input + "/" + i)
+
+                if valid:
+                    validFile += 1
+                else:
+                    invalidFile += 1
+
+        print("=====================================================")
+        print("Total File: " + str(allFile))
+        print("Total DT File: " + str(dtsiFile))
+        print("Total Valid File: " + str(validFile))
+        print("Total Invalid File: " + str(invalidFile))
+
+def dtValidatorMain(input):
+    dt = DTTree(input)
+    dt.dtValidate()
+
+if __name__=="__main__":
+    if (len(sys.argv) < 2):
+        print("usage: python3 " + sys.argv[0] + " [dtsi file path] or [dtsi folder path]")
+        exit()
+    if len(sys.argv) == 2:
+        dtValidatorMain(sys.argv[1])
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
new file mode 100644
index 0000000..49595a7
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.ast import Devicetree, Node, Property, Directive, CellArray, LabelReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
new file mode 100644
index 0000000..f30d897
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.ast.directive import Directive
+from cot_dt2c.pydevicetree.ast.node import Node, NodeReference, Devicetree
+from cot_dt2c.pydevicetree.ast.property import PropertyValues, Bytestring, CellArray, StringList, Property, \
+                                      RegArray, OneString
+from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
new file mode 100644
index 0000000..fdd6f0e
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import Any
+
+from cot_dt2c.pydevicetree.ast.helpers import formatLevel, wrapStrings
+
+class Directive:
+    """Represents a Devicetree directive
+
+    Directives in Devicetree source are statements of the form
+
+        /directive-name/ [option1 [option2 [...]]];
+
+    Common directive examples include:
+
+        /dts-v1/;
+        /include/ "overlay.dtsi";
+        /delete-node/ &uart0;
+        /delete-property/ status;
+
+    Their semantic meaning depends on the directive name, their location in the Devicetree,
+    and their options.
+    """
+    def __init__(self, directive: str, option: Any = None):
+        """Create a directive object"""
+        self.directive = directive
+        self.option = option
+
+    def __repr__(self) -> str:
+        return "<Directive %s>" % self.directive
+
+    def __str__(self) -> str:
+        return self.to_dts()
+
+    def to_dts(self, level: int = 0) -> str:
+        """Format the Directive in Devicetree Source format"""
+        if isinstance(self.option, list):
+            return formatLevel(level, "%s %s;\n" % (self.directive,
+                                                    wrapStrings(self.option)))
+        if isinstance(self.option, str):
+            if self.directive == "/include/":
+                return formatLevel(level, "%s \"%s\"\n" % (self.directive, self.option))
+            return formatLevel(level, "%s \"%s\";\n" % (self.directive, self.option))
+        return formatLevel(level, "%s;\n" % self.directive)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
new file mode 100644
index 0000000..30c54dc
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import List, Any
+
+from cot_dt2c.pydevicetree.ast.reference import Reference
+
+def formatLevel(level: int, s: str) -> str:
+    """Helper to indent a string with a number of tabs"""
+    return "\t" * level + s
+
+def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
+    """Helper to wrap strings in quotes where appropriate"""
+    wrapped = []
+    for v in values:
+        if isinstance(v, Reference):
+            wrapped.append(v.to_dts())
+        elif isinstance(v, str):
+            wrapped.append("\"%s\"" % v)
+        elif isinstance(v, int):
+            if formatHex:
+                wrapped.append("0x%x" % v)
+            else:
+                wrapped.append(str(v))
+        else:
+            wrapped.append(str(v))
+    return wrapped
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
new file mode 100644
index 0000000..d203af8
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
@@ -0,0 +1,514 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+import re
+import os
+from typing import List, Union, Optional, Iterable, Callable, Any, cast, Pattern
+
+from cot_dt2c.pydevicetree.ast.helpers import formatLevel
+from cot_dt2c.pydevicetree.ast.property import Property, PropertyValues, RegArray, RangeArray
+from cot_dt2c.pydevicetree.ast.directive import Directive
+from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
+
+# Type signature for elements passed to Devicetree constructor
+ElementList = Iterable[Union['Node', Property, Directive]]
+
+# Callback type signatures for Devicetree.match() and Devicetree.chosen()
+MatchFunc = Callable[['Node'], bool]
+MatchCallback = Optional[Callable[['Node'], None]]
+ChosenCallback = Optional[Callable[[PropertyValues], None]]
+
+class Node:
+    """Represents a Devicetree Node
+
+    A Devicetree Node generally takes the form
+
+        [label:] node-name@unit-address {
+            [directives]
+            [properties]
+            [child nodes]
+        };
+
+    The structure formed by creating trees of Nodes is the bulk of any Devicetree. As the naming
+    system implies, then, each node roughly corresponds to some conceptual device, subsystem of
+    devices, bus, etc.
+
+    Devices can be referenced by label or by path, and are generally uniquely identified by a
+    collection of string identifiers assigned to the "compatible" property.
+
+    For instance, a UART device might look like
+
+        uart0: uart@10013000 {
+            compatible = "sifive,uart0";
+            reg = <0x10013000 0x1000>;
+            reg-names = "control";
+            interrupt-parent = <&plic>;
+            interrupts = <3>;
+            clocks = <&busclk>;
+            status = "okay";
+        };
+
+    This node can be identified in the following ways:
+
+        - By label: uart0
+        - By path: /path/to/uart@10013000
+        - By name: uart@10013000 (for example when referenced in a /delete-node/ directive)
+    """
+    # pylint: disable=too-many-arguments
+    def __init__(self, name: str, label: Optional[str], address: Optional[int],
+                 properties: List[Property], directives: List[Directive],
+                 children: List['Node']):
+        """Initializes a Devicetree Node
+
+        Also evaluates the /delete-node/ and /delete-property/ directives found in the node
+        and deletes the respective nodes and properties.
+        """
+        self.name = name
+        self.parent = None # type: Optional['Node']
+
+        self.label = label
+        self.address = address
+        self.properties = properties
+        self.directives = directives
+        self.children = children
+        self.ifdef = []
+
+        for d in self.directives:
+            if d.directive == "/delete-node/":
+                if isinstance(d.option, LabelReference):
+                    node = self.get_by_reference(d.option)
+                elif isinstance(d.option, str):
+                    node = self.__get_child_by_handle(d.option)
+                if node:
+                    self.remove_child(node)
+            elif d.directive == "/delete-property/":
+                # pylint: disable=cell-var-from-loop
+                properties = list(filter(lambda p: p.name == d.option, self.properties))
+                if properties:
+                    del self.properties[self.properties.index(properties[0])]
+
+    def __repr__(self) -> str:
+        if self.address:
+            return "<Node %s@%x>" % (self.name, self.address)
+        return "<Node %s>" % self.name
+
+    def __str__(self) -> str:
+        return self.to_dts()
+
+    def __eq__(self, other) -> bool:
+        return self.name == other.name and self.address == other.address
+
+    def __hash__(self):
+        return hash((self.name, self.address))
+
+    @staticmethod
+    def from_dts(source: str) -> 'Node':
+        """Create a node from Devicetree Source"""
+        # pylint: disable=import-outside-toplevel,cyclic-import
+        from pydevicetree.source import parseNode
+        return parseNode(source)
+
+    def add_child(self, node: 'Node', merge: bool = True):
+        """Add a child node and merge it into the tree"""
+        node.parent = self
+        self.children.append(node)
+        if merge:
+            self.merge_tree()
+
+    def to_dts(self, level: int = 0) -> str:
+        """Format the subtree starting at the node as Devicetree Source"""
+        out = ""
+        if isinstance(self.address, int) and self.label:
+            out += formatLevel(level,
+                               "%s: %s@%x {\n" % (self.label, self.name, self.address))
+        elif isinstance(self.address, int):
+            out += formatLevel(level, "%s@%x {\n" % (self.name, self.address))
+        elif self.label:
+            out += formatLevel(level, "%s: %s {\n" % (self.label, self.name))
+        elif self.name != "":
+            out += formatLevel(level, "%s {\n" % self.name)
+
+        for d in self.directives:
+            out += d.to_dts(level + 1)
+        for p in self.properties:
+            out += p.to_dts(level + 1)
+        for c in self.children:
+            out += c.to_dts(level + 1)
+
+        if self.name != "":
+            out += formatLevel(level, "};\n")
+
+        return out
+
+    def merge_tree(self):
+        """Recursively merge child nodes into a single tree
+
+        Parsed Devicetrees can describe the same tree multiple times, adding nodes and properties
+        each time. After parsing, this method is called to recursively merge the tree.
+        """
+        partitioned_children = []
+        for n in self.children:
+            partitioned_children.append([e for e in self.children if e == n])
+
+        new_children = []
+        for part in partitioned_children:
+            first = part[0]
+            rest = part[1:]
+            if first not in new_children:
+                for n in rest:
+                    first.merge(n)
+                new_children.append(first)
+
+        self.children = new_children
+
+        for n in self.children:
+            n.parent = self
+            n.merge_tree()
+
+    def merge(self, other: 'Node'):
+        """Merge the contents of a node into this node.
+
+        Used by Node.merge_trees()
+        """
+        if not self.label and other.label:
+            self.label = other.label
+        self.properties += other.properties
+        self.directives += other.directives
+        self.children += other.children
+        self.ifdef += other.ifdef
+
+    def get_path(self, includeAddress: bool = True) -> str:
+        """Get the path of a node (ex. /cpus/cpu@0)"""
+        if self.name == "/":
+            return ""
+        if self.parent is None:
+            return "/" + self.name
+        if isinstance(self.address, int) and includeAddress:
+            return self.parent.get_path() + "/" + self.name + "@" + ("%x" % self.address)
+        return self.parent.get_path() + "/" + self.name
+
+    def get_by_reference(self, reference: Reference) -> Optional['Node']:
+        """Get a node from the subtree by reference (ex. &label, &{/path/to/node})"""
+        if isinstance(reference, LabelReference):
+            return self.get_by_label(reference.label)
+        if isinstance(reference, PathReference):
+            return self.get_by_path(reference.path)
+
+        return None
+
+    def get_by_label(self, label: Union[Label, str]) -> Optional['Node']:
+        """Get a node from the subtree by label"""
+        matching_nodes = list(filter(lambda n: n.label == label, self.child_nodes()))
+        if len(matching_nodes) != 0:
+            return matching_nodes[0]
+        return None
+
+    def __get_child_by_handle(self, handle: str) -> Optional['Node']:
+        """Get a child node by name or name and unit address"""
+        if '@' in handle:
+            name, addr_s = handle.split('@')
+            address = int(addr_s, base=16)
+            nodes = list(filter(lambda n: n.name == name and n.address == address, self.children))
+        else:
+            name = handle
+            nodes = list(filter(lambda n: n.name == name, self.children))
+
+        if not nodes:
+            return None
+        if len(nodes) > 1:
+            raise Exception("Handle %s is ambiguous!" % handle)
+        return nodes[0]
+
+    def get_by_path(self, path: Union[Path, str]) -> Optional['Node']:
+        """Get a node in the subtree by path"""
+        matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=True), \
+                                     self.child_nodes()))
+        if len(matching_nodes) != 0:
+            return matching_nodes[0]
+
+        matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=False), \
+                                     self.child_nodes()))
+        if len(matching_nodes) != 0:
+            return matching_nodes[0]
+        return None
+
+    def filter(self, matchFunc: MatchFunc, cbFunc: MatchCallback = None) -> List['Node']:
+        """Filter all child nodes by matchFunc
+
+        If cbFunc is provided, this method will iterate over the Nodes selected by matchFunc
+        and call cbFunc on each Node
+
+        Returns a list of all matching Nodes
+        """
+        nodes = list(filter(matchFunc, self.child_nodes()))
+
+        if cbFunc is not None:
+            for n in nodes:
+                cbFunc(n)
+
+        return nodes
+
+    def match(self, compatible: Pattern, func: MatchCallback = None) -> List['Node']:
+        """Get a node from the subtree by compatible string
+
+        Accepts a regular expression to match one of the strings in the compatible property.
+        """
+        regex = re.compile(compatible)
+
+        def match_compat(node: Node) -> bool:
+            compatibles = node.get_fields("compatible")
+            if compatibles is not None:
+                return any(regex.match(c) for c in compatibles)
+            return False
+
+        return self.filter(match_compat, func)
+
+    def child_nodes(self) -> Iterable['Node']:
+        """Get an iterable over all the nodes in the subtree"""
+        for n in self.children:
+            yield n
+            for m in n.child_nodes():
+                yield m
+
+    def remove_child(self, node):
+        """Remove a child node"""
+        del self.children[self.children.index(node)]
+
+    def get_fields(self, field_name: str) -> Optional[PropertyValues]:
+        """Get all the values of a property"""
+        for p in self.properties:
+            if p.name == field_name:
+                return p.values
+        return None
+
+    def has_field(self, field_name: str) -> bool:
+        for p in self.properties:
+            if p.name == field_name:
+                return True
+        return False
+
+    def get_field(self, field_name: str) -> Any:
+        """Get the first value of a property"""
+        fields = self.get_fields(field_name)
+        if fields is not None:
+            if len(cast(PropertyValues, fields)) != 0:
+                return fields[0]
+        return None
+
+    def get_reg(self) -> Optional[RegArray]:
+        """If the node defines a `reg` property, return a RegArray for easier querying"""
+        reg = self.get_fields("reg")
+        reg_names = self.get_fields("reg-names")
+        if reg is not None:
+            if reg_names is not None:
+                return RegArray(reg.values, self.address_cells(), self.size_cells(),
+                                reg_names.values)
+            return RegArray(reg.values, self.address_cells(), self.size_cells())
+        return None
+
+    def get_ranges(self) -> Optional[RangeArray]:
+        """If the node defines a `ranges` property, return a RangeArray for easier querying"""
+        ranges = self.get_fields("ranges")
+        child_address_cells = self.get_field("#address-cells")
+        parent_address_cells = self.address_cells()
+        size_cells = self.get_field("#size-cells")
+        if ranges is not None:
+            return RangeArray(ranges.values, child_address_cells, parent_address_cells, size_cells)
+        return None
+
+    def address_cells(self):
+        """Get the number of address cells
+
+        The #address-cells property is defined by the parent of a node and describes how addresses
+        are encoded in cell arrays. If no property is defined, the default value is 2.
+        """
+        if self.parent is not None:
+            cells = self.parent.get_field("#address-cells")
+            if cells is not None:
+                return cells
+            return 2
+        return 2
+
+    def size_cells(self):
+        """Get the number of size cells
+
+        The #size-cells property is defined by the parent of a node and describes how addresses
+        are encoded in cell arrays. If no property is defined, the default value is 1.
+        """
+        if self.parent is not None:
+            cells = self.parent.get_field("#size-cells")
+            if cells is not None:
+                return cells
+            return 1
+        return 1
+
+class NodeReference(Node):
+    """A NodeReference is used to extend the definition of a previously-defined Node
+
+    NodeReferences are commonly used by Devicetree "overlays" to extend the properties of a node
+    or add child devices, such as to a bus like I2C.
+    """
+    def __init__(self, reference: Reference, properties: List[Property],
+                 directives: List[Directive], children: List[Node]):
+        """Instantiate a Node identified by reference to another node"""
+        self.reference = reference
+        Node.__init__(self, label=None, name="", address=None, properties=properties,
+                      directives=directives, children=children)
+
+    def __repr__(self) -> str:
+        return "<NodeReference %s>" % self.reference.to_dts()
+
+    def resolve_reference(self, tree: 'Devicetree') -> Node:
+        """Given the full tree, get the node being referenced"""
+        node = tree.get_by_reference(self.reference)
+        if node is None:
+            raise Exception("Node reference %s cannot be resolved" % self.reference.to_dts())
+        return cast(Node, node)
+
+    def to_dts(self, level: int = 0) -> str:
+        out = formatLevel(level, self.reference.to_dts() + " {\n")
+
+        for d in self.directives:
+            out += d.to_dts(level + 1)
+        for p in self.properties:
+            out += p.to_dts(level + 1)
+        for c in self.children:
+            out += c.to_dts(level + 1)
+
+        out += formatLevel(level, "};\n")
+
+        return out
+
+
+class Devicetree(Node):
+    """A Devicetree object describes the full Devicetree tree
+
+    This class encapsulates both the tree itself (starting at the root node /) and any Directives
+    or nodes which exist at the top level of the Devicetree Source files.
+
+    Devicetree Source files can be parsed by calling Devicetree.parseFile().
+    """
+    def __init__(self, elements: ElementList):
+        """Instantiate a Devicetree with the list of parsed elements
+
+        Resolves all reference nodes and merges the tree to combine all identical nodes.
+        """
+        properties = [] # type: List[Property]
+        directives = [] # type: List[Directive]
+        children = [] # type: List[Node]
+
+        for e in elements:
+            if isinstance(e, Node):
+                children.append(cast(Node, e))
+            elif isinstance(e, Property):
+                properties.append(cast(Property, e))
+            elif isinstance(e, Directive):
+                directives.append(cast(Directive, e))
+
+        Node.__init__(self, label=None, name="", address=None,
+                      properties=properties, directives=directives, children=children)
+
+        for node in self.children:
+            node.parent = self
+
+        reference_nodes = self.filter(lambda n: isinstance(n, NodeReference))
+        for refnode in reference_nodes:
+            refnode = cast(NodeReference, refnode)
+
+            node = refnode.resolve_reference(self)
+
+            if refnode.parent:
+                cast(Node, refnode.parent).remove_child(refnode)
+
+            node.properties += refnode.properties
+            node.directives += refnode.directives
+            node.children += refnode.children
+
+        self.merge_tree()
+
+    def __repr__(self) -> str:
+        name = self.root().get_field("compatible")
+        return "<Devicetree %s>" % name
+
+    def to_dts(self, level: int = 0) -> str:
+        """Convert the tree back to Devicetree Source"""
+        out = ""
+
+        for d in self.directives:
+            out += d.to_dts()
+        for p in self.properties:
+            out += p.to_dts()
+        for c in self.children:
+            out += c.to_dts()
+
+        return out
+
+    def get_by_path(self, path: Union[Path, str]) -> Optional[Node]:
+        """Get a node in the tree by path (ex. /cpus/cpu@0)"""
+
+        # Find and replace all aliases in the path
+        aliases = self.aliases()
+        if aliases:
+            for prop in aliases.properties:
+                if prop.name in path and len(prop.values) > 0:
+                    path = path.replace(prop.name, prop.values[0])
+
+        return self.root().get_by_path(path)
+
+    @staticmethod
+    # pylint: disable=arguments-differ
+    def from_dts(dts: str) -> 'Devicetree':
+        """Parse a string and return a Devicetree object"""
+        # pylint: disable=import-outside-toplevel,cyclic-import
+        from pydevicetree.source import parseTree
+        return parseTree(dts)
+
+    @staticmethod
+    def parseFile(filename: str, followIncludes: bool = False) -> 'Devicetree':
+        """Parse a file and return a Devicetree object"""
+        # pylint: disable=import-outside-toplevel,cyclic-import
+        from cot_dt2c.pydevicetree.source.parser import parseTree
+        with open(filename, 'r') as f:
+            contents = f.read()
+        dirname = os.path.dirname(filename)
+        if dirname != "":
+            dirname += "/"
+        return parseTree(contents, dirname, followIncludes)
+
+    @staticmethod
+    def parseStr(input: str, followIncludes: bool = False) -> 'Devicetree':
+        from cot_dt2c.pydevicetree.source.parser import parseTree
+        return parseTree(input, "", followIncludes)
+
+    def all_nodes(self) -> Iterable[Node]:
+        """Get an iterable over all nodes in the tree"""
+        return self.child_nodes()
+
+    def root(self) -> Node:
+        """Get the root node of the tree"""
+        for n in self.all_nodes():
+            if n.name == "/":
+                return n
+        raise Exception("Devicetree has no root node!")
+
+    def aliases(self) -> Optional[Node]:
+        """Get the aliases node of the tree if it exists"""
+        for n in self.all_nodes():
+            if n.name == "aliases":
+                return n
+        return None
+
+    def chosen(self, property_name: str, func: ChosenCallback = None) -> Optional[PropertyValues]:
+        """Get the values associated with one of the properties in the chosen node"""
+        def match_chosen(node: Node) -> bool:
+            return node.name == "chosen"
+
+        for n in filter(match_chosen, self.all_nodes()):
+            for p in n.properties:
+                if p.name == property_name:
+                    if func is not None:
+                        func(p.values)
+                    return p.values
+
+        return None
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
new file mode 100644
index 0000000..d5fb687
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import List, Any, cast, Tuple, Optional, Iterable
+from itertools import zip_longest
+
+from cot_dt2c.pydevicetree.ast.helpers import wrapStrings, formatLevel
+
+class PropertyValues:
+    """PropertyValues is the parent class of all values which can be assigned to a Property
+
+    Child classes include
+
+        Bytestring
+        CellArray
+        StringList
+    """
+    def __init__(self, values: List[Any]):
+        """Create a PropertyValue"""
+        self.values = values
+
+    def __repr__(self) -> str:
+        return "<PropertyValues " + self.values.__repr__() + ">"
+
+    def __str__(self) -> str:
+        return self.to_dts()
+
+    def __iter__(self):
+        return iter(self.values)
+
+    def __len__(self) -> int:
+        return len(self.values)
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the values in Devicetree Source format"""
+        return ", ".join(wrapStrings(self.values, formatHex))
+
+    def __getitem__(self, key) -> Any:
+        return self.values[key]
+
+    def __eq__(self, other) -> bool:
+        if isinstance(other, PropertyValues):
+            return self.values == other.values
+        return self.values == other
+
+class Bytestring(PropertyValues):
+    """A Bytestring is a sequence of bytes
+
+    In Devicetree, Bytestrings are represented as a sequence of two-digit hexadecimal integers,
+    optionally space-separated, enclosed by square brackets:
+
+        [de ad be eef]
+    """
+    def __init__(self, bytelist: List[int]):
+        """Create a Bytestring object"""
+        PropertyValues.__init__(self, cast(List[Any], bytearray(bytelist)))
+
+    def __repr__(self) -> str:
+        return "<Bytestring " + str(self.values) + ">"
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the bytestring in Devicetree Source format"""
+        return "[" + " ".join("%02x" % v for v in self.values) + "]"
+
+class CellArray(PropertyValues):
+    """A CellArray is an array of integer values
+
+    CellArrays are commonly used as the value of Devicetree properties like `reg` and `interrupts`.
+    The interpretation of each element of a CellArray is device-dependent. For example, the `reg`
+    property encodes a CellArray as a list of tuples (base address, size), while the `interrupts`
+    property encodes a CellArray as simply a list of interrupt line numbers.
+    """
+    def __init__(self, cells: List[Any]):
+        """Create a CellArray object"""
+        PropertyValues.__init__(self, cells)
+
+    def __repr__(self) -> str:
+        return "<CellArray " + self.values.__repr__() + ">"
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the cell array in Devicetree Source format"""
+        dtsValues = []
+        for i in self.values:
+            if not isinstance(i, OneString) and not isinstance(i, str):
+                dtsValues.append(i)
+        return "<" + " ".join(wrapStrings(dtsValues, formatHex)) + ">"
+
+class RegArray(CellArray):
+    """A RegArray is the CellArray assigned to the reg property"""
+    def __init__(self, cells: List[int],
+                 address_cells: int, size_cells: int,
+                 names: Optional[List[str]] = None):
+        """Create a RegArray from a list of ints"""
+        # pylint: disable=too-many-locals
+        CellArray.__init__(self, cells)
+        self.address_cells = address_cells
+        self.size_cells = size_cells
+
+        self.tuples = [] # type: List[Tuple[int, int, Optional[str]]]
+
+        group_size = self.address_cells + self.size_cells
+
+        if len(cells) % group_size != 0:
+            raise Exception("CellArray does not contain enough cells")
+
+        grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
+
+        if not names:
+            names = []
+
+        for group, name in zip_longest(grouped_cells, cast(Iterable[Any], names)):
+            address = 0
+            a_cells = list(reversed(group[:self.address_cells]))
+            for a, i in zip(a_cells, range(len(a_cells))):
+                address += (1 << (32 * i)) * a
+
+            size = 0
+            s_cells = list(reversed(group[self.address_cells:]))
+            for s, i in zip(s_cells, range(len(s_cells))):
+                size += (1 << (32 * i)) * s
+
+            self.tuples.append(cast(Tuple[int, int, Optional[str]], tuple([address, size, name])))
+
+    def get_by_name(self, name: str) -> Optional[Tuple[int, int]]:
+        """Returns the (address, size) tuple with a given name"""
+        for t in self.tuples:
+            if t[2] == name:
+                return cast(Tuple[int, int], tuple(t[:2]))
+        return None
+
+    def __repr__(self) -> str:
+        return "<RegArray " + self.values.__repr__() + ">"
+
+    def __iter__(self) -> Iterable[Tuple[int, int]]:
+        return cast(Iterable[Tuple[int, int]], map(lambda t: tuple(t[:2]), self.tuples))
+
+    def __len__(self) -> int:
+        return len(self.tuples)
+
+    def __getitem__(self, key) -> Optional[Tuple[int, int]]:
+        return list(self.__iter__())[key]
+
+class RangeArray(CellArray):
+    """A RangeArray is the CellArray assigned to the range property"""
+    def __init__(self, cells: List[int], child_address_cells: int,
+                 parent_address_cells: int, size_cells: int):
+        """Create a RangeArray from a list of ints"""
+        # pylint: disable=too-many-locals
+        CellArray.__init__(self, cells)
+        self.child_address_cells = child_address_cells
+        self.parent_address_cells = parent_address_cells
+        self.size_cells = size_cells
+
+        self.tuples = [] # type: List[Tuple[int, int, int]]
+
+        group_size = self.child_address_cells + self.parent_address_cells + self.size_cells
+
+        if len(cells) % group_size != 0:
+            raise Exception("CellArray does not contain enough cells")
+
+        grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
+
+        def sum_cells(cells: List[int]):
+            value = 0
+            for cell, index in zip(list(reversed(cells)), range(len(cells))):
+                value += (1 << (32 * index)) * cell
+            return value
+
+        for group in grouped_cells:
+            child_address = sum_cells(group[:self.child_address_cells])
+            parent_address = sum_cells(group[self.child_address_cells: \
+                                             self.child_address_cells + self.parent_address_cells])
+            size = sum_cells(group[self.child_address_cells + self.parent_address_cells:])
+
+            self.tuples.append(cast(Tuple[int, int, int],
+                                    tuple([child_address, parent_address, size])))
+
+    def __repr__(self) -> str:
+        return "<RangeArray " + self.values.__repr__() + ">"
+
+    def __iter__(self):
+        return iter(self.tuples)
+
+    def __len__(self) -> int:
+        return len(self.tuples)
+
+    def __getitem__(self, key) -> Any:
+        return self.tuples[key]
+
+class StringList(PropertyValues):
+    """A StringList is a list of null-terminated strings
+
+    The most common use of a StringList in Devicetree is to describe the `compatible` property.
+    """
+    def __init__(self, strings: List[str]):
+        """Create a StringList object"""
+        PropertyValues.__init__(self, strings)
+
+    def __repr__(self) -> str:
+        return "<StringList " + self.values.__repr__() + ">"
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the list of strings in Devicetree Source format"""
+        return ", ".join(wrapStrings(self.values))
+
+class OneString(PropertyValues):
+    def __init__(self, string: str):
+        PropertyValues.__init__(self, string)
+
+    def __repr__(self) -> str:
+        return self.values.__repr__()
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        return super().to_dts(formatHex)
+
+class Property:
+    """A Property is a key-value pair for a Devicetree Node
+
+    Properties are used to describe Nodes in the tree. There are many common properties, like
+
+        - compatible
+        - reg
+        - reg-names
+        - ranges
+        - interrupt-controller
+        - interrupts
+        - interrupt-parent
+        - clocks
+        - status
+
+    Which might commonly describe many or all nodes in a tree, and there are device, vendor,
+    operating system, runtime-specific properties.
+
+    Properties can possess no value, conveing meaning solely by their presence:
+
+        interrupt-controller;
+
+    Properties can also possess values such as an array of cells, a list of strings, etc.
+
+        reg = <0x10013000 0x1000>;
+        compatible = "sifive,rocket0", "riscv";
+
+    And properties can posses arbitrarily complex values, such as the following from the
+    Devicetree specification:
+
+        example = <0xf00f0000 19>, "a strange property format";
+    """
+    def __init__(self, name: str, values: PropertyValues):
+        """Create a Property object"""
+        self.name = name
+        self.values = values
+
+    def __repr__(self) -> str:
+        return "<Property %s>" % self.name
+
+    def __str__(self) -> str:
+        return self.to_dts()
+
+    @staticmethod
+    def from_dts(dts: str) -> 'Property':
+        """Parse a file and return a Devicetree object"""
+        # pylint: disable=import-outside-toplevel,cyclic-import
+        from pydevicetree.source import parseProperty
+        return parseProperty(dts)
+
+    def to_dts(self, level: int = 0) -> str:
+        """Format the Property assignment in Devicetree Source format"""
+        if self.name in ["reg", "ranges"]:
+            value = self.values.to_dts(formatHex=True)
+        else:
+            value = self.values.to_dts(formatHex=False)
+
+        if value != "":
+            return formatLevel(level, "%s = %s;\n" % (self.name, value))
+        if self.name == "ifdef":
+            return ""
+        return formatLevel(level, "%s;\n" % self.name)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
new file mode 100644
index 0000000..54b2d28
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import Union, Iterator
+
+class Label:
+    """A Label is a unique identifier for a Node
+
+    For example, the following node has the label "uart0":
+
+        uart0: uart@10013000 {
+            ...
+        };
+    """
+    def __init__(self, name: str):
+        """Create a Label"""
+        self.name = name
+
+    def __repr__(self) -> str:
+        return "<Label " + self.name + ">"
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, Label):
+            return self.name == other.name
+        if isinstance(other, str):
+            return self.name == other
+        return False
+
+    def to_dts(self) -> str:
+        """Format the label in Devicetree Source format"""
+        return self.name + ":"
+
+class Path:
+    """A Path uniquely identifies a Node by its parents and (optionally) unit address"""
+    def __init__(self, path: str):
+        """Create a path out of a string"""
+        self.path = path
+
+    def to_dts(self) -> str:
+        """Format the Path in Devicetree Source format"""
+        return self.path
+
+    def __repr__(self) -> str:
+        return "<Path " + self.to_dts() + ">"
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, Path):
+            return self.to_dts() == other.to_dts()
+        if isinstance(other, str):
+            return self.to_dts() == other
+        return False
+
+    def __iter__(self) -> Iterator[str]:
+        return iter(self.path.split("/"))
+
+    def replace(self, old: str, new: str) -> 'Path':
+        """Replace any elements of the path which match 'old' with a new element 'new'"""
+        return Path(self.path.replace(old, new))
+
+class Reference:
+    """A Reference is a Devicetree construct which points to a Node in the tree
+
+    The following are types of references:
+
+        - A reference to a label:
+
+            &my-label;
+
+        - A reference to a node by path:
+
+            &{/path/to/node@deadbeef}
+
+    This is the parent class for both types of references, LabelReference and PathReference
+    """
+    # pylint: disable=no-self-use
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the Reference in Devicetree Source format"""
+        return ""
+
+class LabelReference(Reference):
+    """A LabelReference is a reference to a Node by label"""
+    def __init__(self, label: Union[Label, str]):
+        """Create a LabelReference from a Label or string"""
+        if isinstance(label, Label):
+            self.label = label
+        elif isinstance(label, str):
+            self.label = Label(label)
+
+    def __repr__(self) -> str:
+        return "<LabelReference " + self.to_dts() + ">"
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the LabelReference in Devicetree Source format"""
+        return "&" + self.label.name
+
+class PathReference(Reference):
+    """A PathReference is a reference to a Node by path"""
+    def __init__(self, path: Union[Path, str]):
+        """Create a PathReference from a Path or string"""
+        if isinstance(path, Path):
+            self.path = path
+        elif isinstance(path, str):
+            self.path = Path(path)
+
+    def __repr__(self) -> str:
+        return "<PathReference " + self.to_dts() + ">"
+
+    def to_dts(self, formatHex: bool = False) -> str:
+        """Format the PathReference in Devicetree Source format"""
+        return "&{" + self.path.to_dts() + "}"
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
new file mode 100644
index 0000000..96768b3
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.source.parser import parseTree, parseNode, parseProperty
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
new file mode 100644
index 0000000..fb165e1
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+import os
+import sys
+
+import pyparsing as p # type: ignore
+
+ENV_CACHE_OPTION = "PYDEVICETREE_CACHE_SIZE_BOUND"
+
+cache_bound = None
+if ENV_CACHE_OPTION in os.environ:
+    option = os.environ[ENV_CACHE_OPTION]
+    if option != "None":
+        try:
+            cache_bound = int(option)
+        except ValueError:
+            print("%s requires a valid integer" % ENV_CACHE_OPTION, file=sys.stderr)
+p.ParserElement.enablePackrat(cache_bound)
+
+node_name = p.Word(p.alphanums + ",.-+_") ^ p.Literal("/")
+integer = p.pyparsing_common.integer ^ (p.Literal("0x").suppress() + p.pyparsing_common.hex_integer)
+unit_address = p.pyparsing_common.hex_integer
+unit_addresses = p.delimitedList(unit_address("address"), delim=",")
+node_handle = node_name("node_name") + p.Optional(p.Literal("@") + unit_addresses)
+property_name = p.Word(p.alphanums + ",.-_+?#")
+label = p.Word(p.alphanums + "_").setResultsName("label")
+label_creation = p.Combine(label + p.Literal(":"))
+string = p.QuotedString(quoteChar='"')
+stringlist = p.delimitedList(string)
+node_path = p.Combine(p.Literal("/") + \
+        p.delimitedList(node_handle, delim="/", combine=True)).setResultsName("path")
+path_reference = p.Literal("&{").suppress() + node_path + p.Literal("}").suppress()
+label_reference = p.Literal("&").suppress() + label
+label_raw = p.Word(p.alphanums + "_")
+reference = path_reference ^ label_reference ^ label_raw
+include_directive = p.Literal("/include/") + p.QuotedString(quoteChar='"')
+generic_directive = p.QuotedString(quoteChar="/", unquoteResults=False) + \
+        p.Optional(string ^ property_name ^ node_name ^ reference ^ (integer * 2)) + \
+        p.Literal(";").suppress()
+directive = include_directive ^ generic_directive
+
+operator = p.oneOf("~ ! * / + - << >> < <= > >= == != & ^ | && ||")
+arith_expr = p.Forward()
+ternary_element = arith_expr ^ integer
+ternary_expr = ternary_element + p.Literal("?") + ternary_element + p.Literal(":") + ternary_element
+arith_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer) ^ ternary_expr))
+arth_str = p.Forward()
+arith_str_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer ^ label_raw ^ p.Literal(",")) ^ ternary_expr))
+
+label_list = p.OneOrMore(p.Combine(label + p.Literal("\n")))
+
+cell_array = p.Literal("<").suppress() + \
+        p.ZeroOrMore(integer ^ arith_expr ^ arith_str_expr ^ label_list ^ string ^ reference ^ label_creation.suppress()) + \
+        p.Literal(">").suppress()
+bytestring = p.Literal("[").suppress() + \
+        (p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation.suppress())) + \
+        p.Literal("]").suppress()
+property_values = p.Forward()
+property_values = p.delimitedList(property_values ^ cell_array ^ bytestring ^ stringlist ^ \
+                                  reference ^ label_raw)
+property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + \
+        (property_values)).setResultsName("value") + p.Optional(p.Literal(";").suppress())
+
+ifdef_label = p.ZeroOrMore(p.Word(p.alphanums + " _|//*=/(/)"))
+ifdef_define = p.Combine(p.Keyword("#if") + ifdef_label)
+ifdef_end = p.Combine(p.Keyword("#endif") + ifdef_label)
+ifdef_define_values = p.Forward()
+ifdef_define_values = p.ZeroOrMore(ifdef_define)
+ifdef_end_values = p.Forward()
+ifdef_end_values = p.ZeroOrMore(ifdef_end)
+
+node_opener = ifdef_define_values + p.Optional(label_creation) + node_handle + p.Literal("{").suppress()
+node_reference_opener = reference + p.Literal("{").suppress()
+node_closer = p.Literal("}").suppress() + p.Literal(";").suppress() + ifdef_end_values
+node_definition = p.Forward()
+# pylint: disable=expression-not-assigned
+node_definition << (node_opener ^ node_reference_opener) + \
+        p.ZeroOrMore(property_assignment ^ directive ^ node_definition ^ ifdef_define ^ ifdef_end) + \
+        node_closer
+
+devicetree = p.ZeroOrMore(directive ^ node_definition)
+
+devicetree.ignore(p.cStyleComment)
+devicetree.ignore("//" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#include" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#define" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#else" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#error" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#ifndef" + p.SkipTo(p.lineEnd))
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        devicetree.parseFile(sys.argv[1]).pprint()
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
new file mode 100644
index 0000000..0692482
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from itertools import chain
+
+from cot_dt2c.pydevicetree.source import grammar
+from cot_dt2c.pydevicetree.ast import *
+
+ifdef_stack = []
+
+def transformNode(string, location, tokens):
+    """Transforms a ParseResult into a Node"""
+    properties = [e for e in tokens.asList() if isinstance(e, Property)]
+    directives = [e for e in tokens.asList() if isinstance(e, Directive)]
+    children = [e for e in tokens.asList() if isinstance(e, Node)]
+
+    if isinstance(tokens[0], Reference):
+        return NodeReference(tokens[0], properties=properties,
+                             directives=directives, children=children)
+    return Node(tokens.node_name, tokens.label, tokens.address, properties=properties,
+                directives=directives, children=children)
+
+def transformPropertyAssignment(string, location, tokens):
+    """Transforms a ParseResult into a Property"""
+    for v in tokens.value:
+        if isinstance(v, PropertyValues):
+            return Property(tokens.property_name, v)
+        if isinstance(v, CellArray):
+            return Property(tokens.property_name, v)
+        if isinstance(v, StringList):
+            return Property(tokens.property_name, v)
+        if isinstance(v, Reference):
+            return Property(tokens.property_name, v)
+
+    return Property(tokens.property_name, PropertyValues([]))
+
+def transformDirective(string, location, tokens):
+    """Transforms a ParseResult into a Directive"""
+    if len(tokens.asList()) > 1:
+        return Directive(tokens[0], tokens[1])
+    return Directive(tokens[0])
+
+def evaluateArithExpr(string, location, tokens):
+    """Evaluates a ParseResult as a python expression"""
+    flat_tokens = list(chain.from_iterable(tokens.asList()))
+    expr = " ".join(str(t) for t in flat_tokens)
+    # pylint: disable=eval-used
+    return eval(expr)
+
+def transformTernary(string, location, tokens):
+    """Evaluates a ParseResult as a ternary expression"""
+    # pylint: disable=eval-used
+    return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))
+
+def transformPropertyValues(string, location, tokens):
+    """Transforms a ParseResult into a PropertyValues"""
+    if len(tokens.asList()) == 1:
+        return tokens.asList()[0]
+    return PropertyValues(tokens.asList())
+
+def transformStringList(string, location, tokens):
+    """Transforms a ParseResult into a StringList"""
+    return StringList(tokens.asList())
+
+def transformString(string, location, token):
+    return OneString(token)
+
+def transformIfdefMacro(string, location, tokens):
+    tokenlist = tokens.asList()
+    for t in tokenlist:
+        ifdef_stack.append(t)
+    return Property("ifdef", PropertyValues(ifdef_stack.copy()))
+
+def transformIfdefEnd(string, location, tokens):
+    tokenlist = tokens.asList()
+    for t in tokenlist:
+        ifdef_stack.pop()
+
+def transformIfdef(string, location, tokens):
+    return Property("ifdef", PropertyValues(tokens))
+
+def evaluateStrArithExpr(string, location, tokens):
+    """Evaluates a ParseResult as a python expression"""
+    flat_tokens = list(chain.from_iterable(tokens.asList()))
+    for i, t in enumerate(flat_tokens):
+        if isinstance(t, int):
+            flat_tokens[i] = "(" + str(t) + ")"
+    expr = " ".join(str(t) for t in flat_tokens)
+    # pylint: disable=eval-used
+    return expr
+
+def transformBytestring(string, location, tokens):
+    """Transforms a ParseResult into a Bytestring"""
+    inttokens = []
+    for t in tokens.asList():
+        if all(c in "0123456789abcdefABCDEF" for c in t):
+            inttokens.append(int(t, base=16))
+    return Bytestring(inttokens)
+
+def transformCellArray(string, location, tokens):
+    """Transforms a ParseResult into a CellArray"""
+    return CellArray(tokens.asList())
+
+def transformLabel(string, location, tokens):
+    """Transforms a ParseResult into a Label"""
+    return Label(tokens.label)
+
+def transformPath(string, location, tokens):
+    """Transforms a ParseResult into a Path"""
+    path = ""
+    for handle in tokens.path[0].split("/"):
+        if "@" in handle:
+            node, address = handle.split("@")
+            path += "/%s@%x" % (node, int(address))
+        elif handle != "":
+            path += "/" + handle
+    return Path(path)
+
+def transformPathReference(string, location, tokens):
+    """Transforms a ParseResult into a PathReference"""
+    return PathReference(tokens[0])
+
+def transformLabelReference(string, location, tokens):
+    """Transforms a ParseResult into a LabelReference"""
+    return LabelReference(tokens[0])
+
+def transformReference(string, location, tokens):
+    """Transforms a ParseResult into a Reference"""
+    if isinstance(tokens[0], Reference):
+        return tokens[0]
+    return None
+
+grammar.label.setParseAction(transformLabel)
+grammar.node_path.setParseAction(transformPath)
+grammar.path_reference.setParseAction(transformPathReference)
+grammar.label_reference.setParseAction(transformLabelReference)
+grammar.reference.setParseAction(transformReference)
+grammar.node_definition.setParseAction(transformNode)
+grammar.property_assignment.setParseAction(transformPropertyAssignment)
+grammar.directive.setParseAction(transformDirective)
+grammar.arith_expr.setParseAction(evaluateArithExpr)
+grammar.ternary_expr.setParseAction(transformTernary)
+grammar.stringlist.setParseAction(transformStringList)
+grammar.bytestring.setParseAction(transformBytestring)
+grammar.cell_array.setParseAction(transformCellArray)
+grammar.property_values.setParseAction(transformPropertyValues)
+grammar.label_raw.setParseAction(transformString)
+grammar.ifdef_define_values.setParseAction(transformIfdefMacro)
+grammar.ifdef_end_values.setParseAction(transformIfdefEnd)
+grammar.arith_str_expr.setParseAction(transformPropertyValues)
+
+def printTree(tree, level=0):
+    """Helper function to print a bunch of elements as a tree"""
+    def printlevel(level, s):
+        print(" " * level + s)
+
+    for item in tree:
+        if isinstance(item, Node):
+            if item.address:
+                printlevel(level, "Node %s@%x" % (item.name, item.address))
+            else:
+                printlevel(level, "Node %s" % item.name)
+
+            if item.label:
+                printlevel(level, " Label: %s" % item.label)
+
+            if item.parent:
+                printlevel(level, " Parent: %s" % item.parent)
+
+            printTree(item.properties, level=(level + 1))
+
+            printTree(item.children, level=(level + 1))
+        elif isinstance(item, Property):
+            if item.values:
+                printlevel(level, "Property %s: %s" % (item.name, item.values))
+            else:
+                printlevel(level, "Property %s" % item.name)
+        elif isinstance(item, Directive):
+            if item.options:
+                printlevel(level, "Directive %s: %s" % (item.directive, item.options))
+            else:
+                printlevel(level, "Directive %s" % item.directive)
+
+def parentNodes(tree, parent=None):
+    """Walks a tree and sets Nodes' parent field to point at their parent"""
+    for item in tree:
+        if isinstance(item, Node):
+            item.parent = parent
+            parentNodes(item.children, item)
+
+def recurseIncludeFiles(elements, pwd):
+    """Recursively follows and parses /include/ directives an a tree"""
+    for e in elements:
+        if isinstance(e, Directive):
+            if e.directive == "/include/":
+                # Prefix with current directory if path is not absolute
+                if e.option[0] != '/':
+                    e.option = pwd + e.option
+
+                with open(e.option, 'r') as f:
+                    contents = f.read()
+
+                elements += parseElements(contents)
+
+                del elements[elements.asList().index(e)]
+
+def parseElements(dts, pwd="", followIncludes=False):
+    """Parses a string into a list of elements"""
+    elements = grammar.devicetree.parseString(dts, parseAll=True)
+    parentNodes(elements)
+    if followIncludes:
+        recurseIncludeFiles(elements, pwd)
+    return elements
+
+def parseTree(dts, pwd="", followIncludes=False):
+    """Parses a string into a full Devicetree"""
+    return Devicetree(parseElements(dts, pwd, followIncludes))
+
+def parseNode(dts):
+    """Parses a string into a Devictreee Node"""
+    return grammar.node_definition.parseString(dts, parseAll=True)[0]
+
+def parseProperty(dts):
+    """Parses a string into a Devicetree Property"""
+    return grammar.property_assignment.parseString(dts, parseAll=True)[0]
+
+if __name__ == "__main__":
+    import sys
+    if len(sys.argv) > 1:
+        with open(sys.argv[1], 'r') as f:
+            dts = f.read()
+        tree = parseTree(dts)
+        printTree(tree)
+        print(tree)
+    else:
+        print("Please pass the devicetree source file as an argument")
+        sys.exit(1)
diff --git a/tools/cot_dt2c/pyproject.toml b/tools/cot_dt2c/pyproject.toml
new file mode 100644
index 0000000..d383924
--- /dev/null
+++ b/tools/cot_dt2c/pyproject.toml
@@ -0,0 +1,60 @@
+# Poetry pyproject.toml: https://python-poetry.org/docs/pyproject/
+[build-system]
+requires = ["poetry_core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry]
+name = "cot_dt2c"
+version = "0.1.0"
+description = "CoT-dt2c Tool is a python script to convert CoT DT file into corresponding C file"
+authors = ["Arm Ltd <tf-a@lists.trustedfirmware.org>"]
+license = "BSD-3"
+repository = "https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/"
+homepage = "https://trustedfirmware-a.readthedocs.io/en/latest/index.html"
+
+# Pypi classifiers: https://pypi.org/classifiers/
+classifiers = [
+  "Development Status :: 3 - Alpha",
+  "Intended Audience :: Developers",
+  "Operating System :: OS Independent",
+  "Topic :: Software Development :: Libraries :: Python Modules",
+  "License :: OSI Approved :: BSD License",
+  "Programming Language :: Python :: 3",
+  "Programming Language :: Python :: 3.8",
+  "Programming Language :: Python :: 3.9",
+]
+
+
+[tool.poetry.dependencies]
+python = "^3.8"
+click = "^8.1.7"
+pyparsing = "^2.4.7"
+plotly = "^5.23.0"
+pandas = "^2.2.2"
+igraph = "^0.11.6"
+
+[tool.poetry.dev-dependencies]
+mypy = "^0.910"
+pytest = "^6.2.5"
+pyparsing = "^2.4.7"
+plotly = "^5.23.0"
+pandas = "^2.2.2"
+igraph = "^0.11.6"
+
+[tool.mypy]
+# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
+python_version = 3.8
+pretty = true
+show_traceback = true
+color_output = true
+
+[tool.coverage.run]
+source = ["tests"]
+
+[coverage.paths]
+source = "cot_dt2c"
+
+[tool.poetry.scripts]
+# Entry points for the package https://python-poetry.org/docs/pyproject/#scripts
+# "cot-dt2c" = "cot_dt2c.__main__:cli"
+"cot-dt2c" = "cot_dt2c.__main__:cli"
diff --git a/tools/cot_dt2c/requirements.txt b/tools/cot_dt2c/requirements.txt
new file mode 100644
index 0000000..246b81d
--- /dev/null
+++ b/tools/cot_dt2c/requirements.txt
@@ -0,0 +1,6 @@
+mypy
+pylint
+pyparsing
+igraph
+pandas
+plotly
diff --git a/tools/cot_dt2c/tests/test.dtsi b/tools/cot_dt2c/tests/test.dtsi
new file mode 100644
index 0000000..ee744e6
--- /dev/null
+++ b/tools/cot_dt2c/tests/test.dtsi
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a valid CoT DT file
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+#if defined(test)
+		example_cert: example_cert {
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+		};
+#endif
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		example {
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	example_ctr: example_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	example_pk: example_pk {
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test2.dtsi b/tools/cot_dt2c/tests/test2.dtsi
new file mode 100644
index 0000000..c4dbf83
--- /dev/null
+++ b/tools/cot_dt2c/tests/test2.dtsi
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a valid CoT DT file
+ *
+ */
+
+#if test
+#include <example/example.h>
+#include <example/example/example.h>
+#endif
+
+cot
+{
+	manifests
+	{
+		compatible = "arm, cert-descs";
+#if defined (test)
+		example_cert: example_cert
+		{
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+
+		};
+#endif
+	};
+
+	images
+	{
+		compatible = "arm, img-descs";
+
+		example
+		{
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+	};
+};
+
+non_volatile_counters: non_volatile_counters
+{
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	example_ctr: example_ctr
+	{
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys
+{
+	example_pk: example_pk
+	{
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_bracket.dtsi b/tools/cot_dt2c/tests/test_invalid_bracket.dtsi
new file mode 100644
index 0000000..ec5f9c7
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_bracket.dtsi
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching bracket
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		example_cert: example_cert {
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+
+		};
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		example {
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	example_ctr: example_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	example_pk: example_pk {
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi b/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi
new file mode 100644
index 0000000..5bc6bb9
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching ifdef macro
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		example_cert: example_cert {
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+
+		};
+	};
+
+#if defined(test)
+	images {
+		compatible = "arm, img-descs";
+
+		example {
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	example_ctr: example_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	example_pk: example_pk {
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi b/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi
new file mode 100644
index 0000000..c915168
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching ifdef macro
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		example_cert: example_cert {
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+
+		};
+	};
+
+#if defined(test)
+	images {
+		compatible = "arm, img-descs";
+
+		example {
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+	};
+#endif
+#endif
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	example_ctr: example_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	example_pk: example_pk {
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi
new file mode 100644
index 0000000..9c0a5f2
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing mandantory attributes
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		cca_content_cert: cca_content_cert {
+			root-certificate;
+			antirollback-counter = <&cca_nv_ctr>;
+
+			tb_fw_hash: tb_fw_hash {
+				oid = TRUSTED_BOOT_FW_HASH_OID;
+			};
+			tb_fw_config_hash: tb_fw_config_hash {
+				oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+			};
+			hw_config_hash: hw_config_hash {
+			};
+			fw_config_hash: fw_config_hash {
+				oid = FW_CONFIG_HASH_OID;
+			};
+			soc_fw_hash: soc_fw_hash {
+				oid = SOC_AP_FW_HASH_OID;
+			};
+			soc_fw_config_hash: soc_fw_config_hash {
+				oid = SOC_FW_CONFIG_HASH_OID;
+			};
+			rmm_hash: rmm_hash {
+				oid = RMM_HASH_OID;
+			};
+		};
+
+		core_swd_key_cert: core_swd_key_cert {
+			root-certificate;
+			image-id = <CORE_SWD_KEY_CERT_ID>;
+			signing-key = <&swd_rot_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			core_swd_pk: core_swd_pk {
+				oid = CORE_SWD_PK_OID;
+			};
+		};
+
+		trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			tos_fw_hash: tos_fw_hash {
+				oid = TRUSTED_OS_FW_HASH_OID;
+			};
+			tos_fw_config_hash: tos_fw_config_hash {
+				oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+			};
+		};
+
+		plat_key_cert: plat_key_cert {
+			root-certificate;
+			image-id = <PLAT_KEY_CERT_ID>;
+			signing-key = <&prot_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			plat_pk: plat_pk {
+				oid = PLAT_PK_OID;
+			};
+		};
+
+		non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+			parent = <&plat_key_cert>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			nt_world_bl_hash: nt_world_bl_hash {
+				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+			};
+			nt_fw_config_hash: nt_fw_config_hash {
+				oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+			};
+		};
+
+#if defined(SPD_spmd)
+		sip_sp_content_cert: sip_sp_content_cert {
+			image-id = <SIP_SP_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			sp_pkg1_hash: sp_pkg1_hash {
+				oid = SP_PKG1_HASH_OID;
+			};
+			sp_pkg2_hash: sp_pkg2_hash {
+				oid = SP_PKG2_HASH_OID;
+			};
+			sp_pkg3_hash: sp_pkg3_hash {
+				oid = SP_PKG3_HASH_OID;
+			};
+			sp_pkg4_hash: sp_pkg4_hash {
+				oid = SP_PKG4_HASH_OID;
+			};
+		};
+
+		plat_sp_content_cert: plat_sp_content_cert {
+			parent = <&plat_key_cert>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			sp_pkg5_hash: sp_pkg5_hash {
+				oid = SP_PKG5_HASH_OID;
+			};
+			sp_pkg6_hash: sp_pkg6_hash {
+				oid = SP_PKG6_HASH_OID;
+			};
+			sp_pkg7_hash: sp_pkg7_hash {
+				oid = SP_PKG7_HASH_OID;
+			};
+			sp_pkg8_hash: sp_pkg8_hash {
+				oid = SP_PKG8_HASH_OID;
+			};
+		};
+#endif
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		hw_config {
+			image-id = <HW_CONFIG_ID>;
+			hash = <&hw_config_hash>;
+		};
+
+		bl31_image {
+			image-id = <BL31_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_hash>;
+		};
+
+		soc_fw_config {
+			image-id = <SOC_FW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_config_hash>;
+		};
+
+		rmm_image {
+			image-id = <RMM_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&rmm_hash>;
+		};
+
+		bl32_image {
+			image-id = <BL32_IMAGE_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_hash>;
+		};
+
+		tos_fw_config {
+			image-id = <TOS_FW_CONFIG_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_config_hash>;
+		};
+
+		bl33_image {
+			image-id = <BL33_IMAGE_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_world_bl_hash>;
+		};
+
+		nt_fw_config {
+			image-id = <NT_FW_CONFIG_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_fw_config_hash>;
+		};
+
+#if defined(SPD_spmd)
+		sp_pkg1 {
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg1_hash>;
+		};
+
+		sp_pkg2 {
+			image-id = <SP_PKG2_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg2_hash>;
+		};
+
+		sp_pkg3 {
+			image-id = <SP_PKG3_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg3_hash>;
+		};
+
+		sp_pkg4 {
+			image-id = <SP_PKG4_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg4_hash>;
+		};
+
+		sp_pkg5 {
+			image-id = <SP_PKG5_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg5_hash>;
+		};
+
+		sp_pkg6 {
+			image-id = <SP_PKG6_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg6_hash>;
+		};
+
+		sp_pkg7 {
+			image-id = <SP_PKG7_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg7_hash>;
+		};
+
+		sp_pkg8 {
+			image-id = <SP_PKG8_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg8_hash>;
+		};
+#endif
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cca_nv_ctr: cca_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+
+	trusted_nv_ctr: trusted_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = TRUSTED_FW_NVCOUNTER_OID;
+	};
+
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
+		id  = <NON_TRUSTED_NV_CTR_ID>;
+		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	swd_rot_pk: swd_rot_pk {
+		oid = SWD_ROT_PK_OID;
+	};
+	prot_pk: prot_pk {
+		oid = PROT_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi
new file mode 100644
index 0000000..01b2597
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that points to invalid parent
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		cca_content_cert: cca_content_cert {
+			root-certificate;
+			image-id =<CCA_CONTENT_CERT_ID>;
+			antirollback-counter = <&cca_nv_ctr>;
+
+			tb_fw_hash: tb_fw_hash {
+				oid = TRUSTED_BOOT_FW_HASH_OID;
+			};
+			tb_fw_config_hash: tb_fw_config_hash {
+				oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+			};
+			hw_config_hash: hw_config_hash {
+				oid = HW_CONFIG_HASH_OID;
+			};
+			fw_config_hash: fw_config_hash {
+				oid = FW_CONFIG_HASH_OID;
+			};
+			soc_fw_hash: soc_fw_hash {
+				oid = SOC_AP_FW_HASH_OID;
+			};
+			soc_fw_config_hash: soc_fw_config_hash {
+				oid = SOC_FW_CONFIG_HASH_OID;
+			};
+			rmm_hash: rmm_hash {
+				oid = RMM_HASH_OID;
+			};
+		};
+
+		core_swd_key_cert: core_swd_key_cert {
+			root-certificate;
+			image-id = <CORE_SWD_KEY_CERT_ID>;
+			signing-key = <&swd_rot_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			core_swd_pk: core_swd_pk {
+				oid = CORE_SWD_PK_OID;
+			};
+		};
+
+		trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			tos_fw_hash: tos_fw_hash {
+				oid = TRUSTED_OS_FW_HASH_OID;
+			};
+			tos_fw_config_hash: tos_fw_config_hash {
+				oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+			};
+		};
+
+		plat_key_cert: plat_key_cert {
+			root-certificate;
+			image-id = <PLAT_KEY_CERT_ID>;
+			signing-key = <&prot_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			plat_pk: plat_pk {
+				oid = PLAT_PK_OID;
+			};
+		};
+
+		non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+			parent = <&cca_content_cert>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			nt_world_bl_hash: nt_world_bl_hash {
+				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+			};
+			nt_fw_config_hash: nt_fw_config_hash {
+				oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+			};
+		};
+
+#if defined(SPD_spmd)
+		sip_sp_content_cert: sip_sp_content_cert {
+			image-id = <SIP_SP_CONTENT_CERT_ID>;
+			parent = <&cca_content_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			sp_pkg1_hash: sp_pkg1_hash {
+				oid = SP_PKG1_HASH_OID;
+			};
+			sp_pkg2_hash: sp_pkg2_hash {
+				oid = SP_PKG2_HASH_OID;
+			};
+			sp_pkg3_hash: sp_pkg3_hash {
+				oid = SP_PKG3_HASH_OID;
+			};
+			sp_pkg4_hash: sp_pkg4_hash {
+				oid = SP_PKG4_HASH_OID;
+			};
+		};
+
+		plat_sp_content_cert: plat_sp_content_cert {
+			image-id = <PLAT_SP_CONTENT_CERT_ID>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			sp_pkg5_hash: sp_pkg5_hash {
+				oid = SP_PKG5_HASH_OID;
+			};
+			sp_pkg6_hash: sp_pkg6_hash {
+				oid = SP_PKG6_HASH_OID;
+			};
+			sp_pkg7_hash: sp_pkg7_hash {
+				oid = SP_PKG7_HASH_OID;
+			};
+			sp_pkg8_hash: sp_pkg8_hash {
+				oid = SP_PKG8_HASH_OID;
+			};
+		};
+#endif
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		hw_config {
+			image-id = <HW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&hw_config_hash>;
+		};
+
+		bl31_image {
+			image-id = <BL31_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_hash>;
+		};
+
+		soc_fw_config {
+			image-id = <SOC_FW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_config_hash>;
+		};
+
+		rmm_image {
+			image-id = <RMM_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&rmm_hash>;
+		};
+
+		bl32_image {
+			image-id = <BL32_IMAGE_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_hash>;
+		};
+
+		tos_fw_config {
+			image-id = <TOS_FW_CONFIG_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_config_hash>;
+		};
+
+		bl33_image {
+			image-id = <BL33_IMAGE_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_world_bl_hash>;
+		};
+
+		nt_fw_config {
+			image-id = <NT_FW_CONFIG_ID>;
+			hash = <&nt_fw_config_hash>;
+		};
+
+#if defined(SPD_spmd)
+		sp_pkg1 {
+			image-id = <SP_PKG1_ID>;
+			hash = <&sp_pkg1_hash>;
+		};
+
+		sp_pkg2 {
+			image-id = <SP_PKG2_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg2_hash>;
+		};
+
+		sp_pkg3 {
+			image-id = <SP_PKG3_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg3_hash>;
+		};
+
+		sp_pkg4 {
+			image-id = <SP_PKG4_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg4_hash>;
+		};
+
+		sp_pkg5 {
+			image-id = <SP_PKG5_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg5_hash>;
+		};
+
+		sp_pkg6 {
+			image-id = <SP_PKG6_ID>;
+			parent = <&wrong_parent>;
+			hash = <&sp_pkg6_hash>;
+		};
+
+		sp_pkg7 {
+			image-id = <SP_PKG7_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg7_hash>;
+		};
+
+		sp_pkg8 {
+			image-id = <SP_PKG8_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg8_hash>;
+		};
+#endif
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cca_nv_ctr: cca_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+
+	trusted_nv_ctr: trusted_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = TRUSTED_FW_NVCOUNTER_OID;
+	};
+
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
+		id  = <NON_TRUSTED_NV_CTR_ID>;
+		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	swd_rot_pk: swd_rot_pk {
+		oid = SWD_ROT_PK_OID;
+	};
+	prot_pk: prot_pk {
+		oid = PROT_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi
new file mode 100644
index 0000000..5958f5d
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing definition of
+ * nv counters
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		example_cert: example_cert {
+			root-certificate;
+			image-id =<EXAMPLE_ID>;
+			signing-key = <&swd_rot_pk>;
+			antirollback-counter = <&example_ctr>;
+
+			example_hash: example_hash
+			{
+				oid = EXAMPLE_HASH_ID;
+			};
+
+		};
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		example {
+			image-id = <EXAMPLE_ID>;
+			parent = <&example_cert>;
+			hash = <&example_hash>;
+		};
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+};
+
+rot_keys {
+	example_pk: example_pk {
+		oid = EXAMPLE_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi
new file mode 100644
index 0000000..465a4c6
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing root certificate
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		core_swd_key_cert: core_swd_key_cert {
+			image-id = <CORE_SWD_KEY_CERT_ID>;
+			signing-key = <&swd_rot_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			core_swd_pk: core_swd_pk {
+				oid = CORE_SWD_PK_OID;
+			};
+		};
+
+		trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			tos_fw_hash: tos_fw_hash {
+				oid = TRUSTED_OS_FW_HASH_OID;
+			};
+			tos_fw_config_hash: tos_fw_config_hash {
+				oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+			};
+		};
+
+		plat_key_cert: plat_key_cert {
+			image-id = <PLAT_KEY_CERT_ID>;
+			signing-key = <&prot_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			plat_pk: plat_pk {
+				oid = PLAT_PK_OID;
+			};
+		};
+
+		non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+			parent = <&plat_key_cert>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			nt_world_bl_hash: nt_world_bl_hash {
+				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+			};
+			nt_fw_config_hash: nt_fw_config_hash {
+				oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+			};
+		};
+
+#if defined(SPD_spmd)
+		sip_sp_content_cert: sip_sp_content_cert {
+			image-id = <SIP_SP_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			sp_pkg1_hash: sp_pkg1_hash {
+				oid = SP_PKG1_HASH_OID;
+			};
+			sp_pkg2_hash: sp_pkg2_hash {
+				oid = SP_PKG2_HASH_OID;
+			};
+			sp_pkg3_hash: sp_pkg3_hash {
+				oid = SP_PKG3_HASH_OID;
+			};
+			sp_pkg4_hash: sp_pkg4_hash {
+				oid = SP_PKG4_HASH_OID;
+			};
+		};
+
+		plat_sp_content_cert: plat_sp_content_cert {
+			image-id = <PLAT_SP_CONTENT_CERT_ID>;
+			parent = <&plat_key_cert>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			sp_pkg5_hash: sp_pkg5_hash {
+				oid = SP_PKG5_HASH_OID;
+			};
+			sp_pkg6_hash: sp_pkg6_hash {
+				oid = SP_PKG6_HASH_OID;
+			};
+			sp_pkg7_hash: sp_pkg7_hash {
+				oid = SP_PKG7_HASH_OID;
+			};
+			sp_pkg8_hash: sp_pkg8_hash {
+				oid = SP_PKG8_HASH_OID;
+			};
+		};
+#endif
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		hw_config {
+			image-id = <HW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&hw_config_hash>;
+		};
+
+		bl31_image {
+			image-id = <BL31_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_hash>;
+		};
+
+		soc_fw_config {
+			image-id = <SOC_FW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_config_hash>;
+		};
+
+		rmm_image {
+			image-id = <RMM_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&rmm_hash>;
+		};
+
+		bl32_image {
+			image-id = <BL32_IMAGE_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_hash>;
+		};
+
+		tos_fw_config {
+			image-id = <TOS_FW_CONFIG_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_config_hash>;
+		};
+
+		bl33_image {
+			image-id = <BL33_IMAGE_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_world_bl_hash>;
+		};
+
+		nt_fw_config {
+			image-id = <NT_FW_CONFIG_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_fw_config_hash>;
+		};
+
+#if defined(SPD_spmd)
+		sp_pkg1 {
+			image-id = <SP_PKG1_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg1_hash>;
+		};
+
+		sp_pkg2 {
+			image-id = <SP_PKG2_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg2_hash>;
+		};
+
+		sp_pkg3 {
+			image-id = <SP_PKG3_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg3_hash>;
+		};
+
+		sp_pkg4 {
+			image-id = <SP_PKG4_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg4_hash>;
+		};
+
+		sp_pkg5 {
+			image-id = <SP_PKG5_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg5_hash>;
+		};
+
+		sp_pkg6 {
+			image-id = <SP_PKG6_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg6_hash>;
+		};
+
+		sp_pkg7 {
+			image-id = <SP_PKG7_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg7_hash>;
+		};
+
+		sp_pkg8 {
+			image-id = <SP_PKG8_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg8_hash>;
+		};
+#endif
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cca_nv_ctr: cca_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+
+	trusted_nv_ctr: trusted_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = TRUSTED_FW_NVCOUNTER_OID;
+	};
+
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
+		id  = <NON_TRUSTED_NV_CTR_ID>;
+		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	swd_rot_pk: swd_rot_pk {
+		oid = SWD_ROT_PK_OID;
+	};
+	prot_pk: prot_pk {
+		oid = PROT_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi b/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi
new file mode 100644
index 0000000..b761beb
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that points to invalid parent
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+	manifests {
+		compatible = "arm, cert-descs";
+
+		cca_content_cert: cca_content_cert {
+			root-certificate;
+			image-id =<CCA_CONTENT_CERT_ID>;
+			antirollback-counter = <&cca_nv_ctr>;
+
+			tb_fw_hash: tb_fw_hash {
+				oid = TRUSTED_BOOT_FW_HASH_OID;
+			};
+			tb_fw_config_hash: tb_fw_config_hash {
+				oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+			};
+			hw_config_hash: hw_config_hash {
+				oid = HW_CONFIG_HASH_OID;
+			};
+			fw_config_hash: fw_config_hash {
+				oid = FW_CONFIG_HASH_OID;
+			};
+			soc_fw_hash: soc_fw_hash {
+				oid = SOC_AP_FW_HASH_OID;
+			};
+			soc_fw_config_hash: soc_fw_config_hash {
+				oid = SOC_FW_CONFIG_HASH_OID;
+			};
+			rmm_hash: rmm_hash {
+				oid = RMM_HASH_OID;
+			};
+		};
+
+		core_swd_key_cert: core_swd_key_cert {
+			root-certificate;
+			image-id = <CORE_SWD_KEY_CERT_ID>;
+			signing-key = <&swd_rot_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			core_swd_pk: core_swd_pk {
+				oid = CORE_SWD_PK_OID;
+			};
+		};
+
+		trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+			image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+			parent = <&core_swd_key_cert>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			tos_fw_hash: tos_fw_hash {
+				oid = TRUSTED_OS_FW_HASH_OID;
+			};
+			tos_fw_config_hash: tos_fw_config_hash {
+				oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+			};
+		};
+
+		plat_key_cert: plat_key_cert {
+			root-certificate;
+			image-id = <PLAT_KEY_CERT_ID>;
+			signing-key = <&prot_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			plat_pk: plat_pk {
+				oid = PLAT_PK_OID;
+			};
+		};
+
+		non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+			image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+			parent = <&wrong_parent>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			nt_world_bl_hash: nt_world_bl_hash {
+				oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+			};
+			nt_fw_config_hash: nt_fw_config_hash {
+				oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+			};
+		};
+
+#if defined(SPD_spmd)
+		sip_sp_content_cert: sip_sp_content_cert {
+			image-id = <SIP_SP_CONTENT_CERT_ID>;
+			parent = <&wrong_parent>;
+			signing-key = <&core_swd_pk>;
+			antirollback-counter = <&trusted_nv_ctr>;
+
+			sp_pkg1_hash: sp_pkg1_hash {
+				oid = SP_PKG1_HASH_OID;
+			};
+			sp_pkg2_hash: sp_pkg2_hash {
+				oid = SP_PKG2_HASH_OID;
+			};
+			sp_pkg3_hash: sp_pkg3_hash {
+				oid = SP_PKG3_HASH_OID;
+			};
+			sp_pkg4_hash: sp_pkg4_hash {
+				oid = SP_PKG4_HASH_OID;
+			};
+		};
+
+		plat_sp_content_cert: plat_sp_content_cert {
+			image-id = <PLAT_SP_CONTENT_CERT_ID>;
+			signing-key = <&plat_pk>;
+			antirollback-counter = <&non_trusted_nv_ctr>;
+
+			sp_pkg5_hash: sp_pkg5_hash {
+				oid = SP_PKG5_HASH_OID;
+			};
+			sp_pkg6_hash: sp_pkg6_hash {
+				oid = SP_PKG6_HASH_OID;
+			};
+			sp_pkg7_hash: sp_pkg7_hash {
+				oid = SP_PKG7_HASH_OID;
+			};
+			sp_pkg8_hash: sp_pkg8_hash {
+				oid = SP_PKG8_HASH_OID;
+			};
+		};
+#endif
+	};
+
+	images {
+		compatible = "arm, img-descs";
+
+		hw_config {
+			image-id = <HW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&hw_config_hash>;
+		};
+
+		bl31_image {
+			image-id = <BL31_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_hash>;
+		};
+
+		soc_fw_config {
+			image-id = <SOC_FW_CONFIG_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&soc_fw_config_hash>;
+		};
+
+		rmm_image {
+			image-id = <RMM_IMAGE_ID>;
+			parent = <&cca_content_cert>;
+			hash = <&rmm_hash>;
+		};
+
+		bl32_image {
+			image-id = <BL32_IMAGE_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_hash>;
+		};
+
+		tos_fw_config {
+			image-id = <TOS_FW_CONFIG_ID>;
+			parent = <&trusted_os_fw_content_cert>;
+			hash = <&tos_fw_config_hash>;
+		};
+
+		bl33_image {
+			image-id = <BL33_IMAGE_ID>;
+			parent = <&non_trusted_fw_content_cert>;
+			hash = <&nt_world_bl_hash>;
+		};
+
+		nt_fw_config {
+			image-id = <NT_FW_CONFIG_ID>;
+			hash = <&nt_fw_config_hash>;
+		};
+
+#if defined(SPD_spmd)
+		sp_pkg1 {
+			image-id = <SP_PKG1_ID>;
+			hash = <&sp_pkg1_hash>;
+		};
+
+		sp_pkg2 {
+			image-id = <SP_PKG2_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg2_hash>;
+		};
+
+		sp_pkg3 {
+			image-id = <SP_PKG3_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg3_hash>;
+		};
+
+		sp_pkg4 {
+			image-id = <SP_PKG4_ID>;
+			parent = <&sip_sp_content_cert>;
+			hash = <&sp_pkg4_hash>;
+		};
+
+		sp_pkg5 {
+			image-id = <SP_PKG5_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg5_hash>;
+		};
+
+		sp_pkg6 {
+			image-id = <SP_PKG6_ID>;
+			parent = <&wrong_parent>;
+			hash = <&sp_pkg6_hash>;
+		};
+
+		sp_pkg7 {
+			image-id = <SP_PKG7_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg7_hash>;
+		};
+
+		sp_pkg8 {
+			image-id = <SP_PKG8_ID>;
+			parent = <&plat_sp_content_cert>;
+			hash = <&sp_pkg8_hash>;
+		};
+#endif
+	};
+};
+
+non_volatile_counters: non_volatile_counters {
+	compatible = "arm, non-volatile-counter";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cca_nv_ctr: cca_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = CCA_FW_NVCOUNTER_OID;
+	};
+
+	trusted_nv_ctr: trusted_nv_ctr {
+		id  = <TRUSTED_NV_CTR_ID>;
+		oid = TRUSTED_FW_NVCOUNTER_OID;
+	};
+
+	non_trusted_nv_ctr: non_trusted_nv_ctr {
+		id  = <NON_TRUSTED_NV_CTR_ID>;
+		oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+	};
+};
+
+rot_keys {
+	swd_rot_pk: swd_rot_pk {
+		oid = SWD_ROT_PK_OID;
+	};
+	prot_pk: prot_pk {
+		oid = PROT_PK_OID;
+	};
+};
diff --git a/tools/cot_dt2c/tests/test_util.py b/tools/cot_dt2c/tests/test_util.py
new file mode 100644
index 0000000..b8e44d4
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_util.py
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import os
+import sys
+
+from cot_dt2c.cli import *
+from click.testing import CliRunner
+
+def get_script_path():
+    return os.path.dirname(os.path.realpath(sys.argv[0]))
+
+def test_convert():
+    runner = CliRunner()
+    test_file = get_script_path() + "/test.dtsi"
+    test_output = get_script_path() + "/test.c"
+
+    result = runner.invoke(convert_to_c, [test_file, test_output])
+    try:
+        assert result.output == ""
+    except:
+        print("test convert fail")
+
+    try:
+        os.remove(test_output)
+    except OSError:
+        pass
+
+if __name__=="__main__":
+    test_convert()