Merge "fix(versal2): add ufs specific features support" into integration
diff --git a/docs/plat/xilinx-versal-net.rst b/docs/plat/xilinx-versal-net.rst
index e9dd772..d22a46d 100644
--- a/docs/plat/xilinx-versal-net.rst
+++ b/docs/plat/xilinx-versal-net.rst
@@ -75,7 +75,7 @@
 | 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
 +---------------------------+-----------------------------------------------------------+
 
-PM SMC call ranges
+PM SMC call ranges for SiP SVC version 0.1
 --------------------------------------------------------
 
 +---------------------------+---------------------------------------------------------------------------+
@@ -84,6 +84,19 @@
 | 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
 +---------------------------+---------------------------------------------------------------------------+
 
+PM SMC call ranges for SiP SVC version 0.2
+--------------------------------------------------------
+
++---------------------------+---------------------------------------------------------------------------+
+|   SMC Function Identifier |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000FFF                | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform  |
+|                           | Management APIs to firmware                                               |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000A00-0xc2000AFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+|                           | specific TF-A APIs                                                        |
++---------------------------+---------------------------------------------------------------------------+
+
 SMC function IDs for SiP Service queries
 ----------------------------------------------
 
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
index 072329a..7185d91 100644
--- a/docs/plat/xilinx-versal.rst
+++ b/docs/plat/xilinx-versal.rst
@@ -14,11 +14,6 @@
 make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
 ```
 
-To build ATF for different platform (supported are "silicon"(default) and "versal_virt")
-```bash
-make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
-```
-
 To build bl32 TSP you have to rebuild bl31 too
 ```bash
 make CROSS_COMPILE=aarch64-none-elf- PLAT=versal SPD=tspd RESET_TO_BL31=1 bl31 bl32
@@ -51,11 +46,6 @@
     -   `pl011`, `pl011_0`: ARM pl011 UART 0
     -   `pl011_1`         : ARM pl011 UART 1
 
-*   `VERSAL_PLATFORM`: Select the platform. Options:
-    -   `versal_virt`	: Versal Virtual platform
-    -   `spp_itr6`	: SPP ITR6
-    -   `emu_itr6`	: EMU ITR6
-
 *   `CPU_PWRDWN_SGI`: Select the SGI for triggering CPU power down request to
                       secondary cores on receiving power down callback from
                       firmware. Options:
@@ -98,8 +88,8 @@
 | 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
 +---------------------------+-----------------------------------------------------------+
 
-PM SMC call ranges
-------------------
+PM SMC call ranges for SiP SVC version 0.1
+--------------------------------------------------------
 
 +---------------------------+---------------------------------------------------------------------------+
 |   SMC Function Identifier |  Service type                                                             |
@@ -107,6 +97,19 @@
 | 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
 +---------------------------+---------------------------------------------------------------------------+
 
+PM SMC call ranges for SiP SVC version 0.2
+--------------------------------------------------------
+
++---------------------------+---------------------------------------------------------------------------+
+|   SMC Function Identifier |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000FFF                | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform  |
+|                           | Management APIs to firmware                                               |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000A00-0xc2000AFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+|                           | specific TF-A APIs                                                        |
++---------------------------+---------------------------------------------------------------------------+
+
 SMC function IDs for SiP Service queries
 ----------------------------------------
 
diff --git a/docs/tools/transfer-list-compiler.rst b/docs/tools/transfer-list-compiler.rst
index c8ef7ac..fa660dc 100644
--- a/docs/tools/transfer-list-compiler.rst
+++ b/docs/tools/transfer-list-compiler.rst
@@ -59,6 +59,12 @@
     provided tag ID. It only checks that the tags provided as input are within
     range and that there is sufficient memory to include their TE's.
 
+You can also create a TL from a YAML config file.
+
+.. code ::
+
+    tlc create --from-yaml config.yaml tl.bin
+
 Printing the contents of a TL
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -186,9 +192,120 @@
 #. Ensures that the specified version is greater than or equal to the tool’s current version.
 #. Verifies alignment criteria for all TE’s.
 
+YAML Config File Format
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Example YAML config file:
+
+.. code::
+
+    execution_state: aarch32
+    has_checksum: true
+    max_size: 4096
+    entries:
+            - tag_id: 258  # entry point info
+              ep_info:
+                      args:
+                              - 67112968
+                              - 67112960
+                              - 0
+                              - 0
+                              - 0
+                              - 0
+                              - 0
+                              - 0
+                      h:
+                              attr: 8
+                              type: 1
+                              version: 2
+                      pc: 67239936
+                      spsr: 467
+            - tag_id: 3  # memory layout
+              addr: 8
+              size: 8
+            - tag_id: 1,  # fdt
+              blob_file_path: "fdt.bin",
+
+`max_size` defaults to `0x1000`, `execution_state` defaults to `aarch64`, and `has_checksum`
+defaults to `true`.
+
+The fields of the YAML file should match the fields in the specification for the transfer list. You
+don't need to give the hdr_size or data_size fields. For example, a memory layout entry would have
+an entry like:
+
+.. code::
+
+    tag_id: 3
+    addr: 8
+    size: 8
+
+You can input blob files by giving paths to the current working directory. You can do this for any
+TE type. For example, an FDT layout would have an entry like:
+
+.. code::
+
+    tag_id: 1,
+    blob_file_path: "fdt.bin",
+
+You can input C-types by giving its fields. For example, an entry point
+info entry would have an entry like:
+
+.. code::
+
+    tag_id: 258
+    ep_info:
+            args:
+                    - 67112968
+                    - 67112960
+                    - 0
+                    - 0
+            h:
+                    attr: 8
+                    type: 1
+                    version: 2
+            lr_svc: 0
+            pc: 67239936
+            spsr: 467
+
+You can give the name of the tag instead of the tag id number. The valid tag names are in the
+`transfer_entry_formats` dict in `tools/tlc/tlc/tl.py`_. Some examples are:
+
+* empty
+* fdt
+* hob_block
+* hob_list
+
+You can input the attr field of entry_point_info as a string of flag
+names separated by `|`. The names are taken from ep_info_exp.h in TF-A.
+For example:
+
+.. code::
+
+    has_checksum: true
+    max_size: 4096
+    entries:
+    - tag_id: 0x102
+      ep_info:
+        args:
+        - 67112976
+        - 67112960
+        - 0
+        - 0
+        - 0
+        - 0
+        - 0
+        - 0
+        h:
+          attr: EP_NON_SECURE | EP_ST_ENABLE
+          type: 1
+          version: 2
+        pc: 67239936
+        spsr: 965
+
 --------------
 
 *Copyright (c) 2024, Arm Limited. All rights reserved.*
 
 .. _Firmware Handoff specification: https://github.com/FirmwareHandoff/firmware_handoff/
 .. _tools/tlc/pyproject.toml: https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/heads/master/tools/tlc/pyproject.toml
+.. _tools/tlc/tlc/tl.py: https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/heads/master/tools/tlc/tlc/tl.py
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
index 4489892..cc82ddb 100644
--- a/drivers/arm/gic/v3/arm_gicv3_common.c
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -28,10 +28,13 @@
 void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
 {
 	uintptr_t gicr_base = 0;
+	unsigned int typer_reg;
 
 	assert(gicv3_driver_data);
 	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(gicv3_driver_data->gicd_base != 0U);
 
+	typer_reg = gicd_read_typer(gicv3_driver_data->gicd_base);
 	/*
 	 * The GICR_WAKER.Sleep bit should be set only when both
 	 * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
@@ -60,9 +63,14 @@
 	 */
 	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
 
-	/* Wait until the GICR_WAKER.Quiescent bit is set */
-	while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
-		;
+	/*
+	 * If LPIs are supported, wait until the GICR_WAKER.Quiescent bit is
+	 * set.
+	 */
+	if ((typer_reg & TYPER_LPIS) != 0U) {
+		while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+			;
+	}
 }
 
 /*
diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
index 7ae9624..d62eed7 100644
--- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
+++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
@@ -8,6 +8,10 @@
 #include <lib/utils_def.h>
 
 #define FXOSC_BASE_ADDR			(0x40050000UL)
+#define ARMPLL_BASE_ADDR		(0x40038000UL)
+#define ARM_DFS_BASE_ADDR		(0x40054000UL)
+#define CGM0_BASE_ADDR			(0x40030000UL)
+#define CGM1_BASE_ADDR			(0x40034000UL)
 
 /* FXOSC */
 #define FXOSC_CTRL(FXOSC)		((FXOSC) + 0x0UL)
@@ -26,4 +30,80 @@
 #define FXOSC_STAT(FXOSC)		((FXOSC) + 0x4UL)
 #define FXOSC_STAT_OSC_STAT		BIT_32(31U)
 
+/* PLL */
+#define PLLDIG_PLLCR(PLL)		((PLL) + 0x0UL)
+#define PLLDIG_PLLCR_PLLPD		BIT_32(31U)
+
+#define PLLDIG_PLLSR(PLL)		((PLL) + 0x4UL)
+#define PLLDIG_PLLSR_LOCK		BIT_32(2U)
+
+#define PLLDIG_PLLDV(PLL)		((PLL) + 0x8UL)
+#define PLLDIG_PLLDV_RDIV_OFFSET	12U
+#define PLLDIG_PLLDV_RDIV_MASK		GENMASK_32(14U, PLLDIG_PLLDV_RDIV_OFFSET)
+#define PLLDIG_PLLDV_RDIV_SET(VAL)	(PLLDIG_PLLDV_RDIV_MASK & \
+					((VAL) << PLLDIG_PLLDV_RDIV_OFFSET))
+#define PLLDIG_PLLDV_MFI_MASK		GENMASK_32(7U, 0U)
+#define PLLDIG_PLLDV_MFI(DIV)		(PLLDIG_PLLDV_MFI_MASK & (DIV))
+
+#define PLLDIG_PLLFD(PLL)		((PLL) + 0x10UL)
+#define PLLDIG_PLLFD_SMDEN		BIT_32(30U)
+#define PLLDIG_PLLFD_MFN_MASK		GENMASK_32(14U, 0U)
+#define PLLDIG_PLLFD_MFN_SET(VAL)	(PLLDIG_PLLFD_MFN_MASK & (VAL))
+
+#define PLLDIG_PLLCLKMUX(PLL)		((PLL) + 0x20UL)
+
+#define PLLDIG_PLLODIV(PLL, N)		((PLL) + 0x80UL + ((N) * 0x4UL))
+#define PLLDIG_PLLODIV_DE		BIT_32(31U)
+#define PLLDIG_PLLODIV_DIV_OFFSET	16U
+#define PLLDIG_PLLODIV_DIV_MASK		GENMASK_32(23U, PLLDIG_PLLODIV_DIV_OFFSET)
+#define PLLDIG_PLLODIV_DIV(VAL)		(((VAL) & PLLDIG_PLLODIV_DIV_MASK) >> \
+					 PLLDIG_PLLODIV_DIV_OFFSET)
+#define PLLDIG_PLLODIV_DIV_SET(VAL)	(PLLDIG_PLLODIV_DIV_MASK & ((VAL) << \
+					 PLLDIG_PLLODIV_DIV_OFFSET))
+
+/* MMC_CGM */
+#define CGM_MUXn_CSC(CGM_ADDR, MUX)	((CGM_ADDR) + 0x300UL + ((MUX) * 0x40UL))
+#define MC_CGM_MUXn_CSC_SELCTL_OFFSET	24U
+#define MC_CGM_MUXn_CSC_SELCTL_MASK	GENMASK_32(29U, MC_CGM_MUXn_CSC_SELCTL_OFFSET)
+#define MC_CGM_MUXn_CSC_SELCTL(val)	(MC_CGM_MUXn_CSC_SELCTL_MASK & ((val) \
+					 << MC_CGM_MUXn_CSC_SELCTL_OFFSET))
+#define MC_CGM_MUXn_CSC_CLK_SW		BIT_32(2U)
+#define MC_CGM_MUXn_CSC_SAFE_SW		BIT_32(3U)
+
+#define CGM_MUXn_CSS(CGM_ADDR, MUX)	((CGM_ADDR) + 0x304UL + ((MUX) * 0x40UL))
+#define MC_CGM_MUXn_CSS_SELSTAT_OFFSET	24U
+#define MC_CGM_MUXn_CSS_SELSTAT_MASK	GENMASK_32(29U, MC_CGM_MUXn_CSS_SELSTAT_OFFSET)
+#define MC_CGM_MUXn_CSS_SELSTAT(css)	((MC_CGM_MUXn_CSS_SELSTAT_MASK & (css))\
+					 >> MC_CGM_MUXn_CSS_SELSTAT_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG(css)	((MC_CGM_MUXn_CSS_SWTRG_MASK & (css)) \
+					 >> MC_CGM_MUXn_CSS_SWTRG_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG_OFFSET	17U
+#define MC_CGM_MUXn_CSS_SWTRG_MASK	GENMASK_32(19U, MC_CGM_MUXn_CSS_SWTRG_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG_SUCCESS	0x1U
+#define MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK	0x4U
+#define MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE	0x5U
+#define MC_CGM_MUXn_CSS_SWIP		BIT_32(16U)
+#define MC_CGM_MUXn_CSS_SAFE_SW		BIT_32(3U)
+
+/* DFS */
+#define DFS_PORTSR(DFS_ADDR)		((DFS_ADDR) + 0xCUL)
+#define DFS_PORTOLSR(DFS_ADDR)		((DFS_ADDR) + 0x10UL)
+#define DFS_PORTOLSR_LOL(N)		(BIT_32(N) & GENMASK_32(5U, 0U))
+#define DFS_PORTRESET(DFS_ADDR)		((DFS_ADDR) + 0x14UL)
+#define DFS_PORTRESET_MASK		GENMASK_32(5U, 0U)
+#define DFS_PORTRESET_SET(VAL)		(((VAL) & DFS_PORTRESET_MASK))
+
+#define DFS_CTL(DFS_ADDR)		((DFS_ADDR) + 0x18UL)
+#define DFS_CTL_RESET			BIT_32(1U)
+
+#define DFS_DVPORTn(DFS_ADDR, PORT)	((DFS_ADDR) + 0x1CUL + ((PORT) * 0x4UL))
+#define DFS_DVPORTn_MFI_MASK		GENMASK_32(15U, 8U)
+#define DFS_DVPORTn_MFI_SHIFT		8U
+#define DFS_DVPORTn_MFN_MASK		GENMASK_32(7U, 0U)
+#define DFS_DVPORTn_MFN_SHIFT		0U
+#define DFS_DVPORTn_MFI(MFI)		(((MFI) & DFS_DVPORTn_MFI_MASK) >> DFS_DVPORTn_MFI_SHIFT)
+#define DFS_DVPORTn_MFN(MFN)		(((MFN) & DFS_DVPORTn_MFN_MASK) >> DFS_DVPORTn_MFN_SHIFT)
+#define DFS_DVPORTn_MFI_SET(VAL)	(((VAL) << DFS_DVPORTn_MFI_SHIFT) & DFS_DVPORTn_MFI_MASK)
+#define DFS_DVPORTn_MFN_SET(VAL)	(((VAL) << DFS_DVPORTn_MFN_SHIFT) & DFS_DVPORTn_MFN_MASK)
+
 #endif /* S32CC_CLK_REGS_H */
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index f35a469..e23d928 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -10,13 +10,21 @@
 #include <common/debug.h>
 #include <drivers/clk.h>
 #include <lib/mmio.h>
+#include <s32cc-clk-ids.h>
 #include <s32cc-clk-modules.h>
 #include <s32cc-clk-utils.h>
 
 #define MAX_STACK_DEPTH		(15U)
 
+/* This is used for floating-point precision calculations. */
+#define FP_PRECISION		(100000000UL)
+
 struct s32cc_clk_drv {
 	uintptr_t fxosc_base;
+	uintptr_t armpll_base;
+	uintptr_t armdfs_base;
+	uintptr_t cgm0_base;
+	uintptr_t cgm1_base;
 };
 
 static int update_stack_depth(unsigned int *depth)
@@ -33,6 +41,10 @@
 {
 	static struct s32cc_clk_drv driver = {
 		.fxosc_base = FXOSC_BASE_ADDR,
+		.armpll_base = ARMPLL_BASE_ADDR,
+		.armdfs_base = ARM_DFS_BASE_ADDR,
+		.cgm0_base = CGM0_BASE_ADDR,
+		.cgm1_base = CGM1_BASE_ADDR,
 	};
 
 	return &driver;
@@ -67,6 +79,43 @@
 	return -EINVAL;
 }
 
+static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv,
+			 uintptr_t *base)
+{
+	int ret = 0;
+
+	switch (id) {
+	case S32CC_FXOSC:
+		*base = drv->fxosc_base;
+		break;
+	case S32CC_ARM_PLL:
+		*base = drv->armpll_base;
+		break;
+	case S32CC_ARM_DFS:
+		*base = drv->armdfs_base;
+		break;
+	case S32CC_CGM0:
+		*base = drv->cgm0_base;
+		break;
+	case S32CC_CGM1:
+		*base = drv->cgm1_base;
+		break;
+	case S32CC_FIRC:
+		break;
+	case S32CC_SIRC:
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret != 0) {
+		ERROR("Unknown clock source id: %u\n", id);
+	}
+
+	return ret;
+}
+
 static void enable_fxosc(const struct s32cc_clk_drv *drv)
 {
 	uintptr_t fxosc_base = drv->fxosc_base;
@@ -121,6 +170,593 @@
 	return ret;
 }
 
+static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq,
+			   uint32_t *mfi, uint32_t *mfn)
+
+{
+	unsigned long vco;
+	unsigned long mfn64;
+
+	/* FRAC-N mode */
+	*mfi = (uint32_t)(pll_vco / ref_freq);
+
+	/* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */
+	mfn64 = pll_vco % ref_freq;
+	mfn64 *= FP_PRECISION;
+	mfn64 /= ref_freq;
+	mfn64 *= 18432UL;
+	mfn64 /= FP_PRECISION;
+
+	if (mfn64 > UINT32_MAX) {
+		return -EINVAL;
+	}
+
+	*mfn = (uint32_t)mfn64;
+
+	vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL;
+	vco += (unsigned long)*mfi * FP_PRECISION;
+	vco *= ref_freq;
+	vco /= FP_PRECISION;
+
+	if (vco != pll_vco) {
+		ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n",
+		      pll_vco, vco);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll)
+{
+	const struct s32cc_clk_obj *source = pll->source;
+	const struct s32cc_clk *clk;
+
+	if (source == NULL) {
+		ERROR("Failed to identify PLL's parent\n");
+		return NULL;
+	}
+
+	if (source->type != s32cc_clk_t) {
+		ERROR("The parent of the PLL isn't a clock\n");
+		return NULL;
+	}
+
+	clk = s32cc_obj2clk(source);
+
+	if (clk->module == NULL) {
+		ERROR("The clock isn't connected to a module\n");
+		return NULL;
+	}
+
+	source = clk->module;
+
+	if ((source->type != s32cc_clkmux_t) &&
+	    (source->type != s32cc_shared_clkmux_t)) {
+		ERROR("The parent of the PLL isn't a MUX\n");
+		return NULL;
+	}
+
+	return s32cc_obj2clkmux(source);
+}
+
+static void disable_odiv(uintptr_t pll_addr, uint32_t div_index)
+{
+	mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
+}
+
+static void enable_odiv(uintptr_t pll_addr, uint32_t div_index)
+{
+	mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
+}
+
+static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs)
+{
+	uint32_t i;
+
+	for (i = 0; i < ndivs; i++) {
+		disable_odiv(pll_addr, i);
+	}
+}
+
+static void enable_pll_hw(uintptr_t pll_addr)
+{
+	/* Enable the PLL. */
+	mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0);
+
+	/* Poll until PLL acquires lock. */
+	while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) {
+	}
+}
+
+static void disable_pll_hw(uintptr_t pll_addr)
+{
+	mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD);
+}
+
+static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr,
+		       const struct s32cc_clk_drv *drv, uint32_t sclk_id,
+		       unsigned long sclk_freq)
+{
+	uint32_t rdiv = 1, mfi, mfn;
+	int ret;
+
+	ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn);
+	if (ret != 0) {
+		return -EINVAL;
+	}
+
+	/* Disable ODIVs*/
+	disable_odivs(pll_addr, pll->ndividers);
+
+	/* Disable PLL */
+	disable_pll_hw(pll_addr);
+
+	/* Program PLLCLKMUX */
+	mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id);
+
+	/* Program VCO */
+	mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr),
+			   PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK,
+			   PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi));
+
+	mmio_write_32(PLLDIG_PLLFD(pll_addr),
+		      PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN);
+
+	enable_pll_hw(pll_addr);
+
+	return ret;
+}
+
+static int enable_pll(const struct s32cc_clk_obj *module,
+		      const struct s32cc_clk_drv *drv,
+		      unsigned int *depth)
+{
+	const struct s32cc_pll *pll = s32cc_obj2pll(module);
+	const struct s32cc_clkmux *mux;
+	uintptr_t pll_addr = UL(0x0);
+	unsigned long sclk_freq;
+	uint32_t sclk_id;
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	mux = get_pll_mux(pll);
+	if (mux == NULL) {
+		return -EINVAL;
+	}
+
+	if (pll->instance != mux->module) {
+		ERROR("MUX type is not in sync with PLL ID\n");
+		return -EINVAL;
+	}
+
+	ret = get_base_addr(pll->instance, drv, &pll_addr);
+	if (ret != 0) {
+		ERROR("Failed to detect PLL instance\n");
+		return ret;
+	}
+
+	switch (mux->source_id) {
+	case S32CC_CLK_FIRC:
+		sclk_freq = 48U * MHZ;
+		sclk_id = 0;
+		break;
+	case S32CC_CLK_FXOSC:
+		sclk_freq = 40U * MHZ;
+		sclk_id = 1;
+		break;
+	default:
+		ERROR("Invalid source selection for PLL 0x%lx\n",
+		      pll_addr);
+		return -EINVAL;
+	};
+
+	return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq);
+}
+
+static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv)
+{
+	const struct s32cc_clk_obj *parent;
+
+	parent = pdiv->parent;
+	if (parent == NULL) {
+		ERROR("Failed to identify PLL divider's parent\n");
+		return NULL;
+	}
+
+	if (parent->type != s32cc_pll_t) {
+		ERROR("The parent of the divider is not a PLL instance\n");
+		return NULL;
+	}
+
+	return s32cc_obj2pll(parent);
+}
+
+static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc)
+{
+	uint32_t pllodiv;
+	uint32_t pdiv;
+
+	pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index));
+	pdiv = PLLDIG_PLLODIV_DIV(pllodiv);
+
+	if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) {
+		return;
+	}
+
+	if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) {
+		disable_odiv(pll_addr, div_index);
+	}
+
+	pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U);
+	mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv);
+
+	enable_odiv(pll_addr, div_index);
+}
+
+static int enable_pll_div(const struct s32cc_clk_obj *module,
+			  const struct s32cc_clk_drv *drv,
+			  unsigned int *depth)
+{
+	const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
+	uintptr_t pll_addr = 0x0ULL;
+	const struct s32cc_pll *pll;
+	uint32_t dc;
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	pll = get_div_pll(pdiv);
+	if (pll == NULL) {
+		ERROR("The parent of the PLL DIV is invalid\n");
+		return 0;
+	}
+
+	ret = get_base_addr(pll->instance, drv, &pll_addr);
+	if (ret != 0) {
+		ERROR("Failed to detect PLL instance\n");
+		return -EINVAL;
+	}
+
+	dc = (uint32_t)(pll->vco_freq / pdiv->freq);
+
+	config_pll_out_div(pll_addr, pdiv->index, dc);
+
+	return 0;
+}
+
+static int cgm_mux_clk_config(uintptr_t cgm_addr, uint32_t mux, uint32_t source,
+			      bool safe_clk)
+{
+	uint32_t css, csc;
+
+	css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
+
+	/* Already configured */
+	if ((MC_CGM_MUXn_CSS_SELSTAT(css) == source) &&
+	    (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
+	    ((css & MC_CGM_MUXn_CSS_SWIP) == 0U) && !safe_clk) {
+		return 0;
+	}
+
+	/* Ongoing clock switch? */
+	while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
+		MC_CGM_MUXn_CSS_SWIP) != 0U) {
+	}
+
+	csc = mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux));
+
+	/* Clear previous source. */
+	csc &= ~(MC_CGM_MUXn_CSC_SELCTL_MASK);
+
+	if (!safe_clk) {
+		/* Select the clock source and trigger the clock switch. */
+		csc |= MC_CGM_MUXn_CSC_SELCTL(source) | MC_CGM_MUXn_CSC_CLK_SW;
+	} else {
+		/* Switch to safe clock */
+		csc |= MC_CGM_MUXn_CSC_SAFE_SW;
+	}
+
+	mmio_write_32(CGM_MUXn_CSC(cgm_addr, mux), csc);
+
+	/* Wait for configuration bit to auto-clear. */
+	while ((mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux)) &
+		MC_CGM_MUXn_CSC_CLK_SW) != 0U) {
+	}
+
+	/* Is the clock switch completed? */
+	while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
+		MC_CGM_MUXn_CSS_SWIP) != 0U) {
+	}
+
+	/*
+	 * Check if the switch succeeded.
+	 * Check switch trigger cause and the source.
+	 */
+	css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
+	if (!safe_clk) {
+		if ((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
+		    (MC_CGM_MUXn_CSS_SELSTAT(css) == source)) {
+			return 0;
+		}
+
+		ERROR("Failed to change the source of mux %" PRIu32 " to %" PRIu32 " (CGM=%lu)\n",
+		      mux, source, cgm_addr);
+	} else {
+		if (((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK) ||
+		     (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE)) &&
+		     ((MC_CGM_MUXn_CSS_SAFE_SW & css) != 0U)) {
+			return 0;
+		}
+
+		ERROR("The switch of mux %" PRIu32 " (CGM=%lu) to safe clock failed\n",
+		      mux, cgm_addr);
+	}
+
+	return -EINVAL;
+}
+
+static int enable_cgm_mux(const struct s32cc_clkmux *mux,
+			  const struct s32cc_clk_drv *drv)
+{
+	uintptr_t cgm_addr = UL(0x0);
+	uint32_t mux_hw_clk;
+	int ret;
+
+	ret = get_base_addr(mux->module, drv, &cgm_addr);
+	if (ret != 0) {
+		return ret;
+	}
+
+	mux_hw_clk = (uint32_t)S32CC_CLK_ID(mux->source_id);
+
+	return cgm_mux_clk_config(cgm_addr, mux->index,
+				  mux_hw_clk, false);
+}
+
+static int enable_mux(const struct s32cc_clk_obj *module,
+		      const struct s32cc_clk_drv *drv,
+		      unsigned int *depth)
+{
+	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
+	const struct s32cc_clk *clk;
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (mux == NULL) {
+		return -EINVAL;
+	}
+
+	clk = s32cc_get_arch_clk(mux->source_id);
+	if (clk == NULL) {
+		ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n",
+		      mux->source_id, mux->index);
+		return -EINVAL;
+	}
+
+	switch (mux->module) {
+	/* PLL mux will be enabled by PLL setup */
+	case S32CC_ARM_PLL:
+		break;
+	case S32CC_CGM1:
+		ret = enable_cgm_mux(mux, drv);
+		break;
+	case S32CC_CGM0:
+		ret = enable_cgm_mux(mux, drv);
+		break;
+	default:
+		ERROR("Unknown mux parent type: %d\n", mux->module);
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+static int enable_dfs(const struct s32cc_clk_obj *module,
+		      const struct s32cc_clk_drv *drv,
+		      unsigned int *depth)
+{
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct s32cc_dfs *get_div_dfs(const struct s32cc_dfs_div *dfs_div)
+{
+	const struct s32cc_clk_obj *parent = dfs_div->parent;
+
+	if (parent->type != s32cc_dfs_t) {
+		ERROR("DFS DIV doesn't have a DFS as parent\n");
+		return NULL;
+	}
+
+	return s32cc_obj2dfs(parent);
+}
+
+static struct s32cc_pll *dfsdiv2pll(const struct s32cc_dfs_div *dfs_div)
+{
+	const struct s32cc_clk_obj *parent;
+	const struct s32cc_dfs *dfs;
+
+	dfs = get_div_dfs(dfs_div);
+	if (dfs == NULL) {
+		return NULL;
+	}
+
+	parent = dfs->parent;
+	if (parent->type != s32cc_pll_t) {
+		return NULL;
+	}
+
+	return s32cc_obj2pll(parent);
+}
+
+static int get_dfs_mfi_mfn(unsigned long dfs_freq, const struct s32cc_dfs_div *dfs_div,
+			   uint32_t *mfi, uint32_t *mfn)
+{
+	uint64_t factor64, tmp64, ofreq;
+	uint32_t factor32;
+
+	unsigned long in = dfs_freq;
+	unsigned long out = dfs_div->freq;
+
+	/**
+	 * factor = (IN / OUT) / 2
+	 * MFI = integer(factor)
+	 * MFN = (factor - MFI) * 36
+	 */
+	factor64 = ((((uint64_t)in) * FP_PRECISION) / ((uint64_t)out)) / 2ULL;
+	tmp64 = factor64 / FP_PRECISION;
+	if (tmp64 > UINT32_MAX) {
+		return -EINVAL;
+	}
+
+	factor32 = (uint32_t)tmp64;
+	*mfi = factor32;
+
+	tmp64 = ((factor64 - ((uint64_t)*mfi * FP_PRECISION)) * 36UL) / FP_PRECISION;
+	if (tmp64 > UINT32_MAX) {
+		return -EINVAL;
+	}
+
+	*mfn = (uint32_t)tmp64;
+
+	/* div_freq = in / (2 * (*mfi + *mfn / 36.0)) */
+	factor64 = (((uint64_t)*mfn) * FP_PRECISION) / 36ULL;
+	factor64 += ((uint64_t)*mfi) * FP_PRECISION;
+	factor64 *= 2ULL;
+	ofreq = (((uint64_t)in) * FP_PRECISION) / factor64;
+
+	if (ofreq != dfs_div->freq) {
+		ERROR("Failed to find MFI and MFN settings for DFS DIV freq %lu\n",
+		      dfs_div->freq);
+		ERROR("Nearest freq = %" PRIx64 "\n", ofreq);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int init_dfs_port(uintptr_t dfs_addr, uint32_t port,
+			 uint32_t mfi, uint32_t mfn)
+{
+	uint32_t portsr, portolsr;
+	uint32_t mask, old_mfi, old_mfn;
+	uint32_t dvport;
+	bool init_dfs;
+
+	dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, port));
+
+	old_mfi = DFS_DVPORTn_MFI(dvport);
+	old_mfn = DFS_DVPORTn_MFN(dvport);
+
+	portsr = mmio_read_32(DFS_PORTSR(dfs_addr));
+	portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
+
+	/* Skip configuration if it's not needed */
+	if (((portsr & BIT_32(port)) != 0U) &&
+	    ((portolsr & BIT_32(port)) == 0U) &&
+	    (mfi == old_mfi) && (mfn == old_mfn)) {
+		return 0;
+	}
+
+	init_dfs = (portsr == 0U);
+
+	if (init_dfs) {
+		mask = DFS_PORTRESET_MASK;
+	} else {
+		mask = DFS_PORTRESET_SET(BIT_32(port));
+	}
+
+	mmio_write_32(DFS_PORTOLSR(dfs_addr), mask);
+	mmio_write_32(DFS_PORTRESET(dfs_addr), mask);
+
+	while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & mask) != 0U) {
+	}
+
+	if (init_dfs) {
+		mmio_write_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
+	}
+
+	mmio_write_32(DFS_DVPORTn(dfs_addr, port),
+		      DFS_DVPORTn_MFI_SET(mfi) | DFS_DVPORTn_MFN_SET(mfn));
+
+	if (init_dfs) {
+		/* DFS clk enable programming */
+		mmio_clrbits_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
+	}
+
+	mmio_clrbits_32(DFS_PORTRESET(dfs_addr), BIT_32(port));
+
+	while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & BIT_32(port)) != BIT_32(port)) {
+	}
+
+	portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
+	if ((portolsr & DFS_PORTOLSR_LOL(port)) != 0U) {
+		ERROR("Failed to lock DFS divider\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int enable_dfs_div(const struct s32cc_clk_obj *module,
+			  const struct s32cc_clk_drv *drv,
+			  unsigned int *depth)
+{
+	const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
+	const struct s32cc_pll *pll;
+	const struct s32cc_dfs *dfs;
+	uintptr_t dfs_addr = 0UL;
+	uint32_t mfi, mfn;
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	dfs = get_div_dfs(dfs_div);
+	if (dfs == NULL) {
+		return -EINVAL;
+	}
+
+	pll = dfsdiv2pll(dfs_div);
+	if (pll == NULL) {
+		ERROR("Failed to identify DFS divider's parent\n");
+		return -EINVAL;
+	}
+
+	ret = get_base_addr(dfs->instance, drv, &dfs_addr);
+	if ((ret != 0) || (dfs_addr == 0UL)) {
+		return -EINVAL;
+	}
+
+	ret = get_dfs_mfi_mfn(pll->vco_freq, dfs_div, &mfi, &mfn);
+	if (ret != 0) {
+		return -EINVAL;
+	}
+
+	return init_dfs_port(dfs_addr, dfs_div->index, mfi, mfn);
+}
+
 static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
 {
 	const struct s32cc_clk_drv *drv = get_drv();
@@ -142,19 +778,27 @@
 	case s32cc_clk_t:
 		ret = enable_clk_module(module, drv, depth);
 		break;
+	case s32cc_pll_t:
+		ret = enable_pll(module, drv, depth);
+		break;
+	case s32cc_pll_out_div_t:
+		ret = enable_pll_div(module, drv, depth);
+		break;
 	case s32cc_clkmux_t:
-		ret = -ENOTSUP;
+		ret = enable_mux(module, drv, depth);
 		break;
 	case s32cc_shared_clkmux_t:
-		ret = -ENOTSUP;
+		ret = enable_mux(module, drv, depth);
 		break;
-	case s32cc_pll_t:
-		ret = -ENOTSUP;
-		break;
-	case s32cc_pll_out_div_t:
 	case s32cc_fixed_div_t:
 		ret = -ENOTSUP;
 		break;
+	case s32cc_dfs_t:
+		ret = enable_dfs(module, drv, depth);
+		break;
+	case s32cc_dfs_div_t:
+		ret = enable_dfs_div(module, drv, depth);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -340,6 +984,63 @@
 	return ret;
 }
 
+static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+			unsigned long *orate, unsigned int *depth)
+{
+	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
+	const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id);
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (clk == NULL) {
+		ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n",
+		      mux->index, mux->source_id);
+		return -EINVAL;
+	}
+
+	return set_module_rate(&clk->desc, rate, orate, depth);
+}
+
+static int set_dfs_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+			    unsigned long *orate, unsigned int *depth)
+{
+	struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
+	const struct s32cc_dfs *dfs;
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (dfs_div->parent == NULL) {
+		ERROR("Failed to identify DFS divider's parent\n");
+		return -EINVAL;
+	}
+
+	/* Sanity check */
+	dfs = s32cc_obj2dfs(dfs_div->parent);
+	if (dfs->parent == NULL) {
+		ERROR("Failed to identify DFS's parent\n");
+		return -EINVAL;
+	}
+
+	if ((dfs_div->freq != 0U) && (dfs_div->freq != rate)) {
+		ERROR("DFS DIV frequency was already set to %lu\n",
+		      dfs_div->freq);
+		return -EINVAL;
+	}
+
+	dfs_div->freq = rate;
+	*orate = rate;
+
+	return ret;
+}
+
 static int set_module_rate(const struct s32cc_clk_obj *module,
 			   unsigned long rate, unsigned long *orate,
 			   unsigned int *depth)
@@ -351,6 +1052,8 @@
 		return ret;
 	}
 
+	ret = -EINVAL;
+
 	switch (module->type) {
 	case s32cc_clk_t:
 		ret = set_clk_freq(module, rate, orate, depth);
@@ -368,11 +1071,18 @@
 		ret = set_fixed_div_freq(module, rate, orate, depth);
 		break;
 	case s32cc_clkmux_t:
+		ret = set_mux_freq(module, rate, orate, depth);
+		break;
 	case s32cc_shared_clkmux_t:
-		ret = -ENOTSUP;
+		ret = set_mux_freq(module, rate, orate, depth);
+		break;
+	case s32cc_dfs_t:
+		ERROR("Setting the frequency of a DFS is not allowed!");
+		break;
+	case s32cc_dfs_div_t:
+		ret = set_dfs_div_freq(module, rate, orate, depth);
 		break;
 	default:
-		ret = -EINVAL;
 		break;
 	}
 
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
index 039db2a..c4c73c7 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -43,6 +43,45 @@
 static struct s32cc_clk arm_pll_phi0_clk =
 	S32CC_FREQ_MODULE_CLK(arm_pll_phi0_div, 0, GHZ);
 
+/* ARM DFS */
+static struct s32cc_dfs armdfs =
+	S32CC_DFS_INIT(armpll, S32CC_ARM_DFS);
+static struct s32cc_dfs_div arm_dfs1_div =
+	S32CC_DFS_DIV_INIT(armdfs, 0);
+static struct s32cc_clk arm_dfs1_clk =
+	S32CC_FREQ_MODULE_CLK(arm_dfs1_div, 0, 800 * MHZ);
+
+/* MC_CGM0 */
+static struct s32cc_clkmux cgm0_mux0 =
+	S32CC_SHARED_CLKMUX_INIT(S32CC_CGM0, 0, 2,
+				 S32CC_CLK_FIRC,
+				 S32CC_CLK_ARM_PLL_DFS1, 0, 0, 0);
+static struct s32cc_clk cgm0_mux0_clk = S32CC_MODULE_CLK(cgm0_mux0);
+
+/* XBAR */
+static struct s32cc_clk xbar_2x_clk =
+	S32CC_CHILD_CLK(cgm0_mux0_clk, 48 * MHZ, 800 * MHZ);
+static struct s32cc_fixed_div xbar_div2 =
+	S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 2);
+static struct s32cc_clk xbar_clk =
+	S32CC_FREQ_MODULE_CLK(xbar_div2, 24 * MHZ, 400 * MHZ);
+static struct s32cc_fixed_div xbar_div4 =
+	S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 4);
+static struct s32cc_clk xbar_div2_clk =
+	S32CC_FREQ_MODULE_CLK(xbar_div4, 12 * MHZ, 200 * MHZ);
+static struct s32cc_fixed_div xbar_div6 =
+	S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 6);
+static struct s32cc_clk xbar_div3_clk =
+	S32CC_FREQ_MODULE_CLK(xbar_div6, 8 * MHZ, 133333333);
+static struct s32cc_fixed_div xbar_div8 =
+	S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 8);
+static struct s32cc_clk xbar_div4_clk =
+	S32CC_FREQ_MODULE_CLK(xbar_div8, 6 * MHZ, 100 * MHZ);
+static struct s32cc_fixed_div xbar_div12 =
+	S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 12);
+static struct s32cc_clk xbar_div6_clk =
+	S32CC_FREQ_MODULE_CLK(xbar_div12, 4 * MHZ, 66666666);
+
 /* MC_CGM1 */
 static struct s32cc_clkmux cgm1_mux0 =
 	S32CC_SHARED_CLKMUX_INIT(S32CC_CGM1, 0, 3,
@@ -68,13 +107,15 @@
 	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[5] = {
+static struct s32cc_clk *s32cc_hw_clk_list[13] = {
 	/* Oscillators */
 	[S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk,
 	[S32CC_CLK_ID(S32CC_CLK_SIRC)] = &sirc_clk,
 	[S32CC_CLK_ID(S32CC_CLK_FXOSC)] = &fxosc_clk,
 	/* ARM PLL */
 	[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,
 };
 
 static struct s32cc_clk_array s32cc_hw_clocks = {
@@ -83,10 +124,19 @@
 	.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
 };
 
-static struct s32cc_clk *s32cc_arch_clk_list[6] = {
+static struct s32cc_clk *s32cc_arch_clk_list[13] = {
 	/* 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,
+	/* MC_CGM0 */
+	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX0)] = &cgm0_mux0_clk,
+	/* XBAR */
+	[S32CC_CLK_ID(S32CC_CLK_XBAR_2X)] = &xbar_2x_clk,
+	[S32CC_CLK_ID(S32CC_CLK_XBAR)] = &xbar_clk,
+	[S32CC_CLK_ID(S32CC_CLK_XBAR_DIV2)] = &xbar_div2_clk,
+	[S32CC_CLK_ID(S32CC_CLK_XBAR_DIV3)] = &xbar_div3_clk,
+	[S32CC_CLK_ID(S32CC_CLK_XBAR_DIV4)] = &xbar_div4_clk,
+	[S32CC_CLK_ID(S32CC_CLK_XBAR_DIV6)] = &xbar_div6_clk,
 	/* MC_CGM1 */
 	[S32CC_CLK_ID(S32CC_CLK_MC_CGM1_MUX0)] = &cgm1_mux0_clk,
 	/* A53 */
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index ac1f7d0..2c256a5 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -11,39 +11,129 @@
 #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)
 
-int s32cc_init_early_clks(void)
+static int enable_fxosc_clk(void)
 {
 	int ret;
 
-	s32cc_clk_register_drv();
+	ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_FXOSC);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
+
+static int enable_arm_pll(void)
+{
+	int ret;
 
 	ret = clk_set_parent(S32CC_CLK_ARM_PLL_MUX, S32CC_CLK_FXOSC);
 	if (ret != 0) {
 		return ret;
 	}
 
+	ret = clk_set_rate(S32CC_CLK_ARM_PLL_VCO, S32CC_ARM_PLL_VCO_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_rate(S32CC_CLK_ARM_PLL_PHI0, S32CC_ARM_PLL_PHI0_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_ARM_PLL_VCO);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_ARM_PLL_PHI0);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
+
+static int enable_a53_clk(void)
+{
+	int ret;
+
 	ret = clk_set_parent(S32CC_CLK_MC_CGM1_MUX0, S32CC_CLK_ARM_PLL_PHI0);
 	if (ret != 0) {
 		return ret;
 	}
 
-	ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
+	ret = clk_set_rate(S32CC_CLK_A53_CORE, S32CC_A53_FREQ, NULL);
 	if (ret != 0) {
 		return ret;
 	}
 
-	ret = clk_set_rate(S32CC_CLK_ARM_PLL_VCO, S32CC_ARM_PLL_VCO_FREQ, NULL);
+	ret = clk_enable(S32CC_CLK_A53_CORE);
 	if (ret != 0) {
 		return ret;
 	}
 
-	ret = clk_set_rate(S32CC_CLK_ARM_PLL_PHI0, S32CC_ARM_PLL_PHI0_FREQ, NULL);
+	return ret;
+}
+
+static int enable_xbar_clk(void)
+{
+	int ret;
+
+	ret = clk_set_parent(S32CC_CLK_MC_CGM0_MUX0, S32CC_CLK_ARM_PLL_DFS1);
 	if (ret != 0) {
 		return ret;
 	}
 
-	ret = clk_enable(S32CC_CLK_FXOSC);
+	ret = clk_set_rate(S32CC_CLK_XBAR_2X, S32CC_XBAR_2X_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_ARM_PLL_DFS1);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_XBAR_2X);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
+
+int s32cc_init_early_clks(void)
+{
+	int ret;
+
+	s32cc_clk_register_drv();
+
+	ret = enable_fxosc_clk();
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = enable_arm_pll();
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = enable_a53_clk();
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = enable_xbar_clk();
 	if (ret != 0) {
 		return ret;
 	}
diff --git a/drivers/nxp/gpio/nxp_gpio.c b/drivers/nxp/gpio/nxp_gpio.c
index 28c9db9..b477b79 100644
--- a/drivers/nxp/gpio/nxp_gpio.c
+++ b/drivers/nxp/gpio/nxp_gpio.c
@@ -28,8 +28,8 @@
 		ERROR("GPIO is not initialized.\n");
 		return GPIO_FAILURE;
 	}
-
-	gpdir = gpio_base_addr + GPDIR_REG_OFFSET;
+	/* Divide by 4 since we're operating on 32-bit pointer addresses. */
+	gpdir = gpio_base_addr + (GPDIR_REG_OFFSET >> 2);
 	gpdat = gpio_base_addr + (GPDAT_REG_OFFSET >> 2);
 
 	/*
@@ -67,8 +67,9 @@
 		return GPIO_FAILURE;
 	}
 
-	gpdir = gpio_base_addr + GPDIR_REG_OFFSET;
-	gpdat = gpio_base_addr + GPDAT_REG_OFFSET;
+	/* Divide by 4 since we're operating on 32-bit pointer addresses. */
+	gpdir = gpio_base_addr + (GPDIR_REG_OFFSET >> 2);
+	gpdat = gpio_base_addr + (GPDAT_REG_OFFSET >> 2);
 
 	/*
 	 * Reset the corresponding bit in direction and data register
diff --git a/fdts/tc-base.dtsi b/fdts/tc-base.dtsi
index 2e03be2..fc6fe78 100644
--- a/fdts/tc-base.dtsi
+++ b/fdts/tc-base.dtsi
@@ -265,9 +265,22 @@
 		method = "smc";
 	};
 
-	cpu-pmu {
-		compatible = "arm,armv8-pmuv3";
-		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+	cpu-pmu-little {
+		compatible = LIT_CPU_PMU_COMPATIBLE;
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH &ppi_partition_little>;
+		status = "okay";
+	};
+
+	cpu-pmu-mid {
+		compatible = MID_CPU_PMU_COMPATIBLE;
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH &ppi_partition_mid>;
+		status = "okay";
+	};
+
+	cpu-pmu-big {
+		compatible = BIG_CPU_PMU_COMPATIBLE;
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH &ppi_partition_big>;
+		status = "okay";
 	};
 
 	sram: sram@6000000 {
@@ -290,7 +303,7 @@
 		clocks = <&soc_refclk>;
 		clock-names = "apb_pclk";
 		#mbox-cells = <MHU_MBOX_CELLS>;
-		interrupts = <GIC_SPI MHU_RX_INT_NUM IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI MHU_RX_INT_NUM IRQ_TYPE_LEVEL_HIGH 0>;
 		interrupt-names = MHU_RX_INT_NAME;
 	};
 
@@ -332,23 +345,35 @@
 	gic: interrupt-controller@GIC_CTRL_ADDR {
 		compatible = "arm,gic-v3";
 		#address-cells = <2>;
-		#interrupt-cells = <3>;
+		#interrupt-cells = <4>;
 		#size-cells = <2>;
 		ranges;
 		interrupt-controller;
 		reg = <0x0 0x30000000 0 0x10000>, /* GICD */
 		      <0x0 0x30080000 0 GIC_GICR_OFFSET>; /* GICR */
-		interrupts = <GIC_PPI 0x9 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_PPI 0x9 IRQ_TYPE_LEVEL_LOW 0>;
 	};
 
 	timer {
 		compatible = "arm,armv8-timer";
-		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
-			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
-			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
-			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
 	};
 
+	spe-pmu-mid {
+		compatible = "arm,statistical-profiling-extension-v1";
+		interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_HIGH &ppi_partition_mid>;
+		status = "disabled";
+	};
+
+	spe-pmu-big {
+		compatible = "arm,statistical-profiling-extension-v1";
+		interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_HIGH &ppi_partition_big>;
+		status = "disabled";
+	};
+
 	soc_refclk: refclk {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -374,7 +399,7 @@
 	os_uart: serial@2a400000 {
 		compatible = "arm,pl011", "arm,primecell";
 		reg = <0x0 0x2A400000 0x0 UART_OFFSET>;
-		interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&soc_uartclk>, <&soc_refclk>;
 		clock-names = "uartclk", "apb_pclk";
 		status = "okay";
@@ -414,7 +439,7 @@
 
 	ethernet: ethernet@18000000 {
 		reg = <0x0 0x18000000 0x0 0x10000>;
-		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>;
 
 		reg-io-width = <2>;
 		smsc,irq-push-pull;
@@ -446,8 +471,8 @@
 	mmci: mmci@1c050000 {
 		compatible = "arm,pl180", "arm,primecell";
 		reg = <0x0 0x001c050000 0x0 0x1000>;
-		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>;
 		wp-gpios = <&sysreg 1 0>;
 		bus-width = <4>;
 		max-frequency = <25000000>;
@@ -471,9 +496,9 @@
 	gpu: gpu@2d000000 {
 		compatible = "arm,mali-midgard";
 		reg = <0x0 0x2d000000 0x0 0x200000>;
-		interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH 0>;
 		interrupt-names = "JOB", "MMU", "GPU";
 		clocks = <&gpu_core_clk>;
 		clock-names = "shadercores";
@@ -507,10 +532,10 @@
 	smmu_600: smmu@2ce00000 {
 		compatible = "arm,smmu-v3";
 		reg = <0 0x2ce00000 0 0x20000>;
-		interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 76 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 77 IRQ_TYPE_EDGE_RISING>;
+		interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 74 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 76 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 77 IRQ_TYPE_EDGE_RISING 0>;
 		interrupt-names = "eventq", "priq", "cmdq-sync", "gerror";
 		#iommu-cells = <1>;
 		status = "disabled";
@@ -520,9 +545,9 @@
 		#iommu-cells = <1>;
 		compatible = "arm,smmu-v3";
 		reg = <0x0 0x3f000000 0x0 0x5000000>;
-		interrupts = <GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 230 IRQ_TYPE_EDGE_RISING>;
+		interrupts = <GIC_SPI 228 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 229 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 230 IRQ_TYPE_EDGE_RISING 0>;
 		interrupt-names = "eventq", "cmdq-sync", "gerror";
 		dma-coherent;
 		status = "disabled";
@@ -532,9 +557,9 @@
 		#iommu-cells = <1>;
 		compatible = "arm,smmu-v3";
 		reg = <HI(0x4002a00000) LO(0x4002a00000) 0x0 0x5000000>;
-		interrupts = <GIC_SPI 481 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 482 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 483 IRQ_TYPE_EDGE_RISING>;
+		interrupts = <GIC_SPI 481 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 482 IRQ_TYPE_EDGE_RISING 0>,
+			     <GIC_SPI 483 IRQ_TYPE_EDGE_RISING 0>;
 		interrupt-names = "eventq", "cmdq-sync", "gerror";
 		dma-coherent;
 		status = "disabled";
@@ -545,7 +570,7 @@
 		#size-cells = <0>;
 		compatible = "arm,mali-d71";
 		reg = <HI(ADDRESSIFY(DPU_ADDR)) LO(ADDRESSIFY(DPU_ADDR)) 0 0x20000>;
-		interrupts = <GIC_SPI DPU_IRQ IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI DPU_IRQ IRQ_TYPE_LEVEL_HIGH 0>;
 		interrupt-names = "DPU";
 		DPU_CLK_ATTR1;
 
@@ -630,7 +655,7 @@
 
 	trbe {
 		compatible = "arm,trace-buffer-extension";
-		interrupts = <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW 0>;
 	};
 
 	trusty {
diff --git a/fdts/tc-fvp.dtsi b/fdts/tc-fvp.dtsi
index 9f3a9ac..1e14f0b 100644
--- a/fdts/tc-fvp.dtsi
+++ b/fdts/tc-fvp.dtsi
@@ -54,7 +54,7 @@
 	rtc@1c170000 {
 		compatible = "arm,pl031", "arm,primecell";
 		reg = <0x0 0x1C170000 0x0 0x1000>;
-		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&soc_refclk>;
 		clock-names = "apb_pclk";
 	};
@@ -62,7 +62,7 @@
 	kmi@1c060000 {
 		compatible = "arm,pl050", "arm,primecell";
 		reg = <0x0 0x001c060000 0x0 0x1000>;
-		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
 		clock-names = "KMIREFCLK", "apb_pclk";
 	};
@@ -70,7 +70,7 @@
 	kmi@1c070000 {
 		compatible = "arm,pl050", "arm,primecell";
 		reg = <0x0 0x001c070000 0x0 0x1000>;
-		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
 		clock-names = "KMIREFCLK", "apb_pclk";
 	};
@@ -79,6 +79,6 @@
 		compatible = "virtio,mmio";
 		reg = <0x0 0x1c130000 0x0 0x200>;
 		/* spec lists this wrong */
-		interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH 0>;
 	};
 };
diff --git a/fdts/tc2.dts b/fdts/tc2.dts
index 4946aca..ae37ce3 100644
--- a/fdts/tc2.dts
+++ b/fdts/tc2.dts
@@ -31,6 +31,10 @@
 #define MHU_RX_INT_NUM			317
 #define MHU_RX_INT_NAME			"mhu_rx"
 
+#define LIT_CPU_PMU_COMPATIBLE		"arm,cortex-a520-pmu"
+#define MID_CPU_PMU_COMPATIBLE		"arm,cortex-a720-pmu"
+#define BIG_CPU_PMU_COMPATIBLE		"arm,cortex-x4-pmu"
+
 #define MPAM_ADDR			0x1 0x00010000 /* 0x1_0001_0000 */
 #define UARTCLK_FREQ			5000000
 
@@ -193,22 +197,10 @@
 	};
 #endif /* TARGET_FLAVOUR_FPGA */
 
-	cpu-pmu {
-#if TARGET_FLAVOUR_FPGA
-		interrupt-affinity = <&CPU0>,  <&CPU1>,  <&CPU2>,  <&CPU3>,
-				     <&CPU4>,  <&CPU5>,  <&CPU6>,  <&CPU7>,
-				     <&CPU8>,  <&CPU9>,  <&CPU10>, <&CPU11>,
-				     <&CPU12>, <&CPU13>;
-#else
-		interrupt-affinity = <&CPU0>,  <&CPU1>,  <&CPU2>,  <&CPU3>,
-				     <&CPU4>,  <&CPU5>,  <&CPU6>,  <&CPU7>;
-#endif
-	};
-
 	cmn-pmu {
 		compatible = "arm,ci-700";
 		reg = <0x0 0x50000000 0x0 0x10000000>;
-		interrupts = <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH 0>;
 	};
 
 	mbox_db_rx: mhu@MHU_RX_ADDR {
@@ -237,6 +229,36 @@
 		};
 	};
 
+	gic: interrupt-controller@GIC_CTRL_ADDR {
+		ppi-partitions {
+			ppi_partition_little: interrupt-partition-0 {
+				affinity = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>;
+			};
+
+#if TARGET_FLAVOUR_FVP
+			ppi_partition_mid: interrupt-partition-1 {
+				affinity = <&CPU4>, <&CPU5>, <&CPU6>;
+			};
+
+			ppi_partition_big: interrupt-partition-2 {
+				affinity = <&CPU7>;
+			};
+#elif TARGET_FLAVOUR_FPGA
+			ppi_partition_mid: interrupt-partition-1 {
+				affinity = <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>, <&CPU8>;
+			};
+
+			ppi_partition_big: interrupt-partition-2 {
+				affinity = <&CPU9>, <&CPU10>, <&CPU11>, <&CPU12>, <&CPU13>;
+			};
+#endif
+		};
+	};
+
+	spe-pmu-big {
+		status = "okay";
+	};
+
 	smmu_700: iommu@3f000000 {
 		status = "okay";
 	};
diff --git a/fdts/tc3.dts b/fdts/tc3.dts
index 71b3cb1..58c8edc 100644
--- a/fdts/tc3.dts
+++ b/fdts/tc3.dts
@@ -25,6 +25,10 @@
 #define MHU_RX_INT_NUM			300
 #define MHU_RX_INT_NAME			"combined-mbx"
 
+#define LIT_CPU_PMU_COMPATIBLE		"arm,cortex-a520-pmu"
+#define MID_CPU_PMU_COMPATIBLE		"arm,cortex-a725-pmu"
+#define BIG_CPU_PMU_COMPATIBLE		"arm,cortex-x925-pmu"
+
 #define MPAM_ADDR			0x0 0x5f010000 /* 0x5f01_0000 */
 #define UARTCLK_FREQ			3750000
 
@@ -67,11 +71,6 @@
 		};
 	};
 
-	cpu-pmu {
-		interrupt-affinity = <&CPU0>,  <&CPU1>,  <&CPU2>,  <&CPU3>,
-				     <&CPU4>,  <&CPU5>,  <&CPU6>,  <&CPU7>;
-	};
-
 	cs-pmu@0 {
 		compatible = "arm,coresight-pmu";
 		reg = <0x0 MCN_PMU_ADDR(0) 0x0 0xffc>;
@@ -92,11 +91,24 @@
 		reg = <0x0 MCN_PMU_ADDR(3) 0x0 0xffc>;
 	};
 
+	spe-pmu-mid {
+		status = "okay";
+	};
+
+	spe-pmu-big {
+		status = "okay";
+	};
+
 	dsu-pmu {
 		compatible = "arm,dsu-pmu";
 		cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>;
 	};
 
+	ni-pmu {
+		compatible = "arm,ni-tower";
+		reg = <0x0 0x4f000000 0x0 0x4000000>;
+	};
+
 	sram: sram@6000000 {
 		cpu_scp_scmi_p2a: scp-shmem@80 {
 			compatible = "arm,scmi-shmem";
@@ -111,6 +123,22 @@
 		};
 	};
 
+	gic: interrupt-controller@GIC_CTRL_ADDR {
+		ppi-partitions {
+			ppi_partition_little: interrupt-partition-0 {
+				affinity = <&CPU0>, <&CPU1>;
+			};
+
+			ppi_partition_mid: interrupt-partition-1 {
+				affinity = <&CPU2>, <&CPU3>, <&CPU4>, <&CPU5>;
+			};
+
+			ppi_partition_big: interrupt-partition-2 {
+				affinity = <&CPU6>, <&CPU7>;
+			};
+		};
+	};
+
 #if TARGET_FLAVOUR_FVP
 	smmu_700: iommu@3f000000 {
 		status = "okay";
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
index 8e39529..abe34a4 100644
--- a/include/arch/aarch32/arch_features.h
+++ b/include/arch/aarch32/arch_features.h
@@ -16,6 +16,7 @@
 	((unsigned int)(((reg) >> (feat)) & mask))
 
 #define CREATE_FEATURE_SUPPORTED(name, read_func, guard)			\
+__attribute__((always_inline))							\
 static inline bool is_ ## name ## _supported(void)				\
 {										\
 	if ((guard) == FEAT_STATE_DISABLED) {					\
@@ -28,6 +29,7 @@
 }
 
 #define CREATE_FEATURE_PRESENT(name, idreg, idfield, mask, idval)		\
+__attribute__((always_inline))							\
 static inline bool is_ ## name ## _present(void)				\
 {										\
 	return (ISOLATE_FIELD(read_ ## idreg(), idfield, mask) >= idval) 	\
@@ -68,6 +70,7 @@
  */
 
 /* GENTIMER */
+__attribute__((always_inline))
 static inline bool is_armv7_gentimer_present(void)
 {
 	return ISOLATE_FIELD(read_id_pfr1(), ID_PFR1_GENTIMER_SHIFT,
@@ -111,6 +114,7 @@
 		      ID_DFR0_PERFMON_MASK, 3U)
 
 /* FEAT_MTPMU */
+__attribute__((always_inline))
 static inline bool is_feat_mtpmu_present(void)
 {
 	unsigned int mtpmu = ISOLATE_FIELD(read_id_dfr1(), ID_DFR1_MTPMU_SHIFT,
@@ -124,39 +128,71 @@
  * code. In fact, EL2 context switching is only needed for AArch64 (since
  * there is no secure AArch32 EL2), so just disable these features here.
  */
+__attribute__((always_inline))
 static inline bool is_feat_twed_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_ecv_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_ecv_v2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_csv2_2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_csv2_3_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_ras_supported(void) { return false; }
 
 /* The following features are supported in AArch64 only. */
+__attribute__((always_inline))
 static inline bool is_feat_vhe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sel2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_fgt_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_tcr2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_spe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_rng_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_gcs_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_mte2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_mpam_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_hcx_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sve_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_brbe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_trbe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_nv2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sme_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sme2_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_s2poe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_s1poe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sxpoe_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_s2pie_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_s1pie_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sxpie_supported(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_uao_present(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_nmi_present(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_ebep_present(void) { return false; }
+__attribute__((always_inline))
 static inline bool is_feat_sebep_present(void) { return false; }
 
 #endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index c63eec8..f03c9d5 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -16,6 +16,7 @@
 	((unsigned int)(((reg) >> (feat)) & mask))
 
 #define CREATE_FEATURE_SUPPORTED(name, read_func, guard)			\
+__attribute__((always_inline))							\
 static inline bool is_ ## name ## _supported(void)				\
 {										\
 	if ((guard) == FEAT_STATE_DISABLED) {					\
@@ -28,6 +29,7 @@
 }
 
 #define CREATE_FEATURE_PRESENT(name, idreg, idfield, mask, idval)		\
+__attribute__((always_inline))							\
 static inline bool is_ ## name ## _present(void)				\
 {										\
 	return (ISOLATE_FIELD(read_ ## idreg(), idfield, mask) >= idval) 	\
@@ -134,6 +136,7 @@
  * +----------------------------+
  */
 
+__attribute__((always_inline))
 static inline bool is_armv7_gentimer_present(void)
 {
 	/* The Generic Timer is always present in an ARMv8-A implementation */
@@ -162,6 +165,7 @@
 			(ID_AA64ISAR2_APA3_MASK << ID_AA64ISAR2_APA3_SHIFT)), 1U)
 
 /* PAUTH */
+__attribute__((always_inline))
 static inline bool is_armv8_3_pauth_present(void)
 {
 	uint64_t mask_id_aa64isar1 =
@@ -244,6 +248,7 @@
 CREATE_FEATURE_FUNCS(feat_s1poe, id_aa64mmfr3_el1, ID_AA64MMFR3_EL1_S1POE_SHIFT,
 		     ID_AA64MMFR3_EL1_S1POE_MASK, 1U, ENABLE_FEAT_S1POE)
 
+__attribute__((always_inline))
 static inline bool is_feat_sxpoe_supported(void)
 {
 	return is_feat_s1poe_supported() || is_feat_s2poe_supported();
@@ -257,6 +262,7 @@
 CREATE_FEATURE_FUNCS(feat_s1pie, id_aa64mmfr3_el1, ID_AA64MMFR3_EL1_S1PIE_SHIFT,
 		     ID_AA64MMFR3_EL1_S1PIE_MASK, 1U, ENABLE_FEAT_S1PIE)
 
+__attribute__((always_inline))
 static inline bool is_feat_sxpie_supported(void)
 {
 	return is_feat_s1pie_supported() || is_feat_s2pie_supported();
@@ -283,6 +289,7 @@
  * 0x11: v1.1 Armv8.4 or later
  *
  */
+__attribute__((always_inline))
 static inline bool is_feat_mpam_present(void)
 {
 	unsigned int ret = (unsigned int)((((read_id_aa64pfr0_el1() >>
@@ -398,6 +405,7 @@
  * Function to get hardware granularity support
  ******************************************************************************/
 
+__attribute__((always_inline))
 static inline bool is_feat_tgran4K_present(void)
 {
 	unsigned int tgranx = ISOLATE_FIELD(read_id_aa64mmfr0_el1(),
@@ -408,6 +416,7 @@
 CREATE_FEATURE_PRESENT(feat_tgran16K, id_aa64mmfr0_el1, ID_AA64MMFR0_EL1_TGRAN16_SHIFT,
 		       ID_AA64MMFR0_EL1_TGRAN16_MASK, TGRAN16_IMPLEMENTED)
 
+__attribute__((always_inline))
 static inline bool is_feat_tgran64K_present(void)
 {
 	unsigned int tgranx = ISOLATE_FIELD(read_id_aa64mmfr0_el1(),
@@ -420,6 +429,7 @@
 		      ID_AA64DFR0_PMUVER_MASK, 1U)
 
 /* FEAT_MTPMU */
+__attribute__((always_inline))
 static inline bool is_feat_mtpmu_present(void)
 {
 	unsigned int mtpmu = ISOLATE_FIELD(read_id_aa64dfr0_el1(), ID_AA64DFR0_MTPMU_SHIFT,
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index bfda31b..ca46eb1 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -150,6 +150,7 @@
 /* GICD_TYPER shifts and masks */
 #define	TYPER_ESPI		U(1 << 8)
 #define	TYPER_DVIS		U(1 << 18)
+#define	TYPER_LPIS		U(1 << 17)
 #define	TYPER_ESPI_RANGE_MASK	U(0x1f)
 #define	TYPER_ESPI_RANGE_SHIFT	U(27)
 #define	TYPER_ESPI_RANGE	U(TYPER_ESPI_MASK << TYPER_ESPI_SHIFT)
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
index 633f173..b95cd32 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
@@ -78,4 +78,13 @@
 #define S32CC_CLK_A53_CORE_DIV2			S32CC_ARCH_CLK(4)
 #define S32CC_CLK_A53_CORE_DIV10		S32CC_ARCH_CLK(5)
 
+/* XBAR clock*/
+#define S32CC_CLK_MC_CGM0_MUX0			S32CC_ARCH_CLK(6)
+#define S32CC_CLK_XBAR_2X			S32CC_ARCH_CLK(7)
+#define S32CC_CLK_XBAR				S32CC_ARCH_CLK(8)
+#define S32CC_CLK_XBAR_DIV2			S32CC_ARCH_CLK(9)
+#define S32CC_CLK_XBAR_DIV3			S32CC_ARCH_CLK(10)
+#define S32CC_CLK_XBAR_DIV4			S32CC_ARCH_CLK(11)
+#define S32CC_CLK_XBAR_DIV6			S32CC_ARCH_CLK(12)
+
 #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 41fc6f4..703713b 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -17,6 +17,8 @@
 	s32cc_clk_t,
 	s32cc_pll_t,
 	s32cc_pll_out_div_t,
+	s32cc_dfs_t,
+	s32cc_dfs_div_t,
 	s32cc_clkmux_t,
 	s32cc_shared_clkmux_t,
 	s32cc_fixed_div_t,
@@ -27,6 +29,8 @@
 	S32CC_FXOSC,
 	S32CC_SIRC,
 	S32CC_ARM_PLL,
+	S32CC_ARM_DFS,
+	S32CC_CGM0,
 	S32CC_CGM1,
 };
 
@@ -122,6 +126,38 @@
 	.index = (INDEX),                      \
 }
 
+struct s32cc_dfs {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *parent;
+	enum s32cc_clk_source instance;
+	uintptr_t base;
+};
+
+#define S32CC_DFS_INIT(PARENT, INSTANCE) \
+{                                        \
+	.desc = {                        \
+		.type = s32cc_dfs_t,     \
+	},                               \
+	.parent = &(PARENT).desc,        \
+	.instance = (INSTANCE),          \
+}
+
+struct s32cc_dfs_div {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *parent;
+	uint32_t index;
+	unsigned long freq;
+};
+
+#define S32CC_DFS_DIV_INIT(PARENT, INDEX) \
+{                                         \
+	.desc = {                         \
+		.type = s32cc_dfs_div_t,  \
+	},                                \
+	.parent = &(PARENT).desc,         \
+	.index = (INDEX),                 \
+}
+
 struct s32cc_fixed_div {
 	struct s32cc_clk_obj desc;
 	struct s32cc_clk_obj *parent;
@@ -151,22 +187,26 @@
 	size_t n_clks;
 };
 
-#define S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F) \
-{                                                      \
-	.desc = {                                      \
-		.type = s32cc_clk_t,                   \
-	},                                             \
-	.module = &(PARENT_MODULE).desc,               \
-	.min_freq = (MIN_F),                           \
-	.max_freq = (MAX_F),                           \
+#define S32CC_FREQ_CLK(PARENT_MODULE, PARENT, MIN_F, MAX_F) \
+{                                                           \
+	.desc = {                                           \
+		.type = s32cc_clk_t,                        \
+	},                                                  \
+	.pclock = (PARENT),                                 \
+	.module = (PARENT_MODULE),                          \
+	.min_freq = (MIN_F),                                \
+	.max_freq = (MAX_F),                                \
 }
 
 #define S32CC_FREQ_MODULE_CLK(PARENT_MODULE, MIN_F, MAX_F) \
-	S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F)
+	S32CC_FREQ_CLK(&(PARENT_MODULE).desc, NULL, MIN_F, MAX_F)
 
 #define S32CC_MODULE_CLK(PARENT_MODULE) \
 	S32CC_FREQ_MODULE_CLK(PARENT_MODULE, 0, 0)
 
+#define S32CC_CHILD_CLK(PARENT, MIN_F, MAX_F) \
+	S32CC_FREQ_CLK(NULL, &(PARENT), MIN_F, MAX_F)
+
 static inline struct s32cc_osc *s32cc_obj2osc(const struct s32cc_clk_obj *mod)
 {
 	uintptr_t osc_addr;
@@ -237,4 +277,20 @@
 	return (struct s32cc_fixed_div *)fdiv_addr;
 }
 
+static inline struct s32cc_dfs *s32cc_obj2dfs(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t dfs_addr;
+
+	dfs_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs, desc);
+	return (struct s32cc_dfs *)dfs_addr;
+}
+
+static inline struct s32cc_dfs_div *s32cc_obj2dfsdiv(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t dfs_div_addr;
+
+	dfs_div_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs_div, desc);
+	return (struct s32cc_dfs_div *)dfs_div_addr;
+}
+
 #endif /* S32CC_CLK_MODULES_H */
diff --git a/include/lib/extensions/spe.h b/include/lib/extensions/spe.h
index c6e44f9..4801a22 100644
--- a/include/lib/extensions/spe.h
+++ b/include/lib/extensions/spe.h
@@ -12,16 +12,20 @@
 
 #if ENABLE_SPE_FOR_NS
 void spe_enable(cpu_context_t *ctx);
+void spe_disable(cpu_context_t *ctx);
 void spe_init_el2_unused(void);
-void spe_disable(void);
+void spe_stop(void);
 #else
 static inline void spe_enable(cpu_context_t *ctx)
 {
 }
+static inline void spe_disable(cpu_context_t *ctx)
+{
+}
 static inline void spe_init_el2_unused(void)
 {
 }
-static inline void spe_disable(void)
+static inline void spe_stop(void)
 {
 }
 #endif /* ENABLE_SPE_FOR_NS */
diff --git a/include/lib/extensions/trbe.h b/include/lib/extensions/trbe.h
index 5db3316..2c488e0 100644
--- a/include/lib/extensions/trbe.h
+++ b/include/lib/extensions/trbe.h
@@ -10,9 +10,13 @@
 #include <context.h>
 
 #if ENABLE_TRBE_FOR_NS
+void trbe_disable(cpu_context_t *ctx);
 void trbe_enable(cpu_context_t *ctx);
 void trbe_init_el2_unused(void);
 #else
+static inline void trbe_disable(cpu_context_t *ctx)
+{
+}
 static inline void trbe_enable(cpu_context_t *ctx)
 {
 }
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index ba8df2a..83a5cd2 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -284,10 +284,7 @@
 /* Firmware Handoff utility functions */
 void arm_transfer_list_dyn_cfg_init(struct transfer_list_header *secure_tl);
 void arm_transfer_list_populate_ep_info(bl_mem_params_node_t *next_param_node,
-					struct transfer_list_header *secure_tl,
-					struct transfer_list_header *ns_tl);
-void arm_transfer_list_copy_hw_config(struct transfer_list_header *secure_tl,
-				      struct transfer_list_header *ns_tl);
+					struct transfer_list_header *secure_tl);
 
 /* TSP utility functions */
 void arm_tsp_early_platform_setup(void);
@@ -365,6 +362,7 @@
 void plat_arm_interconnect_exit_coherency(void);
 void plat_arm_program_trusted_mailbox(uintptr_t address);
 bool plat_arm_bl1_fwu_needed(void);
+int plat_arm_ni_setup(uintptr_t global_cfg);
 __dead2 void plat_arm_error_handler(int err);
 __dead2 void plat_arm_system_reset(void);
 
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
index c6076fe..d653222 100644
--- a/lib/extensions/spe/spe.c
+++ b/lib/extensions/spe/spe.c
@@ -52,6 +52,27 @@
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
 }
 
+void spe_disable(cpu_context_t *ctx)
+{
+	el3_state_t *state = get_el3state_ctx(ctx);
+	u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3);
+
+	/*
+	 * MDCR_EL3.NSPB: Clear these bits to disable SPE feature, as it was enabled
+	 * for Non-secure state only. After clearing these bits Secure state owns
+	 * the Profiling Buffer and accesses to Statistical Profiling and Profiling
+	 * Buffer control registers at EL2 and EL1 generate Trap exceptions to EL3
+	 *
+	 * MDCR_EL3.NSPBE: Don't care as it was cleared during spe_enable and setting
+	 * this to 1 does not make sense as NSPBE{1} and NSPB{0b0x} is RESERVED.
+	 *
+	 * MDCR_EL3.EnPMSN (ARM v8.7): Clear the bit to trap access of PMSNEVFR_EL1
+	 * from EL2/EL1 to EL3.
+	 */
+	mdcr_el3_val &= ~(MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT);
+	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
+}
+
 void spe_init_el2_unused(void)
 {
 	uint64_t v;
@@ -70,7 +91,7 @@
 	write_mdcr_el2(v);
 }
 
-void spe_disable(void)
+void spe_stop(void)
 {
 	uint64_t v;
 
diff --git a/lib/extensions/trbe/trbe.c b/lib/extensions/trbe/trbe.c
index 9157734..8c1c421 100644
--- a/lib/extensions/trbe/trbe.c
+++ b/lib/extensions/trbe/trbe.c
@@ -39,6 +39,25 @@
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
 }
 
+void trbe_disable(cpu_context_t *ctx)
+{
+	el3_state_t *state = get_el3state_ctx(ctx);
+	u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3);
+
+	/*
+	 * MDCR_EL3.NSTBE = 0b0
+	 *  Trace Buffer owning Security state is secure state. If FEAT_RME
+	 *  is not implemented, this field is RES0.
+	 *
+	 * MDCR_EL3.NSTB = 0b00
+	 *  Clear these bits to disable access of trace buffer control registers
+	 *  from lower ELs in any security state.
+	 */
+	mdcr_el3_val &= ~(MDCR_NSTB(MDCR_NSTB_EL1));
+	mdcr_el3_val &= ~(MDCR_NSTBE_BIT);
+	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
+}
+
 void trbe_init_el2_unused(void)
 {
 	/*
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 60449f6..375cdba 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -182,9 +182,9 @@
 	}
 
 	my_idx = plat_my_core_pos();
-
-	for (lvl = PSCI_CPU_PWR_LVL; lvl <= end_pwrlvl; lvl++) {
-		parent_idx = psci_cpu_pd_nodes[my_idx].parent_node;
+	parent_idx = psci_cpu_pd_nodes[my_idx].parent_node;
+	for (lvl = PSCI_CPU_PWR_LVL + U(1); lvl < end_pwrlvl; lvl++) {
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
 	}
 
 	cpu_start_idx = psci_non_cpu_pd_nodes[parent_idx].cpu_start_idx;
@@ -1303,7 +1303,7 @@
 	 * before exiting coherency.
 	 */
 	if (is_feat_spe_supported()) {
-		spe_disable();
+		spe_stop();
 	}
 
 }
diff --git a/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c b/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c
index 457d181..de6a15a 100644
--- a/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c
+++ b/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, 2024 ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -77,7 +77,8 @@
 		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
 			VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
 		.ep_info.pc = BL33_BASE,
-
+		.ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+				       DISABLE_ALL_EXCEPTIONS),
 		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
 			VERSION_2, image_info_t, 0),
 		.image_info.image_base = BL33_BASE,
diff --git a/plat/arm/board/corstone1000/common/corstone1000_plat.c b/plat/arm/board/corstone1000/common/corstone1000_plat.c
index ed3801c..e388c82 100644
--- a/plat/arm/board/corstone1000/common/corstone1000_plat.c
+++ b/plat/arm/board/corstone1000/common/corstone1000_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,7 +23,6 @@
 
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
-	ARM_MAP_NS_SHARED_RAM,
 	ARM_MAP_NS_DRAM1,
 	CORSTONE1000_MAP_DEVICE,
 	CORSTONE1000_EXTERNAL_FLASH,
diff --git a/plat/arm/board/corstone1000/common/corstone1000_pm.c b/plat/arm/board/corstone1000/common/corstone1000_pm.c
index 51d696c..bd3faec 100644
--- a/plat/arm/board/corstone1000/common/corstone1000_pm.c
+++ b/plat/arm/board/corstone1000/common/corstone1000_pm.c
@@ -8,6 +8,7 @@
 #include <plat/arm/common/plat_arm.h>
 #include <platform_def.h>
 #include <plat/common/platform.h>
+#include <drivers/arm/gicv2.h>
 /*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform layer will take care of registering the handlers with PSCI.
@@ -19,6 +20,15 @@
 	uint32_t volatile * const watchdog_ctrl_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_CTRL_REG;
 	uint32_t volatile * const watchdog_val_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_VAL_REG;
 
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt
+	 * from waking up the AP from WFI.
+	 */
+	gicv2_cpuif_disable();
+
+	/* Flush and invalidate data cache */
+	dcsw_op_all(DCCISW);
+
 	*(watchdog_val_reg) = SECURE_WATCHDOG_COUNTDOWN_VAL;
 	*watchdog_ctrl_reg = SECURE_WATCHDOG_MASK_ENABLE;
 	while (1) {
diff --git a/plat/arm/board/corstone1000/common/include/platform_def.h b/plat/arm/board/corstone1000/common/include/platform_def.h
index e3f3268..caf3d46 100644
--- a/plat/arm/board/corstone1000/common/include/platform_def.h
+++ b/plat/arm/board/corstone1000/common/include/platform_def.h
@@ -55,42 +55,42 @@
 
 /* Memory related constants */
 
-/* SRAM (CVM) memory layout
+/* Memory mappings of where the BLs in the FIP are copied to
  *
- * <ARM_TRUSTED_SRAM_BASE>
+ * <ARM_TRUSTED_SRAM_BASE> = 0x02000000
  *	partition size: sizeof(meminfo_t) = 16 bytes
  *	content: memory info area used by the next BL
  *
- * <ARM_FW_CONFIG_BASE>
+ * <ARM_FW_CONFIG_BASE> = 0x02000010
  *	partition size: 4080 bytes
  *
- * <ARM_BL2_MEM_DESC_BASE>
+ * <ARM_BL2_MEM_DESC_BASE> = 0x02001000
  *	partition size: 4 KB
  *	content: Area where BL2 copies the images descriptors
  *
- * <ARM_BL_RAM_BASE> = <BL32_BASE>
- *	partition size: 688 KB
+ * <ARM_BL_RAM_BASE> = <BL32_BASE> = 0x02002000
+ *	partition size: 3752 KB
  *	content: BL32 (optee-os)
  *
- * <CORSTONE1000_TOS_FW_CONFIG_BASE> = 0x20ae000
+ * <CORSTONE1000_TOS_FW_CONFIG_BASE> = 0x023AC000
  *	partition size: 8 KB
  *	content: BL32 config (TOS_FW_CONFIG)
  *
- * <BL31_BASE>
+ * <BL31_BASE> = 0x023AE000
  *	partition size: 140 KB
  *	content: BL31
  *
- * <BL2_SIGNATURE_BASE>
+ * <BL2_SIGNATURE_BASE> = 0x023D1000
  *	partition size: 4 KB
  *	content: MCUBOOT data needed to verify TF-A BL2
  *
- * <BL2_BASE>
+ * <BL2_BASE> = 0x023D2000
  *	partition size: 176 KB
  *	content: BL2
  *
- * <ARM_NS_SHARED_RAM_BASE> = <ARM_TRUSTED_SRAM_BASE> + 1 MB
- *	partition size: 512 KB
- *	content: BL33 (u-boot)
+ * <BL33_BASE> = 0x80000000
+ *	partition size: 12 MB
+ *	content: BL33 (U-Boot)
  */
 
 /* DDR memory */
@@ -115,11 +115,8 @@
 /* The remaining Trusted SRAM is used to load the BL images */
 #define TOTAL_SRAM_SIZE		(SZ_4M)  /* 4 MB */
 
-/* Last 512KB of CVM is allocated for shared RAM as an example openAMP */
-#define ARM_NS_SHARED_RAM_SIZE	(512 * SZ_1K)
 
 #define PLAT_ARM_TRUSTED_SRAM_SIZE	(TOTAL_SRAM_SIZE - \
-					 ARM_NS_SHARED_RAM_SIZE - \
 					 ARM_SHARED_RAM_SIZE)
 
 #define PLAT_ARM_MAX_BL2_SIZE	(180 * SZ_1K)  /* 180 KB */
@@ -158,11 +155,6 @@
 
 /* NS memory */
 
-/* The last 512KB of the SRAM is allocated as shared memory */
-#define ARM_NS_SHARED_RAM_BASE	(ARM_TRUSTED_SRAM_BASE + TOTAL_SRAM_SIZE - \
-				 (PLAT_ARM_MAX_BL31_SIZE + \
-				  PLAT_ARM_MAX_BL32_SIZE))
-
 #define BL33_BASE		ARM_DRAM1_BASE
 #define PLAT_ARM_MAX_BL33_SIZE	(12 * SZ_1M)  /* 12 MB*/
 #define BL33_LIMIT		(ARM_DRAM1_BASE + PLAT_ARM_MAX_BL33_SIZE)
@@ -277,7 +269,7 @@
 
 #define PLAT_ARM_NSTIMER_FRAME_ID	U(1)
 
-#define PLAT_ARM_NS_IMAGE_BASE		(ARM_NS_SHARED_RAM_BASE)
+#define PLAT_ARM_NS_IMAGE_BASE		(BL33_BASE)
 
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
@@ -306,11 +298,6 @@
 				ARM_SHARED_RAM_SIZE, \
 				MT_MEMORY | MT_RW | MT_SECURE)
 
-#define ARM_MAP_NS_SHARED_RAM	MAP_REGION_FLAT( \
-				ARM_NS_SHARED_RAM_BASE, \
-				ARM_NS_SHARED_RAM_SIZE, \
-				MT_MEMORY | MT_RW | MT_NS)
-
 #define ARM_MAP_NS_DRAM1	MAP_REGION_FLAT( \
 				ARM_NS_DRAM1_BASE, \
 				ARM_NS_DRAM1_SIZE, \
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 78b6945..fb70500 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -121,7 +121,8 @@
 			lib/cpus/aarch64/cortex_x925.S
 endif
 
-INTERCONNECT_SOURCES	:=	${TC_BASE}/tc_interconnect.c
+INTERCONNECT_SOURCES	:=	${TC_BASE}/tc_interconnect.c \
+				plat/arm/common/arm_ni.c
 
 PLAT_BL_COMMON_SOURCES	+=	${TC_BASE}/tc_plat.c	\
 				${TC_BASE}/include/tc_helpers.S
diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c
index 7d1bc9c..53404df 100644
--- a/plat/arm/board/tc/tc_bl31_setup.c
+++ b/plat/arm/board/tc/tc_bl31_setup.c
@@ -110,6 +110,7 @@
 #if TARGET_PLATFORM == 3
 	enable_ns_mcn_pmu();
 	set_mcn_slc_alloc_mode();
+	plat_arm_ni_setup(NCI_BASE_ADDR);
 #endif
 }
 
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 99243dc..b5a7db1 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -162,16 +162,6 @@
 #if defined(PLAT_ARM_MEM_PROT_ADDR)
 	arm_nor_psci_do_static_mem_protect();
 #endif
-
-#if TRANSFER_LIST
-	ns_tl = transfer_list_init((void *)FW_NS_HANDOFF_BASE,
-				   PLAT_ARM_FW_HANDOFF_SIZE);
-
-	if (ns_tl == NULL) {
-		ERROR("Non-secure transfer list initialisation failed!");
-		panic();
-	}
-#endif
 }
 
 void bl2_platform_setup(void)
@@ -326,7 +316,8 @@
 
 #if TRANSFER_LIST
 	if (image_id == HW_CONFIG_ID) {
-		arm_transfer_list_copy_hw_config(secure_tl, ns_tl);
+		/* Refresh the now stale checksum following loading of HW_CONFIG into the TL. */
+		transfer_list_update_checksum(secure_tl);
 	}
 #endif /* TRANSFER_LIST */
 
@@ -340,5 +331,5 @@
 					    &next_param_node->ep_info);
 	assert(ep != NULL);
 
-	arm_transfer_list_populate_ep_info(next_param_node, secure_tl, ns_tl);
+	arm_transfer_list_populate_ep_info(next_param_node, secure_tl);
 }
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 632e84c..e91746b 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -25,6 +25,8 @@
 #include <platform_def.h>
 
 static struct transfer_list_header *secure_tl __unused;
+static struct transfer_list_header *ns_tl __unused;
+
 /*
  * Placeholder variables for copying the arguments that have been passed to
  * BL31 from BL2.
@@ -95,7 +97,12 @@
 
 	assert(sec_state_is_valid(type));
 	if (type == NON_SECURE) {
+#if TRANSFER_LIST && !RESET_TO_BL31
+		next_image_info = transfer_list_set_handoff_args(
+			ns_tl, &bl33_image_ep_info);
+#else
 		next_image_info = &bl33_image_ep_info;
+#endif
 	}
 #if ENABLE_RME
 	else if (type == REALM) {
@@ -142,8 +149,8 @@
 
 	bl33_image_ep_info.args.arg0 =
 		FW_NS_HANDOFF_BASE + ARM_PRELOADED_DTB_OFFSET;
-	bl33_image_ep_info.args.arg1 = TRANSFER_LIST_SIGNATURE |
-				       REGISTER_CONVENTION_VERSION_MASK;
+	bl33_image_ep_info.args.arg1 =
+		TRANSFER_LIST_HANDOFF_X1_VALUE(REGISTER_CONVENTION_VERSION);
 	bl33_image_ep_info.args.arg3 = FW_NS_HANDOFF_BASE;
 #else
 	struct transfer_list_entry *te = NULL;
@@ -357,6 +364,28 @@
  ******************************************************************************/
 void arm_bl31_platform_setup(void)
 {
+	struct transfer_list_entry *te __unused;
+
+#if TRANSFER_LIST && !RESET_TO_BL31
+	/* Initialise the non-secure world tl, BL31 may modify the HW_CONFIG so defer
+	 * copying it until later.
+	 */
+	ns_tl = transfer_list_init((void *)FW_NS_HANDOFF_BASE,
+				   PLAT_ARM_FW_HANDOFF_SIZE);
+
+	if (ns_tl == NULL) {
+		ERROR("Non-secure transfer list initialisation failed!");
+		panic();
+	}
+
+#if !RESET_TO_BL2
+	te = transfer_list_find(secure_tl, TL_TAG_FDT);
+	assert(te != NULL);
+
+	fconf_populate("HW_CONFIG", (uintptr_t)transfer_list_entry_data(te));
+#endif /* !(RESET_TO_BL2 && RESET_TO_BL31) */
+#endif /* TRANSFER_LIST */
+
 	/* Initialize the GIC driver, cpu and distributor interfaces */
 	plat_arm_gic_driver_init();
 	plat_arm_gic_init();
@@ -399,9 +428,26 @@
  ******************************************************************************/
 void arm_bl31_plat_runtime_setup(void)
 {
+	struct transfer_list_entry *te __unused;
 	/* Initialize the runtime console */
 	arm_console_runtime_init();
 
+#if TRANSFER_LIST && !RESET_TO_BL31
+	te = transfer_list_find(secure_tl, TL_TAG_FDT);
+	assert(te != NULL);
+
+	te = transfer_list_add(ns_tl, TL_TAG_FDT, te->data_size,
+			       transfer_list_entry_data(te));
+	assert(te != NULL);
+
+	/*
+	 * We assume BL31 has added all TE's required by BL33 at this stage, ensure
+	 * that data is visible to all observers by performing a flush operation, so
+	 * they can access the updated data even if caching is not enabled.
+	 */
+	flush_dcache_range((uintptr_t)ns_tl, ns_tl->size);
+#endif /* TRANSFER_LIST && !(RESET_TO_BL2 || RESET_TO_BL31) */
+
 #if RECLAIM_INIT_CODE
 	arm_free_init_memory();
 #endif
@@ -516,15 +562,5 @@
 
 void __init bl31_plat_arch_setup(void)
 {
-	struct transfer_list_entry *te __unused;
-
 	arm_bl31_plat_arch_setup();
-
-#if TRANSFER_LIST && !(RESET_TO_BL2 || RESET_TO_BL31)
-	te = transfer_list_find(secure_tl, TL_TAG_FDT);
-	assert(te != NULL);
-
-	/* Populate HW_CONFIG device tree with the mapped address */
-	fconf_populate("HW_CONFIG", (uintptr_t)transfer_list_entry_data(te));
-#endif
 }
diff --git a/plat/arm/common/arm_ni.c b/plat/arm/common/arm_ni.c
new file mode 100644
index 0000000..b3ad8b3
--- /dev/null
+++ b/plat/arm/common/arm_ni.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2024, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+#define NI_CHILD_NODE_COUNT			4
+#define NI_CHILD_POINTERS_START			8
+
+#define NI_PMU_SECURE_CTRL			0x100
+#define NI_PMU_SECURE_EVENT_OBSERVATION		0x108
+#define NI_PMU_DEBUG_ENABLE			0x110
+#define NI_COMP_NUM_SUBFEATURES			0x100
+#define NI_COMP_SUBFEATURE_TYPE_START		0x108
+#define NI_COMP_SUBFEATURE_SECURE_CTRL_START	0x308
+
+#define SECURE_OVERRIDE_DEFAULT			BIT(0)
+#define SECURE_EVENT_ENABLE			BIT(2)
+#define NA_EVENT_ENABLE				BIT(3)
+#define PMU_ENABLE				BIT(0)
+
+#define NI_NODE_MASK				0x0000ffff
+#define NI_NODE_TYPE(node_info)			(node_info & NI_NODE_MASK)
+#define NI_CHILD_POINTER(i)			(NI_CHILD_POINTERS_START + (i * 4))
+#define NI_COMP_SUBFEATURE_TYPE(i)		(NI_COMP_SUBFEATURE_TYPE_START + (i * 8))
+#define NI_COMP_SUBFEATURE_SECURE_CTRL(i)	(NI_COMP_SUBFEATURE_SECURE_CTRL_START + (i * 8))
+
+#define NI_PERIPHERAL_ID0			0xfe0
+#define NI_PIDR0_PART_MASK			0xff
+#define NI_PERIPHERAL_ID1			0xfe4
+#define NI_PIDR1_PART_MASK			0xf
+#define NI_PIDR1_PART_SHIFT			8
+
+enum ni_part {
+	NI_700 = 0x43b,
+	NI_710AE = 0x43d,
+	NI_TOWER = 0x43f,
+};
+
+enum ni_node_type {
+	NI_INVALID_NODE = 0,
+	NI_VOLTAGE_DOMAIN  = 1,
+	NI_POWER_DOMAIN = 2,
+	NI_CLOCK_DOMAIN = 3,
+	NI_ASNI = 4,
+	NI_AMNI = 5,
+	NI_PMU = 6,
+	NI_HSNI = 7,
+	NI_HMNI = 8,
+	NI_PMNI = 9,
+	NI_CMNI = 14,
+	NI_CFGNI = 15
+};
+
+enum ni_subfeature_type {
+	NI_SUBFEATURE_APU = 0,
+	NI_SUBFEATURE_ADDR_MAP = 1,
+	NI_SUBFEATURE_FCU = 2,
+	NI_SUBFEATURE_IDM = 3
+};
+
+static void ni_enable_pmu(uintptr_t pmu_addr)
+{
+	mmio_setbits_32(pmu_addr + NI_PMU_DEBUG_ENABLE, PMU_ENABLE);
+}
+
+static void ni_enable_fcu_ns_access(uintptr_t comp_addr)
+{
+	uint32_t subfeature_type;
+	uint32_t subfeature_count;
+	uint32_t subfeature_secure_ctrl;
+
+	subfeature_count = mmio_read_32(comp_addr + NI_COMP_NUM_SUBFEATURES);
+	for (uint32_t i = 0U; i < subfeature_count; i++) {
+		subfeature_type =
+			NI_NODE_TYPE(mmio_read_32(comp_addr + NI_COMP_SUBFEATURE_TYPE(i)));
+		if (subfeature_type == NI_SUBFEATURE_FCU) {
+			subfeature_secure_ctrl = comp_addr + NI_COMP_SUBFEATURE_SECURE_CTRL(i);
+			mmio_setbits_32(subfeature_secure_ctrl, SECURE_OVERRIDE_DEFAULT);
+		}
+	}
+}
+
+static void ni_enable_pmu_ns_access(uintptr_t comp_addr)
+{
+	mmio_setbits_32(comp_addr + NI_PMU_SECURE_CTRL, SECURE_OVERRIDE_DEFAULT);
+	mmio_setbits_32(comp_addr + NI_PMU_SECURE_EVENT_OBSERVATION,
+			SECURE_EVENT_ENABLE | NA_EVENT_ENABLE);
+}
+
+static void ni_setup_component(uintptr_t comp_addr)
+{
+	uint32_t node_info;
+
+	node_info = mmio_read_32(comp_addr);
+
+	switch (NI_NODE_TYPE(node_info)) {
+	case NI_ASNI:
+	case NI_AMNI:
+	case NI_HSNI:
+	case NI_HMNI:
+	case NI_PMNI:
+		ni_enable_fcu_ns_access(comp_addr);
+		break;
+	case NI_PMU:
+		ni_enable_pmu_ns_access(comp_addr);
+		ni_enable_pmu(comp_addr);
+		break;
+	default:
+		return;
+	}
+}
+
+int plat_arm_ni_setup(uintptr_t global_cfg)
+{
+	uintptr_t vd_addr;
+	uintptr_t pd_addr;
+	uintptr_t cd_addr;
+	uintptr_t comp_addr;
+	uint32_t vd_count;
+	uint32_t pd_count;
+	uint32_t cd_count;
+	uint32_t comp_count;
+	uint32_t part;
+	uint32_t reg;
+
+	reg = mmio_read_32(global_cfg + NI_PERIPHERAL_ID0);
+	part = reg & NI_PIDR0_PART_MASK;
+	reg = mmio_read_32(global_cfg + NI_PERIPHERAL_ID1);
+	part |= ((reg & NI_PIDR1_PART_MASK) << NI_PIDR1_PART_SHIFT);
+
+	if (part != NI_TOWER) {
+		ERROR("0x%x is not supported\n", part);
+		return -EINVAL;
+	}
+
+	vd_count = mmio_read_32(global_cfg + NI_CHILD_NODE_COUNT);
+
+	for (uint32_t i = 0U; i < vd_count; i++) {
+		vd_addr = global_cfg + mmio_read_32(global_cfg + NI_CHILD_POINTER(i));
+		pd_count = mmio_read_32(vd_addr + NI_CHILD_NODE_COUNT);
+
+		for (uint32_t j = 0U; j < pd_count; j++) {
+			pd_addr = global_cfg + mmio_read_32(vd_addr + NI_CHILD_POINTER(j));
+			cd_count = mmio_read_32(pd_addr + NI_CHILD_NODE_COUNT);
+
+			for (uint32_t k = 0U; k < cd_count; k++) {
+				cd_addr = global_cfg + mmio_read_32(pd_addr + NI_CHILD_POINTER(k));
+				comp_count = mmio_read_32(cd_addr + NI_CHILD_NODE_COUNT);
+
+				for (uint32_t l = 0U; l < comp_count; l++) {
+					comp_addr = global_cfg +
+						mmio_read_32(cd_addr + NI_CHILD_POINTER(l));
+					ni_setup_component(comp_addr);
+				}
+			}
+		}
+	}
+
+	return 0;
+}
diff --git a/plat/arm/common/arm_transfer_list.c b/plat/arm/common/arm_transfer_list.c
index d144bbb..59fb039 100644
--- a/plat/arm/common/arm_transfer_list.c
+++ b/plat/arm/common/arm_transfer_list.c
@@ -30,8 +30,7 @@
 }
 
 void arm_transfer_list_populate_ep_info(bl_mem_params_node_t *next_param_node,
-					struct transfer_list_header *secure_tl,
-					struct transfer_list_header *ns_tl)
+					struct transfer_list_header *secure_tl)
 {
 	uint32_t next_exe_img_id;
 	entry_point_info_t *ep;
@@ -53,10 +52,7 @@
 
 		ep = transfer_list_entry_data(te);
 
-		if (next_exe_img_id == BL33_IMAGE_ID) {
-			ep = transfer_list_set_handoff_args(ns_tl, ep);
-			assert(ep != NULL);
-		} else if ((next_exe_img_id == BL32_IMAGE_ID) && SPMC_AT_EL3) {
+		if ((next_exe_img_id == BL32_IMAGE_ID) && SPMC_AT_EL3) {
 			/*
 			 * Populate the BL32 image base, size and max limit in
 			 * the entry point information, since there is no
@@ -78,19 +74,3 @@
 
 	flush_dcache_range((uintptr_t)secure_tl, secure_tl->size);
 }
-
-void arm_transfer_list_copy_hw_config(struct transfer_list_header *secure_tl,
-				      struct transfer_list_header *ns_tl)
-{
-	struct transfer_list_entry *te =
-		transfer_list_find(secure_tl, TL_TAG_FDT);
-	assert(te != NULL);
-
-	/* Refresh the now stale checksum following loading of HW_CONFIG into the TL. */
-	transfer_list_update_checksum(secure_tl);
-
-	/* Copy the hardware configuration to the non-secure TL. */
-	te = transfer_list_add(ns_tl, TL_TAG_FDT, te->data_size,
-			       transfer_list_entry_data(te));
-	assert(te != NULL);
-}
diff --git a/plat/aspeed/ast2700/plat_bl31_setup.c b/plat/aspeed/ast2700/plat_bl31_setup.c
index 9fec3e8..087b479 100644
--- a/plat/aspeed/ast2700/plat_bl31_setup.c
+++ b/plat/aspeed/ast2700/plat_bl31_setup.c
@@ -174,7 +174,7 @@
 			break;
 		}
 	} else {
-		if (pll_reg.b.bypass != 0U) {
+		if (pll_reg.b.bypass == 0U) {
 			if (pll_idx == PLAT_CLK_MPLL) {
 				/* F = 25Mhz * [M / (n + 1)] / (p + 1) */
 				mul = (pll_reg.b.m) / ((pll_reg.b.n + 1));
diff --git a/plat/xilinx/common/include/pm_api_sys.h b/plat/xilinx/common/include/pm_api_sys.h
index ffee805..029bb43 100644
--- a/plat/xilinx/common/include/pm_api_sys.h
+++ b/plat/xilinx/common/include/pm_api_sys.h
@@ -64,6 +64,7 @@
 					uint32_t wake, uint32_t enable,
 					uint32_t flag);
 enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload);
 
 /*
  * Assigning of argument values into array elements.
@@ -97,4 +98,9 @@
 	PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4));		\
 }
 
+#define PM_PACK_PAYLOAD7(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5, arg6) {	\
+	pl[6] = (uint32_t)(arg6);							\
+	PM_PACK_PAYLOAD6(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4), (arg5));	\
+}
+
 #endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
index c0308ab..c38cdef 100644
--- a/plat/xilinx/common/include/pm_common.h
+++ b/plat/xilinx/common/include/pm_common.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,13 +18,15 @@
 
 #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
 #define CRC_ORDER               16U
 #define CRC_POLYNOM             0x8005U
 #else
-#define PAYLOAD_ARG_CNT         6U
+#define PAYLOAD_ARG_CNT		7U
+#define RET_PAYLOAD_ARG_CNT	6U
 #endif
 #define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
 
diff --git a/plat/xilinx/common/include/pm_defs.h b/plat/xilinx/common/include/pm_defs.h
index c6e825d..9920611 100644
--- a/plat/xilinx/common/include/pm_defs.h
+++ b/plat/xilinx/common/include/pm_defs.h
@@ -35,6 +35,7 @@
 				       (uint32_t)XPM_NODESUBCL_DEV_PERIPH, \
 				       (uint32_t)XPM_NODETYPE_DEV_PERIPH, (IDX))
 
+#define TF_A_FEATURE_CHECK		0xa00U
 #define PM_GET_CALLBACK_DATA		0xa01U
 #define PM_GET_TRUSTZONE_VERSION	0xa03U
 #define TF_A_PM_REGISTER_SGI		0xa04U
diff --git a/plat/xilinx/common/include/pm_svc_main.h b/plat/xilinx/common/include/pm_svc_main.h
index 67fbeae..000f198 100644
--- a/plat/xilinx/common/include/pm_svc_main.h
+++ b/plat/xilinx/common/include/pm_svc_main.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,8 @@
 
 extern bool pwrdwn_req_received;
 
+#define PASS_THROUGH_FW_CMD_ID	U(0xfff)
+
 /******************************************************************************/
 /**
  * SECURE_REDUNDANT_CALL() - Adds redundancy to the function call. This is to
diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c
index 0a6e810..e9c5f13 100644
--- a/plat/xilinx/common/pm_service/pm_api_sys.c
+++ b/plat/xilinx/common/pm_service/pm_api_sys.c
@@ -122,7 +122,7 @@
 	}
 
 	PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
-	return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
+	return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, RET_PAYLOAD_ARG_CNT);
 }
 
 /**
@@ -364,6 +364,37 @@
 }
 
 /**
+ * eemi_feature_check() - Returns the supported API version if supported.
+ * @api_id: API ID to check.
+ * @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
+ *               words Returned supported API version
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload)
+{
+	enum pm_ret_status ret;
+
+	/* Return version of API which are implemented in TF-A only */
+	switch (api_id) {
+	case PM_GET_CALLBACK_DATA:
+	case PM_GET_TRUSTZONE_VERSION:
+		ret_payload[0] = PM_API_VERSION_2;
+		ret = PM_RET_SUCCESS;
+		break;
+	case TF_A_PM_REGISTER_SGI:
+	case TF_A_FEATURE_CHECK:
+		ret_payload[0] = PM_API_BASE_VERSION;
+		ret = PM_RET_SUCCESS;
+		break;
+	default:
+		ret = PM_RET_ERROR_NO_FEATURE;
+	}
+
+	return ret;
+}
+
+/**
  * pm_feature_check() - Returns the supported API version if supported.
  * @api_id: API ID to check.
  * @flag: 0 - Call from secure source.
@@ -406,7 +437,7 @@
 
 	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
 			 PM_FEATURE_CHECK, api_id);
-	return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
+	return pm_ipi_send_sync(primary_proc, payload, ret_payload, RET_PAYLOAD_ARG_CNT);
 }
 
 /**
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index 56567dd..205877c 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -164,15 +164,10 @@
  *
  */
 static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
-					   uint32_t *value, size_t count)
+					   uint32_t value[PAYLOAD_ARG_CNT])
 {
 	size_t i;
 	enum pm_ret_status ret;
-#if IPI_CRC_CHECK
-	uint32_t *payload_ptr = value;
-	size_t j;
-	uint32_t response_payload[PAYLOAD_ARG_CNT];
-#endif
 	uintptr_t buffer_base = proc->ipi->buffer_base +
 				IPI_BUFFER_TARGET_REMOTE_OFFSET +
 				IPI_BUFFER_RESP_OFFSET;
@@ -184,27 +179,21 @@
 	 * buf-2: unused
 	 * buf-3: unused
 	 */
-	for (i = 1; i <= count; i++) {
-		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
-		value++;
+	for (i = 0; i < PAYLOAD_ARG_CNT; i++) {
+		value[i] = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 	}
 
-	ret = mmio_read_32(buffer_base);
+	ret = value[0];
 #if IPI_CRC_CHECK
-	for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
-		response_payload[j] = mmio_read_32(buffer_base +
-						(j * PAYLOAD_ARG_SIZE));
-	}
-
-	if (response_payload[PAYLOAD_CRC_POS] !=
-			calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+	if (value[PAYLOAD_CRC_POS] !=
+			calculate_crc(value, IPI_W0_TO_W6_SIZE)) {
 		NOTICE("ERROR in CRC response payload value:0x%x\n",
-					response_payload[PAYLOAD_CRC_POS]);
+					value[PAYLOAD_CRC_POS]);
 		ret = PM_RET_ERROR_INVALID_CRC;
 		/* Payload data is invalid as CRC validation failed
 		 * Clear the payload to avoid leakage of data to upper layers
 		 */
-		memset(payload_ptr, 0, count);
+		memset(value, 0, PAYLOAD_ARG_CNT);
 	}
 #endif
 
@@ -240,7 +229,7 @@
 		count = IPI_BUFFER_MAX_WORDS;
 	}
 
-	for (i = 0; i <= count; i++) {
+	for (i = 0; i < count; i++) {
 		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
 		value++;
 	}
@@ -282,6 +271,7 @@
 				    uint32_t *value, size_t count)
 {
 	enum pm_ret_status ret;
+	uint32_t i, ret_payload[PAYLOAD_ARG_CNT] = {0U};
 
 	pm_ipi_lock_get();
 
@@ -290,7 +280,12 @@
 		goto unlock;
 	}
 
+	ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, ret_payload));
+
-	ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
+	for (i = 1U; i <= count; i++) {
+		*value = ret_payload[i];
+		value++;
+	}
 
 unlock:
 	pm_ipi_lock_release();
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index 7ac0ac1..b431a6c 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -36,6 +36,32 @@
 #define EVENT_CPU_PWRDWN	(4U)
 #define MBOX_SGI_SHARED_IPI	(7U)
 
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ */
+#define upper_32_bits(n)	((uint32_t)((n) >> 32U))
+
+/**
+ * lower_32_bits - return bits 0-31 of a number
+ * @n: the number we're accessing
+ */
+#define lower_32_bits(n)	((uint32_t)((n) & 0xffffffffU))
+
+/**
+ * EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
+ * @pm_arg: array of 32-bit payloads
+ * @x: array of 64-bit SMC arguments
+ */
+#define EXTRACT_ARGS(pm_arg, x)						\
+	for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) {	\
+		if ((i % 2U) != 0U) {					\
+			pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]);	\
+		} else {						\
+			pm_arg[i] = upper_32_bits(x[i / 2U]);		\
+		}							\
+	}
+
 /* 1 sec of wait timeout for secondary core down */
 #define PWRDWN_WAIT_TIMEOUT	(1000U)
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
@@ -278,7 +304,7 @@
 
 	case (uint32_t)PM_FEATURE_CHECK:
 	{
-		uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+		uint32_t result[RET_PAYLOAD_ARG_CNT] = {0U};
 
 		ret = pm_feature_check(pm_arg[0], result, security_flag);
 		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
@@ -367,6 +393,15 @@
 {
 	switch (api_id) {
 
+	case TF_A_FEATURE_CHECK:
+	{
+		enum pm_ret_status ret;
+		uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+		ret = eemi_feature_check(pm_arg[0], result);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
+	}
+
 	case TF_A_PM_REGISTER_SGI:
 	{
 		int32_t ret;
@@ -424,7 +459,7 @@
 			      void *handle, uint32_t security_flag)
 {
 	enum pm_ret_status ret;
-	uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+	uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0};
 
 	ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
 				  pm_arg[2], pm_arg[3], pm_arg[4],
@@ -449,6 +484,45 @@
 }
 
 /**
+ * eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
+ * protocol to allow communication between power management controller and
+ * different processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0
+ */
+static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
+				  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 module_id;
+
+	module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+	PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
+			 pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+			 pm_arg[4], pm_arg[5]);
+
+	ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
+			       PAYLOAD_ARG_CNT);
+
+	SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+		 (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
+		 (uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
+		 (uint64_t)buf[5]);
+}
+
+/**
  * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
  * @smc_fid: Function Identifier.
  * @x1: SMC64 Arguments from kernel.
@@ -477,6 +551,7 @@
 	uint32_t security_flag = NON_SECURE_FLAG;
 	uint32_t api_id;
 	bool status = false, status_tmp = false;
+	uint64_t x[4] = {x1, x2, x3, x4};
 
 	/* Handle case where PM wasn't initialized properly */
 	if (pm_up == false) {
@@ -494,6 +569,14 @@
 		security_flag = SECURE_FLAG;
 	}
 
+	if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
+		api_id = lower_32_bits(x[0]);
+
+		EXTRACT_ARGS(pm_arg, x);
+
+		return eemi_api_handler(api_id, pm_arg, handle, security_flag);
+	}
+
 	pm_arg[0] = (uint32_t)x1;
 	pm_arg[1] = (uint32_t)(x1 >> 32U);
 	pm_arg[2] = (uint32_t)x2;
diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
index 772477f..9e8134a 100644
--- a/plat/xilinx/versal/aarch64/versal_common.c
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -1,12 +1,11 @@
 /*
  * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <common/debug.h>
-#include <drivers/generic_delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
@@ -18,7 +17,7 @@
 #include <versal_def.h>
 
 uint32_t platform_id, platform_version;
-uint32_t cpu_clock = VERSAL_CPU_CLOCK;
+uint32_t cpu_clock;
 
 /*
  * Table of regions to map using the MMU.
@@ -39,19 +38,10 @@
 	return plat_versal_mmap;
 }
 
-static void versal_print_platform_name(void)
-{
-	NOTICE("TF-A running on %s\n", PLATFORM_NAME);
-}
-
 void versal_config_setup(void)
 {
 	/* Configure IPI data for versal */
 	versal_ipi_config_table_init();
-
-	versal_print_platform_name();
-
-	generic_delay_timer_init();
 }
 
 void board_detection(void)
@@ -70,7 +60,50 @@
 	platform_version = FIELD_GET(PLATFORM_VERSION_MASK, plat_info[1]);
 }
 
+const char *board_name_decode(void)
+{
+	const char *platform;
+
+	switch (platform_id) {
+	case VERSAL_SPP:
+		platform = "IPP";
+		break;
+	case VERSAL_EMU:
+		platform = "EMU";
+		break;
+	case VERSAL_QEMU:
+		platform = "QEMU";
+		break;
+	case VERSAL_SILICON:
+		platform = "SILICON";
+		break;
+	default:
+		platform = "unknown";
+	}
+
+	return platform;
+}
+
 uint32_t get_uart_clk(void)
 {
-	return UART_CLOCK;
+	uint32_t uart_clock;
+
+	switch (platform_id) {
+	case VERSAL_SPP:
+		uart_clock = 25000000;
+		break;
+	case VERSAL_EMU:
+		uart_clock = 212000;
+		break;
+	case VERSAL_QEMU:
+		uart_clock = 25000000;
+		break;
+	case VERSAL_SILICON:
+		uart_clock = 100000000;
+		break;
+	default:
+		panic();
+	}
+
+	return uart_clock;
 }
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
index 594784f..0e4ec1c 100644
--- a/plat/xilinx/versal/bl31_versal_setup.c
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,7 @@
 #include <bl31/bl31.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
@@ -73,22 +74,41 @@
 	enum pm_ret_status ret_status;
 	uint64_t addr[HANDOFF_PARAMS_MAX_SIZE];
 
-	set_cnt_freq();
-
-	setup_console();
-
-	/* Initialize the platform config for future decision making */
-	versal_config_setup();
-
-	/* Get platform related information */
-	board_detection();
-
 	/*
 	 * Do initial security configuration to allow DRAM/device access. On
 	 * Base VERSAL only DRAM security is programmable (via TrustZone), but
 	 * other platforms might have more programmable security devices
 	 * present.
 	 */
+	versal_config_setup();
+
+	/* Initialize the platform config for future decision making */
+	board_detection();
+
+	switch (platform_id) {
+	case VERSAL_SPP:
+		cpu_clock = 2720000;
+		break;
+	case VERSAL_EMU:
+		cpu_clock = 212000;
+		break;
+	case VERSAL_QEMU:
+		/* Random values now */
+		cpu_clock = 2720000;
+		break;
+	case VERSAL_SILICON:
+		cpu_clock = 100000000;
+		break;
+	default:
+		panic();
+	}
+	set_cnt_freq();
+
+	generic_delay_timer_init();
+
+	setup_console();
+
+	NOTICE("TF-A running on %s %d\n", board_name_decode(), platform_version);
 
 	/* Populate common information for BL32 and BL33 */
 	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h
index 932c6de..4b2b6cf 100644
--- a/plat/xilinx/versal/include/plat_private.h
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,6 +25,8 @@
 extern uint32_t cpu_clock, platform_id, platform_version;
 
 void board_detection(void);
+const char *board_name_decode(void);
+
 void plat_versal_gic_driver_init(void);
 void plat_versal_gic_init(void);
 void plat_versal_gic_cpuif_enable(void);
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index f21d409..b7691ad 100644
--- a/plat/xilinx/versal/include/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,13 +25,11 @@
 
 #define CONSOLE_IS(con)	(VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE)
 
-/* List all supported platforms */
-#define VERSAL_PLATFORM_ID_versal_virt	1
-#define VERSAL_PLATFORM_ID_spp_itr6	2
-#define VERSAL_PLATFORM_ID_emu_itr6	3
-#define VERSAL_PLATFORM_ID_silicon	4
-
-#define VERSAL_PLATFORM_IS(con)	(VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
+/* List of platforms */
+#define VERSAL_SILICON              U(0)
+#define VERSAL_SPP                  U(1)
+#define VERSAL_EMU                  U(2)
+#define VERSAL_QEMU                 U(3)
 
 /* Firmware Image Package */
 #define VERSAL_PRIMARY_CPU	0
@@ -75,27 +73,7 @@
 /*******************************************************************************
  * Platform related constants
  ******************************************************************************/
-#if VERSAL_PLATFORM_IS(versal_virt)
-# define PLATFORM_NAME		"Versal Virt"
-# define UART_CLOCK	25000000
-# define UART_BAUDRATE	115200
-# define VERSAL_CPU_CLOCK	2720000
-#elif VERSAL_PLATFORM_IS(silicon)
-# define PLATFORM_NAME		"Versal Silicon"
-# define UART_CLOCK	100000000
-# define UART_BAUDRATE	115200
-# define VERSAL_CPU_CLOCK	100000000
-#elif VERSAL_PLATFORM_IS(spp_itr6)
-# define PLATFORM_NAME		"SPP ITR6"
-# define UART_CLOCK	25000000
-# define UART_BAUDRATE	115200
-# define VERSAL_CPU_CLOCK	2720000
-#elif VERSAL_PLATFORM_IS(emu_itr6)
-# define PLATFORM_NAME		"EMU ITR6"
-# define UART_CLOCK	212000
-# define UART_BAUDRATE	9600
-# define VERSAL_CPU_CLOCK	212000
-#endif
+#define UART_BAUDRATE  115200
 
 /* Access control register defines */
 #define ACTLR_EL3_L2ACTLR_BIT	(1 << 6)
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 4cf1ed1..74c5bf3 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -197,7 +197,7 @@
  */
 static void versal_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index 2f07996..6cc28e1 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -1,5 +1,5 @@
 # Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
-# Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -44,8 +44,9 @@
     $(eval $(call add_define,IPI_CRC_CHECK))
 endif
 
-VERSAL_PLATFORM ?= silicon
-$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
+ifdef VERSAL_PLATFORM
+    $(warning "VERSAL_PLATFORM has been deprecated")
+endif
 
 ifdef XILINX_OF_BOARD_DTB_ADDR
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
index 4441d3e..3c0bd63 100644
--- a/plat/xilinx/versal/sip_svc_setup.c
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,7 +22,7 @@
 
 /* SiP Service Calls version numbers */
 #define SIP_SVC_VERSION_MAJOR	U(0)
-#define SIP_SVC_VERSION_MINOR	U(1)
+#define SIP_SVC_VERSION_MINOR	U(2)
 
 /* These macros are used to identify PM calls from the SMC function ID */
 #define SIP_FID_MASK	GENMASK(23, 16)
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
index e5a5235..fb2005d 100644
--- a/plat/xilinx/versal_net/plat_psci_pm.c
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -59,7 +59,7 @@
  */
 static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
diff --git a/plat/xilinx/versal_net/sip_svc_setup.c b/plat/xilinx/versal_net/sip_svc_setup.c
index 80d5a53..c974810 100644
--- a/plat/xilinx/versal_net/sip_svc_setup.c
+++ b/plat/xilinx/versal_net/sip_svc_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,7 +25,7 @@
 
 /* SiP Service Calls version numbers */
 #define SIP_SVC_VERSION_MAJOR		(0U)
-#define SIP_SVC_VERSION_MINOR		(1U)
+#define SIP_SVC_VERSION_MINOR		(2U)
 
 /* These macros are used to identify PM calls from the SMC function ID */
 #define SIP_FID_MASK	GENMASK(23, 16)
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
index 3d546b3..66f011a 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
@@ -919,7 +919,7 @@
 enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
 				    uint32_t *bit_mask, uint8_t len)
 {
-	uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t ret_payload[RET_PAYLOAD_ARG_CNT] = {0U};
 	uint32_t status;
 
 	/* Get API version implemented in TF-A */
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
index 5a6a9f8..bf17ea4 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
@@ -285,7 +285,7 @@
 	uint32_t payload[PAYLOAD_ARG_CNT];
 
 	uint32_t pm_arg[5];
-	uint32_t result[PAYLOAD_ARG_CNT] = {0};
+	uint32_t result[RET_PAYLOAD_ARG_CNT] = {0};
 	uint32_t api_id;
 
 	/* Handle case where PM wasn't initialized properly */
@@ -566,7 +566,7 @@
 		PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
 				 pm_arg[2], pm_arg[3], pm_arg[4]);
 		ret = pm_ipi_send_sync(primary_proc, payload, result,
-				       PAYLOAD_ARG_CNT);
+				       RET_PAYLOAD_ARG_CNT);
 		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
 			 (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
 	}
diff --git a/poetry.lock b/poetry.lock
index d72e14a..b465f48 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -893,6 +893,7 @@
 
 [package.dependencies]
 click = "^8.1.7"
+pyyaml = "^6.0.1"
 rich = "^10.14.0"
 typer = {version = "^0.4.0", extras = ["all"]}
 
diff --git a/tools/tlc/assets/images/coverage.svg b/tools/tlc/assets/images/coverage.svg
index 3438732..b6c4e36 100644
--- a/tools/tlc/assets/images/coverage.svg
+++ b/tools/tlc/assets/images/coverage.svg
@@ -15,7 +15,7 @@
     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
         <text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
         <text x="31.5" y="14">coverage</text>
-        <text x="80" y="15" fill="#010101" fill-opacity=".3">97%</text>
-        <text x="80" y="14">97%</text>
+        <text x="80" y="15" fill="#010101" fill-opacity=".3">95%</text>
+        <text x="80" y="14">95%</text>
     </g>
 </svg>
diff --git a/tools/tlc/poetry.lock b/tools/tlc/poetry.lock
index 5a39322..839f236 100644
--- a/tools/tlc/poetry.lock
+++ b/tools/tlc/poetry.lock
@@ -386,13 +386,13 @@
 
 [[package]]
 name = "exceptiongroup"
-version = "1.2.1"
+version = "1.2.2"
 description = "Backport of PEP 654 (exception groups)"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
-    {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
+    {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
+    {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
 ]
 
 [package.extras]
@@ -1107,18 +1107,19 @@
 
 [[package]]
 name = "setuptools"
-version = "70.2.0"
+version = "72.1.0"
 description = "Easily download, build, install, upgrade, and uninstall Python packages"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
-    {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
+    {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"},
+    {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"},
 ]
 
 [package.extras]
+core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
 doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
 
 [[package]]
 name = "shellingham"
@@ -1191,13 +1192,13 @@
 
 [[package]]
 name = "tomlkit"
-version = "0.12.5"
+version = "0.13.0"
 description = "Style preserving TOML library"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"},
-    {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"},
+    {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"},
+    {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"},
 ]
 
 [[package]]
@@ -1352,4 +1353,4 @@
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "60bdb4a8b67815f01b4e7089d9f7664afcb9041fa8adf5aa92d977f4e2d5b4b2"
+content-hash = "cfcb196cda412f6139302937640455aa8154d7979c69017fe45ddd528e4a1bf2"
diff --git a/tools/tlc/pyproject.toml b/tools/tlc/pyproject.toml
index 30875a5..5661abf 100644
--- a/tools/tlc/pyproject.toml
+++ b/tools/tlc/pyproject.toml
@@ -37,6 +37,7 @@
 typer = {extras = ["all"], version = "^0.4.0"}
 rich = "^10.14.0"
 click = "^8.1.7"
+pyyaml = "^6.0.1"
 
 [tool.poetry.dev-dependencies]
 bandit = "^1.7.1"
diff --git a/tools/tlc/tests/conftest.py b/tools/tlc/tests/conftest.py
index 6b28e43..b8f88b5 100644
--- a/tools/tlc/tests/conftest.py
+++ b/tools/tlc/tests/conftest.py
@@ -10,6 +10,7 @@
 """ Common configurations and fixtures for test environment."""
 
 import pytest
+import yaml
 from click.testing import CliRunner
 
 from tlc.cli import cli
@@ -21,12 +22,43 @@
 
 
 @pytest.fixture
+def tmpyamlconfig(tmpdir):
+    return tmpdir.join("config.yaml").strpath
+
+
+@pytest.fixture
 def tmpfdt(tmpdir):
     fdt = tmpdir.join("fdt.dtb")
     fdt.write_binary(b"\x00" * 100)
     return fdt
 
 
+@pytest.fixture(params=[1, 2, 3, 4, 5, 0x100, 0x101, 0x102, 0x104])
+def non_empty_tag_id(request):
+    return request.param
+
+
+@pytest.fixture
+def tmpyamlconfig_blob_file(tmpdir, tmpfdt, non_empty_tag_id):
+    config_path = tmpdir.join("config.yaml")
+
+    config = {
+        "has_checksum": True,
+        "max_size": 0x1000,
+        "entries": [
+            {
+                "tag_id": non_empty_tag_id,
+                "blob_file_path": tmpfdt.strpath,
+            },
+        ],
+    }
+
+    with open(config_path, "w") as f:
+        yaml.safe_dump(config, f)
+
+    return config_path
+
+
 @pytest.fixture
 def tlcrunner(tmptlstr):
     runner = CliRunner()
diff --git a/tools/tlc/tests/test_cli.py b/tools/tlc/tests/test_cli.py
index d79773b..99b5816 100644
--- a/tools/tlc/tests/test_cli.py
+++ b/tools/tlc/tests/test_cli.py
@@ -11,8 +11,11 @@
 
 from pathlib import Path
 from unittest import mock
+from math import log2, ceil
 
 import pytest
+import pytest
+import yaml
 from click.testing import CliRunner
 
 from tlc.cli import cli
@@ -203,3 +206,208 @@
         assert result.exit_code == 0
     else:
         assert result.exit_code == 1
+
+
+def test_create_entry_from_yaml_and_blob_file(
+    tlcrunner, tmpyamlconfig_blob_file, tmptlstr, non_empty_tag_id
+):
+    tlcrunner.invoke(
+        cli,
+        [
+            "create",
+            "--from-yaml",
+            tmpyamlconfig_blob_file.strpath,
+            tmptlstr,
+        ],
+    )
+
+    tl = TransferList.fromfile(tmptlstr)
+    assert tl is not None
+    assert len(tl.entries) == 1
+    assert tl.entries[0].id == non_empty_tag_id
+
+
+@pytest.mark.parametrize(
+    "entry",
+    [
+        {"tag_id": 0},
+        {
+            "tag_id": 0x104,
+            "addr": 0x0400100000000010,
+            "size": 0x0003300000000000,
+        },
+        {
+            "tag_id": 0x100,
+            "pp_addr": 100,
+        },
+        {
+            "tag_id": "optee_pageable_part",
+            "pp_addr": 100,
+        },
+    ],
+)
+def test_create_from_yaml_check_sum_bytes(tlcrunner, tmpyamlconfig, tmptlstr, entry):
+    """Test creating a TL from a yaml file, but only check that the sum of the
+    data in the yaml file matches the sum of the data in the TL. This means
+    you don't have to type the exact sequence of expected bytes. All the data
+    in the yaml file must be integers (except for the tag IDs, which can be
+    strings).
+    """
+    # create yaml config file
+    config = {
+        "has_checksum": True,
+        "max_size": 0x1000,
+        "entries": [entry],
+    }
+    with open(tmpyamlconfig, "w") as f:
+        yaml.safe_dump(config, f)
+
+    # invoke TLC
+    tlcrunner.invoke(
+        cli,
+        [
+            "create",
+            "--from-yaml",
+            tmpyamlconfig,
+            tmptlstr,
+        ],
+    )
+
+    # open created TL, and check
+    tl = TransferList.fromfile(tmptlstr)
+    assert tl is not None
+    assert len(tl.entries) == 1
+
+    # Check that the sum of all the data in the transfer entry in the yaml file
+    # is the same as the sum of all the data in the transfer list. Don't count
+    # the tag id or the TE headers.
+
+    # every item in the entry dict must be an integer
+    yaml_total = 0
+    for key, data in iter_nested_dict(entry):
+        if key != "tag_id":
+            num_bytes = ceil(log2(data + 1) / 8)
+            yaml_total += sum(data.to_bytes(num_bytes, "little"))
+
+    tl_total = sum(tl.entries[0].data)
+
+    assert tl_total == yaml_total
+
+
+@pytest.mark.parametrize(
+    "entry,expected",
+    [
+        (
+            {
+                "tag_id": 0x102,
+                "ep_info": {
+                    "h": {
+                        "type": 0x01,
+                        "version": 0x02,
+                        "attr": 8,
+                    },
+                    "pc": 67239936,
+                    "spsr": 965,
+                    "args": [67112976, 67112960, 0, 0, 0, 0, 0, 0],
+                },
+            },
+            (
+                "0x00580201 0x00000008 0x04020000 0x00000000 "
+                "0x000003C5 0x00000000 0x04001010 0x00000000 "
+                "0x04001000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000"
+            ),
+        ),
+        (
+            {
+                "tag_id": 0x102,
+                "ep_info": {
+                    "h": {
+                        "type": 0x01,
+                        "version": 0x02,
+                        "attr": "EP_NON_SECURE | EP_ST_ENABLE",
+                    },
+                    "pc": 67239936,
+                    "spsr": 965,
+                    "args": [67112976, 67112960, 0, 0, 0, 0, 0, 0],
+                },
+            },
+            (
+                "0x00580201 0x00000005 0x04020000 0x00000000 "
+                "0x000003C5 0x00000000 0x04001010 0x00000000 "
+                "0x04001000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000 0x00000000 0x00000000 "
+                "0x00000000 0x00000000"
+            ),
+        ),
+    ],
+)
+def test_create_from_yaml_check_exact_data(
+    tlcrunner, tmpyamlconfig, tmptlstr, entry, expected
+):
+    """Test creating a TL from a yaml file, checking the exact sequence of
+    bytes. This is useful for checking that the alignment is correct. You can
+    get the expected sequence of bytes by copying it from the ArmDS debugger.
+    """
+    # create yaml config file
+    config = {
+        "has_checksum": True,
+        "max_size": 0x1000,
+        "entries": [entry],
+    }
+    with open(tmpyamlconfig, "w") as f:
+        yaml.safe_dump(config, f)
+
+    # invoke TLC
+    tlcrunner.invoke(
+        cli,
+        [
+            "create",
+            "--from-yaml",
+            tmpyamlconfig,
+            tmptlstr,
+        ],
+    )
+
+    # open TL and check
+    tl = TransferList.fromfile(tmptlstr)
+    assert tl is not None
+    assert len(tl.entries) == 1
+
+    # check expected and actual data
+    actual = tl.entries[0].data
+    actual = bytes_to_hex(actual)
+
+    assert actual == expected
+
+
+def bytes_to_hex(data: bytes) -> str:
+    """Convert bytes to a hex string in the same format as the debugger in
+    ArmDS
+
+    You can copy data from the debugger in Arm Development Studio and put it
+    into a unit test. You can then run this function on the output from tlc,
+    and compare it to the data you copied.
+
+    The format is groups of 4 bytes with 0x prefixes separated by spaces.
+    Little endian is used.
+    """
+    words_hex = []
+    for i in range(0, len(data), 4):
+        word = data[i : i + 4]
+        word_int = int.from_bytes(word, "little")
+        word_hex = "0x" + f"{word_int:0>8x}".upper()
+        words_hex.append(word_hex)
+
+    return " ".join(words_hex)
+
+
+def iter_nested_dict(dictionary: dict):
+    for key, value in dictionary.items():
+        if isinstance(value, dict):
+            yield from iter_nested_dict(value)
+        else:
+            yield key, value
diff --git a/tools/tlc/tlc/cli.py b/tools/tlc/tlc/cli.py
index e574e59..1d4949d 100644
--- a/tools/tlc/tlc/cli.py
+++ b/tools/tlc/tlc/cli.py
@@ -12,6 +12,7 @@
 from pathlib import Path
 
 import click
+import yaml
 
 from tlc.tl import *
 
@@ -44,15 +45,26 @@
     show_default=True,
     help="Settings for the TL's properties.",
 )
-def create(filename, size, fdt, entry, flags):
+@click.option(
+    "--from-yaml",
+    type=click.Path(exists=True),
+    help="Create the transfer list from a YAML config file.",
+)
+def create(filename, size, fdt, entry, flags, from_yaml):
     """Create a new Transfer List."""
-    tl = TransferList(size)
+    try:
+        if from_yaml:
+            with open(from_yaml, "r") as f:
+                config = yaml.safe_load(f)
 
-    entry = (*entry, (1, fdt)) if fdt else entry
+            tl = TransferList.from_dict(config)
+        else:
+            tl = TransferList(size)
 
-    try:
-        for id, path in entry:
-            tl.add_transfer_entry_from_file(id, path)
+            entry = (*entry, (1, fdt)) if fdt else entry
+
+            for id, path in entry:
+                tl.add_transfer_entry_from_file(id, path)
     except MemoryError as mem_excp:
         raise MemoryError(
             "TL max size exceeded, consider increasing with the option -s"
diff --git a/tools/tlc/tlc/tl.py b/tools/tlc/tlc/tl.py
index a409651..3f0065d 100644
--- a/tools/tlc/tlc/tl.py
+++ b/tools/tlc/tlc/tl.py
@@ -13,12 +13,67 @@
 import math
 import struct
 from dataclasses import dataclass
+from functools import reduce
 from pathlib import Path
 
 from tlc.te import TransferEntry
 
 TRANSFER_LIST_ENABLE_CHECKSUM = 0b1
 
+# Description of each TE type. For each TE, there is a tag ID, a format (to be
+# used in struct.pack to encode the TE), and a list of field names that can
+# appear in the yaml file for that TE. Some fields are missing, if that TE has
+# to be processed differently, or if it can only be added with a blob file.
+transfer_entry_formats = {
+    0: {
+        "tag_name": "empty",
+        "format": "4x",
+        "fields": [],
+    },
+    1: {
+        "tag_name": "fdt",
+    },
+    2: {
+        "tag_name": "hob_block",
+    },
+    3: {
+        "tag_name": "hob_list",
+    },
+    4: {
+        "tag_name": "acpi_table_aggregate",
+    },
+    5: {
+        "tag_name": "tpm_event_log_table",
+        "fields": ["event_log", "flags"],
+    },
+    6: {
+        "tag_name": "tpm_crb_base_address_table",
+        "format": "QI",
+        "fields": ["crb_base_address", "crb_size"],
+    },
+    0x100: {
+        "tag_name": "optee_pageable_part",
+        "format": "Q",
+        "fields": ["pp_addr"],
+    },
+    0x101: {
+        "tag_name": "dt_spmc_manifest",
+    },
+    0x102: {
+        "tag_name": "exec_ep_info",
+        "format": "2BHIQI4x8Q",
+        "fields": ["ep_info"],
+    },
+    0x104: {
+        "tag_name": "sram_layout",
+        "format": "2Q",
+        "fields": ["addr", "size"],
+    },
+}
+tag_name_to_tag_id = {
+    te["tag_name"]: tag_id for tag_id, te in transfer_entry_formats.items()
+}
+
 
 class TransferList:
     """Class representing a Transfer List based on version 1.0 of the Firmware Handoff specification."""
@@ -96,6 +151,28 @@
 
         return tl
 
+    @classmethod
+    def from_dict(cls, config: dict):
+        """Create a TL from data in a dictionary
+
+        The dictionary should have the same format as the yaml config files.
+        See the readme for more detail.
+
+        :param config: Dictionary containing the data described above.
+        """
+        # get settings from config and set defaults
+        max_size = config.get("max_size", 0x1000)
+        has_checksum = config.get("has_checksum", True)
+
+        flags = TRANSFER_LIST_ENABLE_CHECKSUM if has_checksum else 0
+
+        tl = cls(max_size, flags)
+
+        for entry in config["entries"]:
+            tl.add_transfer_entry_from_dict(entry)
+
+        return tl
+
     def header_to_bytes(self) -> bytes:
         return struct.pack(
             self.encoding,
@@ -141,6 +218,106 @@
             self.update_checksum()
             return te
 
+    def add_transfer_entry_from_struct_format(
+        self, tag_id: int, struct_format: str, *args
+    ):
+        struct_format = "<" + struct_format
+        data = struct.pack(struct_format, *args)
+        return self.add_transfer_entry(tag_id, data)
+
+    def add_entry_point_info_transfer_entry(self, entry: dict) -> "TransferEntry":
+        """Add entry_point_info transfer entry
+
+        :param entry: Dictionary of the transfer entry, in the same format as
+        the YAML file.
+        """
+        ep_info = entry["ep_info"]
+        header = ep_info["h"]
+
+        # size of the entry_point_info struct
+        entry_point_size = 88
+
+        attr = header["attr"]
+        if type(attr) is str:
+            # convert string of flags names to an integer
+
+            # bit number  | 0                     | 1                    |
+            # ------------|-----------------------|----------------------|
+            # 0           | secure                | non-secure           |
+            # 1           | little endian         | big-endian           |
+            # 2           | disable secure timer  | enable secure timer  |
+            # 3           | executable            | non-executable       |
+            # 4           | first exe             | not first exe        |
+            #
+            # Bit 5 and bit 0 are used to determine the security state.
+
+            flag_names = {
+                "EP_SECURE": 0x0,
+                "EP_NON_SECURE": 0x1,
+                "EP_REALM": 0x21,
+                "EP_EE_LITTLE": 0x0,
+                "EP_EE_BIG": 0x2,
+                "EP_ST_DISABLE": 0x0,
+                "EP_ST_ENABLE": 0x4,
+                "EP_NON_EXECUTABLE": 0x0,
+                "EP_EXECUTABLE": 0x8,
+                "EP_FIRST_EXE": 0x10,
+            }
+
+            # create list of integer flags, then bitwise-or them together
+            flags = [flag_names[f.strip()] for f in attr.split("|")]
+            attr = reduce(lambda x, y: x | y, flags)
+
+        return self.add_transfer_entry_from_struct_format(
+            0x102,
+            transfer_entry_formats[0x102]["format"],
+            header["type"],
+            header["version"],
+            entry_point_size,
+            attr,
+            ep_info["pc"],
+            ep_info["spsr"],
+            *ep_info["args"],
+        )
+
+    def add_transfer_entry_from_dict(
+        self,
+        entry: dict,
+    ) -> "TransferEntry":
+        """Add a transfer entry from data in a dictionary
+
+        The dictionary should have the same format as the entries in the yaml
+        config files. See the readme for more detail.
+
+        :param entry: Dictionary containing the data described above.
+        """
+        # Tag_id is either a tag name or a tag id. Use it to get the TE format.
+        tag_id = entry["tag_id"]
+        if tag_id in tag_name_to_tag_id:
+            tag_id = tag_name_to_tag_id[tag_id]
+        te_format = transfer_entry_formats[tag_id]
+        tag_name = te_format["tag_name"]
+
+        if "blob_file_path" in entry:
+            return self.add_transfer_entry_from_file(tag_id, entry["blob_file_path"])
+        elif tag_name == "tpm_event_log_table":
+            with open(entry["event_log"], "rb") as f:
+                event_log_data = f.read()
+
+            flags_bytes = entry["flags"].to_bytes(4, "little")
+            data = flags_bytes + event_log_data
+
+            return self.add_transfer_entry(tag_id, data)
+        elif tag_name == "exec_ep_info":
+            return self.add_entry_point_info_transfer_entry(entry)
+        elif "format" in te_format and "fields" in te_format:
+            fields = [entry[field] for field in te_format["fields"]]
+            return self.add_transfer_entry_from_struct_format(
+                tag_id, te_format["format"], *fields
+            )
+        else:
+            raise ValueError(f"Invalid transfer entry {entry}.")
+
     def add_transfer_entry_from_file(self, tag_id: int, path: Path) -> "TransferEntry":
         with open(path, "rb") as f:
             return self.add_transfer_entry(tag_id, f.read())