Merge "refactor(mediatek): fix mcusys off issue for MTK GIC v3 driver" into integration
diff --git a/Makefile b/Makefile
index e111be2..eca70bd 100644
--- a/Makefile
+++ b/Makefile
@@ -1232,6 +1232,7 @@
 	HARDEN_SLS \
 	HW_ASSISTED_COHERENCY \
 	MEASURED_BOOT \
+	DISCRETE_TPM \
 	DICE_PROTECTION_ENVIRONMENT \
 	RMMD_ENABLE_EL3_TOKEN_SIGN \
 	DRTM_SUPPORT \
@@ -1418,6 +1419,7 @@
 	HW_ASSISTED_COHERENCY \
 	LOG_LEVEL \
 	MEASURED_BOOT \
+	DISCRETE_TPM \
 	DICE_PROTECTION_ENVIRONMENT \
 	DRTM_SUPPORT \
 	NS_TIMER_SWITCH \
@@ -1684,7 +1686,7 @@
 # Add Secure Partition packages
 ifeq (${NEED_SP_PKG},yes)
 $(BUILD_PLAT)/sp_gen.mk: ${SP_MK_GEN} ${SP_LAYOUT_FILE} | $$(@D)/
-	$(if $(host-poetry),$(q)poetry -q install)
+	$(if $(host-poetry),$(q)poetry -q install --no-root)
 	$(q)$(if $(host-poetry),poetry run )${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT}
 sp: $(DTBS) $(BUILD_PLAT)/sp_gen.mk $(SP_PKGS)
 	$(s)echo
diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S
index 678d9c2..91fc682 100644
--- a/bl2/aarch32/bl2_entrypoint.S
+++ b/bl2/aarch32/bl2_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -29,10 +29,10 @@
 	 * use.
 	 * ---------------------------------------------
 	 */
-	mov	r9, r0
-	mov	r10, r1
-	mov	r11, r2
-	mov	r12, r3
+	mov	r8, r0
+	mov	r9, r1
+	mov	r10, r2
+	mov	r11, r3
 
 	/* ---------------------------------------------
 	 * Set the exception vector to something sane.
@@ -114,10 +114,10 @@
 	 * Perform BL2 setup
 	 * ---------------------------------------------
 	 */
-	mov	r0, r9
-	mov	r1, r10
-	mov	r2, r11
-	mov	r3, r12
+	mov	r0, r8
+	mov	r1, r9
+	mov	r2, r10
+	mov	r3, r11
 
 	bl	bl2_setup
 
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index b1f4343..44d1e66 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -83,3 +83,7 @@
 SP_MIN_WITH_SECURE_FIQ 	?= 0
 $(eval $(call add_define,SP_MIN_WITH_SECURE_FIQ))
 $(eval $(call assert_boolean,SP_MIN_WITH_SECURE_FIQ))
+
+ifeq (${TRANSFER_LIST},1)
+BL32_SOURCES	+=	$(TRANSFER_LIST_SOURCES)
+endif
diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
index a85b355..9add239 100644
--- a/bl32/sp_min/sp_min_main.c
+++ b/bl32/sp_min/sp_min_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -113,6 +113,7 @@
 	next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
 	next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1);
 	next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2);
+	next_smc_ctx->r3 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R3);
 	next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
 	next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
 	next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
diff --git a/changelog.yaml b/changelog.yaml
index 422b9da..b612831 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -962,6 +962,9 @@
           - drivers/scmi-msg
           - scmi-msg
 
+      - title: TPM
+        scope: tpm
+
       - title: UFS
         scope: ufs
 
@@ -1273,6 +1276,9 @@
       - title: AArch64
         scope: aarch64
 
+      - title: AArch32
+        scope: aarch32
+
       - title: Debug
         scope: debug
 
diff --git a/docs/components/activity-monitors.rst b/docs/components/activity-monitors.rst
index 4c33d42..d25fcb1 100644
--- a/docs/components/activity-monitors.rst
+++ b/docs/components/activity-monitors.rst
@@ -21,7 +21,9 @@
 
 As a security precaution, Trusted Firmware-A does not enable these by default.
 Instead, platforms must configure their auxiliary counters through the
-``plat_amu_aux_enables`` platform hook.
+``plat_amu_aux_enables`` platform hook. This is a per-core array indexed with
+``plat_my_core_pos()``. A core's value will be written verbatim into
+``AMCNTENSET1_EL0``.
 
 --------------
 
diff --git a/docs/components/rmm-el3-comms-spec.rst b/docs/components/rmm-el3-comms-spec.rst
index dfdabc6..2693e58 100644
--- a/docs/components/rmm-el3-comms-spec.rst
+++ b/docs/components/rmm-el3-comms-spec.rst
@@ -768,47 +768,53 @@
 RMM-EL3 Boot Manifest structure
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The RMM-EL3 Boot Manifest v0.4 structure contains platform boot information passed
-from EL3 to RMM. The size of the Boot Manifest is 112 bytes.
+The RMM-EL3 Boot Manifest v0.5 structure contains platform boot information passed
+from EL3 to RMM. The size of the Boot Manifest is 160 bytes.
 
 The members of the RMM-EL3 Boot Manifest structure are shown in the following
 table:
 
-+--------------------+--------+-------------------+----------------------------------------------+
-|   Name             | Offset |       Type        |            Description                       |
-+====================+========+===================+==============================================+
-| version            |   0    |      uint32_t     | Boot Manifest version                        |
-+--------------------+--------+-------------------+----------------------------------------------+
-| padding            |   4    |      uint32_t     | Reserved, set to 0                           |
-+--------------------+--------+-------------------+----------------------------------------------+
-| plat_data          |   8    |     uintptr_t     | Pointer to Platform Data section             |
-+--------------------+--------+-------------------+----------------------------------------------+
-| plat_dram          |   16   |    memory_info    | NS DRAM Layout Info structure                |
-+--------------------+--------+-------------------+----------------------------------------------+
-| plat_console       |   40   |   console_list    | List of consoles available to RMM            |
-+--------------------+--------+-------------------+----------------------------------------------+
-| plat_ncoh_region   |   64   |    memory_info    | Device non-coherent ranges Info structure    |
-+--------------------+--------+-------------------+----------------------------------------------+
-| plat_coh_region    |   88   |    memory_info    | Device coherent ranges Info structure        |
-+--------------------+--------+-------------------+----------------------------------------------+
++-------------------+--------+-------------------+----------------------------------------------+
+|        Name       | Offset |       Type        |                 Description                  |
++===================+========+===================+==============================================+
+| version           |   0    |      uint32_t     | Boot Manifest version                        |
++-------------------+--------+-------------------+----------------------------------------------+
+| padding           |   4    |      uint32_t     | Reserved, set to 0                           |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_data         |   8    |      uint64_t     | Pointer to Platform Data section             |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_dram         |   16   |    memory_info    | NS DRAM Layout Info structure                |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_console      |   40   |   console_list    | List of consoles available to RMM            |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_ncoh_region  |   64   |    memory_info    | Device non-coherent ranges Info structure    |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_coh_region   |   88   |    memory_info    | Device coherent ranges Info structure        |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_smmu         |   112  |     smmu_list     | List of SMMUs available to RMM               |
+|                   |        |                   | (from Boot Manifest v0.5)                    |
++-------------------+--------+-------------------+----------------------------------------------+
+| plat_root_complex |   136  | root_complex_list | List of PCIe root complexes available to RMM |
+|                   |        |                   | (from Boot Manifest v0.5)                    |
++-------------------+--------+-------------------+----------------------------------------------+
 
 .. _memory_info_struct:
 
 Memory Info structure
-~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~
 
 Memory Info structure contains information about platform memory layout.
 The members of this structure are shown in the table below:
 
-+-----------+--------+----------------+----------------------------------------+
-|   Name    | Offset |     Type       |               Description              |
-+===========+========+================+========================================+
-| num_banks |   0    |   uint64_t     | Number of memory banks/device regions  |
-+-----------+--------+----------------+----------------------------------------+
-| banks     |   8    |  memory_bank * | Pointer to 'memory_bank'[] array       |
-+-----------+--------+----------------+----------------------------------------+
-| checksum  |   16   |   uint64_t     | Checksum                               |
-+-----------+--------+----------------+----------------------------------------+
++-----------+--------+---------------+----------------------------------------+
+|   Name    | Offset |     Type      |              Description               |
++===========+========+===============+========================================+
+| num_banks |   0    |    uint64_t   | Number of memory banks/device regions  |
++-----------+--------+---------------+----------------------------------------+
+| banks     |   8    | memory_bank * | Pointer to 'memory_bank'[] array       |
++-----------+--------+---------------+----------------------------------------+
+| checksum  |   16   |    uint64_t   | Checksum                               |
++-----------+--------+---------------+----------------------------------------+
 
 Checksum is calculated as two's complement sum of 'num_banks', 'banks' pointer
 and memory banks data array pointed by it.
@@ -820,13 +826,13 @@
 
 Memory Bank structure contains information about each memory bank/device region:
 
-+-----------+--------+----------------+--------------------------------------------+
-|   Name    | Offset |     Type       |                Description                 |
-+===========+========+================+============================================+
-|   base    |   0    |   uintptr_t    | Base address                               |
-+-----------+--------+----------------+--------------------------------------------+
-|   size    |   8    |   uint64_t     | Size of memory bank/device region in bytes |
-+-----------+--------+----------------+--------------------------------------------+
++------+--------+----------+--------------------------------------------+
+| Name | Offset |   Type   |                Description                 |
++======+========+==========+============================================+
+| base |   0    | uint64_t | Base address                               |
++------+--------+----------+--------------------------------------------+
+| size |   8    | uint64_t | Size of memory bank/device region in bytes |
++------+--------+----------+--------------------------------------------+
 
 .. _console_list_struct:
 
@@ -836,15 +842,15 @@
 Console List structure contains information about the available consoles for RMM.
 The members of this structure are shown in the table below:
 
-+--------------+--------+----------------+-------------------------------------+
-|   Name       | Offset |     Type       |               Description           |
-+==============+========+================+=====================================+
-| num_consoles |   0    |   uint64_t     | Number of consoles                  |
-+--------------+--------+----------------+-------------------------------------+
-| consoles     |   8    | console_info * | Pointer to 'console_info'[] array   |
-+--------------+--------+----------------+-------------------------------------+
-| checksum     |   16   |   uint64_t     | Checksum                            |
-+--------------+--------+----------------+-------------------------------------+
++--------------+--------+----------------+-----------------------------------+
+|   Name       | Offset |     Type       |           Description             |
++==============+========+================+===================================+
+| num_consoles |   0    |   uint64_t     | Number of consoles                |
++--------------+--------+----------------+-----------------------------------+
+| consoles     |   8    | console_info * | Pointer to 'console_info'[] array |
++--------------+--------+----------------+-----------------------------------+
+| checksum     |   16   |   uint64_t     | Checksum                          |
++--------------+--------+----------------+-----------------------------------+
 
 Checksum is calculated as two's complement sum of 'num_consoles', 'consoles'
 pointer and the consoles array pointed by it.
@@ -856,21 +862,144 @@
 
 Console Info structure contains information about each Console available to RMM.
 
-+-----------+--------+---------------+-----------------------------------------+
-|   Name    | Offset |     Type      |               Description               |
-+===========+========+===============+=========================================+
-| base      |   0    |   uintptr_t   | Console Base address                    |
-+-----------+--------+---------------+-----------------------------------------+
-| map_pages |   8    |   uint64_t    | Num of pages to map for console MMIO    |
-+-----------+--------+---------------+-----------------------------------------+
-| name      |   16   |   char[8]     | Name of console                         |
-+-----------+--------+---------------+-----------------------------------------+
-| clk_in_hz |   24   |   uint64_t    | UART clock (in Hz) for console          |
-+-----------+--------+---------------+-----------------------------------------+
-| baud_rate |   32   |   uint64_t    | Baud rate                               |
-+-----------+--------+---------------+-----------------------------------------+
-| flags     |   40   |   uint64_t    | Additional flags (RES0)                 |
-+-----------+--------+---------------+-----------------------------------------+
++-----------+--------+----------+--------------------------------------+
+|   Name    | Offset |   Type   |             Description              |
++===========+========+==========+======================================+
+| base      |   0    | uint64_t | Console Base address                 |
++-----------+--------+----------+--------------------------------------+
+| map_pages |   8    | uint64_t | Num of pages to map for console MMIO |
++-----------+--------+----------+--------------------------------------+
+| name      |   16   | char[8]  | Name of console                      |
++-----------+--------+----------+--------------------------------------+
+| clk_in_hz |   24   | uint64_t | UART clock (in Hz) for console       |
++-----------+--------+----------+--------------------------------------+
+| baud_rate |   32   | uint64_t | Baud rate                            |
++-----------+--------+----------+--------------------------------------+
+| flags     |   40   | uint64_t | Additional flags (RES0)              |
++-----------+--------+----------+--------------------------------------+
+
+.. _smmu_list_struct:
+
+SMMU List structure
+~~~~~~~~~~~~~~~~~~~
+
+SMMU List structure contains information about SMMUs available for RMM.
+The members of this structure are shown in the table below:
+
++-----------+--------+-------------+--------------------------------+
+|    Name   | Offset |     Type    |          Description           |
++===========+========+=============+================================+
+| num_smmus |   0    |   uint64_t  | Number of SMMUs                |
++-----------+--------+-------------+--------------------------------+
+| smmus     |   8    | smmu_info * | Pointer to 'smmu_info'[] array |
++-----------+--------+-------------+--------------------------------+
+| checksum  |   16   |   uint64_t  | Checksum                       |
++-----------+--------+-------------+--------------------------------+
+
+.. _smmu_info_struct:
+
+SMMU Info structure
+~~~~~~~~~~~~~~~~~~~
+
+SMMU Info structure contains information about each SMMU available to RMM.
+
++-------------+--------+----------+-------------------------------+
+|    Name     | Offset |   Type   |          Description          |
++=============+========+==========+===============================+
+| smmu_base   |   0    | uint64_t | SMMU Base address             |
++-------------+--------+----------+-------------------------------+
+| smmu_r_base |   8    | uint64_t | SMMU Realm Pages base address |
++-------------+--------+----------+-------------------------------+
+
+.. _root_complex_list_struct:
+
+Root Complex List structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Root Complex List structure contains information about PCIe root complexes available for RMM.
+The members of this structure are shown in the table below.
+
++------------------+--------+---------------------+-------------------------------------+
+|       Name       | Offset |        Type         |           Description               |
++==================+========+=====================+=====================================+
+| num_root_complex |   0    |      uint64_t       | Number of root complexes            |
++------------------+--------+---------------------+-------------------------------------+
+| rc_info_version  |   8    |      uint32_t       | Root Complex Info structure version |
++------------------+--------+---------------------+-------------------------------------+
+| padding          |   12   |      uint32_t       | Reserved, set to 0                  |
++------------------+--------+---------------------+-------------------------------------+
+| root_complex     |   16   | root_complex_info * | Pointer to 'root_complex'[] array   |
++------------------+--------+---------------------+-------------------------------------+
+| checksum         |   24   |      uint64_t       | Checksum                            |
++------------------+--------+---------------------+-------------------------------------+
+
+The checksum calculation of Root Complex List structure includes all data structures
+referenced by 'root_complex_info' pointer.
+
+.. _root_complex_info_struct:
+
+Root Complex Info structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Root Complex Info structure contains information about each PCIe root complex available to RMM.
+The table below describes the members of this structure as per v0.1.
+
++-----------------+--------+------------------+-------------------------------------+
+|    Name         | Offset |       Type       |               Description           |
++=================+========+==================+=====================================+
+| ecam_base       |   0    |     uint64_t     | PCIe ECAM Base address              |
++-----------------+--------+------------------+-------------------------------------+
+| segment         |   8    |     uint8_t      | PCIe segment identifier             |
++-----------------+--------+------------------+-------------------------------------+
+| padding[3]      |   9    |     uint8_t      | Reserved, set to 0                  |
++-----------------+--------+------------------+-------------------------------------+
+| num_root_ports  |   12   |     uint32_t     | Number of root ports                |
++-----------------+--------+------------------+-------------------------------------+
+| root_ports      |   16   | root_port_info * | Pointer to 'root_port_info'[] array |
++-----------------+--------+------------------+-------------------------------------+
+
+The Root Complex Info structure version uses the same numbering scheme as described in
+:ref:`rmm_el3_ifc_versioning`.
+
+.. _root_port_info_struct:
+
+Root Port Info structure
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Root Complex Info structure contains information about each root port in PCIe root complex.
+
++------------------+--------+--------------------+---------------------------------------+
+|      Name        | Offset |       Type         |              Description              |
++==================+========+====================+=======================================+
+| root_port_id     |   0    |     uint16_t       | Root Port identifier                  |
++------------------+--------+--------------------+---------------------------------------+
+| padding          |   2    |     uint16_t       | Reserved, set to 0                    |
++------------------+--------+--------------------+---------------------------------------+
+| num_bdf_mappings |   4    |     uint32_t       | Number of BDF mappings                |
++------------------+--------+--------------------+---------------------------------------+
+| bdf_mappings     |   8    | bdf_mapping_info * | Pointer to 'bdf_mapping_info'[] array |
++------------------+--------+--------------------+---------------------------------------+
+
+.. _bdf_mapping_info_struct:
+
+BDF Mapping Info structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BDF Mapping Info structure contains information about each Device-Bus-Function (BDF) mapping
+for PCIe root port.
+
++--------------+--------+----------+------------------------------------------------------+
+|     Name     | Offset |   Type   |                     Description                      |
++==============+========+==========+======================================================+
+| mapping_base |   0    | uint16_t | Base of BDF mapping (inclusive)                      |
++--------------+--------+----------+------------------------------------------------------+
+| mapping_top  |   2    | uint16_t | Top of BDF mapping (exclusive)                       |
++--------------+--------+----------+------------------------------------------------------+
+| mapping_off  |   4    | uint16_t | Mapping offset, as per Arm Base System Architecture: |
+|              |        |          | StreamID = RequesterID[N-1:0] + (1<<N)*Constant_B    |
++--------------+--------+----------+------------------------------------------------------+
+| smmu_idx     |   6    | uint16_t | SMMU index in 'smmu_info'[] array                    |
++--------------+--------+----------+------------------------------------------------------+
 
 .. _el3_token_sign_request_struct:
 
diff --git a/docs/design_documents/dtpm_drivers.rst b/docs/design_documents/dtpm_drivers.rst
new file mode 100644
index 0000000..324af03
--- /dev/null
+++ b/docs/design_documents/dtpm_drivers.rst
@@ -0,0 +1,119 @@
+Discrete TPM drivers
+====================
+
+This section focuses on the design and functionality of Discrete TPM drivers
+in |TF-A|. The |TPM| technology is designed to provide
+a dedicated, hardware-based solution for storing cryptographic keys and
+performing security-related operations.
+
+Discrete TPMs are separate, standalone hardware components that are physically
+isolated from the system's main processor. This isolation helps protect
+sensitive information, such as encryption keys and platform credentials, from
+being accessed or tampered with by malicious software or unauthorized users.
+When a Discrete TPM interface is implemented correctly, the risk of software
+based attacks is reduced, further reducing the attack surface.
+
+TPM measurements establish the security posture of a system and are used for
+attestation. Performing measurements using a TPM in TF-A is beneficial from
+a security standpoint because it ensures hardware-backed attestation earlier
+in the boot flow, reducing the risk of a compromised root of trust.
+
+The design implemented in TF-A supports multiple types of TPM hardware interfaces
+and hardware bus types in order to be compatible with different platforms.
+Platforms opt to use a specific messaging interface, such as |CRB| or |FIFO|,
+and a specific hardware bus interface, such as |I2C| or |SPI|.
+
+Driver architecture
+-------------------
+
+The Discrete TPM drivers are split up into four layers, each serving a distinct
+purpose in the overall architecture:
+
+   - **Command Layer**: This layer provides various TPM commands based on the
+     `TCG TPM 2.0 Library Specification`_. It allows a system to initialize the
+     TPM interface, perform a TPM startup, set up a locality for operations like
+     PCR extend and read, and release the locality when finished.
+   - **Interface Layer**: This layer handles sending and receiving TPM commands
+     via a specific TPM interface like FIFO or CRB. It also includes functions
+     such as getting information, requesting access, and relinquishing access,
+     tailored to the specific interface.
+   - **Link Layer**: Discrete TPMs may appear as a SPI, I2C, or memory mapped
+     device. The link layer maps the command passed from the interface layer to
+     the appropriate bus type. It includes hardware link read and write functions
+     that use the platform bus interface to transfer commands.
+   - **Platform Layer**: The platform layer implements the details of how to
+     communicate to the TPM chip for a specific platform. The link layer uses the
+     platform layer to read and write to the TPM.
+
+   .. note::
+      The command, interface, and link layers are implemented in common code in
+      TF-A. The platform layer is implemented in platform specific code.
+
+The following diagram illustrates the Discrete TPM driver stack for the Raspberry
+Pi 3 platform.
+
+|rpi3 dtpm driver stack|
+
+Header files
+^^^^^^^^^^^^
+- TPM Drivers: ``include/drivers/tpm``
+
+
+Source files
+^^^^^^^^^^^^
+- TPM Drivers: ``drivers/tpm``
+
+
+Build time config options
+-------------------------
+
+- ``MBOOT_TPM_HASH_ALG``: The hash algorithm to be used by the TPM, currently
+  the only supported algorithm is ``sha256``. As additional Discrete TPMs are
+  tested and integrated in TF-A, support for more algorithms will become
+  available.
+- ``DISCRETE_TPM``: Boolean flag to enable Discrete TPM support. Depending
+  on the selected TPM interface, the appropriate drivers will be built and
+  packaged into firmware.
+- ``TPM_INTERFACE``: This flag is required when ``DISCRETE_TPM=1``,
+  currently the only supported interface is ``FIFO_SPI``.
+  Ideally there should be four options:
+
+  .. code:: shell
+
+      FIFO_I2C
+      FIFO_SPI
+      FIFO_MMIO
+      CRB
+
+  .. note::
+    ``MBOOT_TPM_HASH_ALG`` will automatically overwrite ``MBOOT_EL_HASH_ALG``.
+    This is to ensure the event log and the TPM are using the same hash
+    algorithm.
+
+
+Discrete TPM Initialization
+---------------------------
+The TPM needs to be initialized based on the platform, the hardware interfaces
+need to be set up independently, and once they are setup, the TPM commands
+``tpm_interface_init()`` and subsequently ``tpm_startup()`` can be called.
+``tpm_startup()`` only needs to be called once after startup, or if the system
+is reset.
+
+An example of platform specific TPM hardware initialization for the rpi3 can be
+found in ``plat/rpi/rpi3/rpi3_bl1_setup.c`` and ``plat/rpi/rpi3/rpi3_bl1_mboot.c``
+
+
+Discrete TPM PCR Extend
+-----------------------
+Once the TPM is setup, the TPM ``pcr_extend`` operation can be used to extend
+hashes and store them in PCR 0.
+
+An example of ``pcr_extend`` that is used during rpi3 measured boot can be found
+ in ``plat/rpi/rpi3/rpi3_bl1_mboot.c`` and ``plat/rpi/rpi3/rpi3_bl2_mboot.c``.
+
+
+*Copyright (c) 2025, Arm Limited. All rights reserved.*
+
+.. |rpi3 dtpm driver stack| image::
+   ../resources/diagrams/rpi3_dtpm_driver.png
+.. _TCG TPM 2.0 Library Specification: https://trustedcomputinggroup.org/resource/tpm-library-specification/
diff --git a/docs/design_documents/index.rst b/docs/design_documents/index.rst
index f1d8386..11c1c5a 100644
--- a/docs/design_documents/index.rst
+++ b/docs/design_documents/index.rst
@@ -7,10 +7,12 @@
 
    cmake_framework
    measured_boot_poc
+   measured_boot_dtpm_poc
    drtm_poc
    rse
    psci_osi_mode
    measured_boot
+   dtpm_drivers
 
 --------------
 
diff --git a/docs/design_documents/measured_boot.rst b/docs/design_documents/measured_boot.rst
index 005903e..1f76770 100644
--- a/docs/design_documents/measured_boot.rst
+++ b/docs/design_documents/measured_boot.rst
@@ -91,6 +91,14 @@
    and the variable length crypto agile structure called TCG_PCR_EVENT2. Event
    Log driver implemented in TF-A covers later part.
 
+#. Discrete TPM
+
+   A Discrete TPM (Trusted Platform Module) can be used alongside Event Log to
+   extend measurements and validate Measured Boot functionality. The use of a
+   Discrete TPM in TF-A to extend measurements of images and other critical data
+   allows for an additional layer of security. The TPM can be used to attest the
+   integrity of the Event Log.
+
 #. |RSE|
 
    It is one of the physical backends to extend the measurements. Please refer
@@ -229,7 +237,7 @@
 
 --------------
 
-*Copyright (c) 2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2023-2025, Arm Limited. All rights reserved.*
 
 .. _Arm® Server Base Security Guide: https://developer.arm.com/documentation/den0086/latest
 .. _TCG EFI Protocol Specification: https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf
diff --git a/docs/design_documents/measured_boot_dtpm_poc.rst b/docs/design_documents/measured_boot_dtpm_poc.rst
new file mode 100644
index 0000000..63a12f2
--- /dev/null
+++ b/docs/design_documents/measured_boot_dtpm_poc.rst
@@ -0,0 +1,458 @@
+Measured Boot using a Discrete TPM (PoC)
+========================================
+
+Measured Boot is the process of cryptographically measuring the code and
+critical data used at boot time, for example using a TPM, so that the
+security state can be attested later.
+
+The current implementation of the driver included in |TF-A| supports several
+backends and each has a different means to store the measurements.
+This section focuses on the Discrete TPM backend, which stores measurements
+in a PCR within the TPM. This backend can be paired with the `TCG event log`_
+to provide attestation of the measurements stored in the event log. See
+details in :ref:`Measured Boot Design`.
+
+This section provides instructions to setup and build a proof of concept (PoC)
+that showcases the use of Measured Boot with a Discrete TPM interface.
+
+.. note::
+   The instructions given in this document are meant to build a PoC to
+   show how Measured Boot on TF-A can interact with a Discrete TPM interface.
+   This PoC is platform specific, and uses a SPI based Discrete TPM, the
+   Raspberry Pi communicates with the TPM via a GPIO pin bit-banged SPI interface.
+   For other platforms, different may be required to interface with the hardware
+   (e.g., different hardware communication protocols) and different TPM interfaces
+   (e.g., |FIFO| vs |CRB|).
+
+Components
+~~~~~~~~~~
+
+   - **Platform**: The PoC is developed on the Raspberry Pi 3 (rpi3), due to quick
+     driver development and the availability of GPIO pins to interface with a TPM
+     expansion module. Measured boot capabilities using the TCG Event Log are
+     ported to the Raspberry Pi 3 platform inside TF-A. This PoC specifically uses
+     the Raspberry Pi 3 Model B V1.2, but this PoC is compatible with other
+     Raspberry Pi 3 models.
+
+   - **Discrete TPM**: The TPM chip selected is a breakout board compatible with
+     the Raspberry Pi 3 GPIO pins. This PoC uses a |SPI| based LetsTrust TPM
+     breakout board equipped with a Infineon Optiga™ SLB 9670 TPM 2.0 chip. Link
+     to device: https://thepihut.com/products/letstrust-tpm-for-raspberry-pi
+
+   .. note::
+      If you have another TPM breakout board that uses the same
+      Infineon Optiga™ SLB 9670 TPM 2.0 SPI based chip, it will also work.
+      Ensure that the correct GPIO pins are utilized on the Raspberry Pi 3 to
+      avoid communication issues, and possible hardware failures.
+
+   - **TF-A TPM Drivers**: To interface with a physical (Discrete) TPM chip in
+     TF-A, the PoC uses TF-A drivers that provide the command, interface, link,
+     and platform layers required to send and receive data to and from the TPM.
+     The drivers are located in TFA, and not in a |SP|, so that they may be used
+     in early stages such as BL2, and in some cases, BL1. The design of the TPM
+     Drivers is documented here: :ref:`Discrete TPM drivers`.
+
+   - **U-boot BL33**: This PoC showcases measured boot up to BL33, and for
+     simplicity uses a U-boot image for BL33, so that the image is measured and
+     loaded. Currently U-boot does not have Discrete TPM support for the
+     Raspberry Pi 3 platform so the boot flow ends here.
+
+
+Building the PoC for the Raspberry Pi 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Build instructions for U-Boot.bin for Raspberry Pi 3.**
+
+First, the build requires a BL33 firmware image that can be packaged and measured
+by TF-A.
+
+U-boot can be built for the Raspberry Pi 3, but there are some changes to be made
+to allow the build to succeed. First Clone U-boot and enter the repo.
+
+.. code:: shell
+
+    git clone https://github.com/u-boot/u-boot.git
+    cd u-boot
+
+Now to switch to a specific tag ``v2024.04``  for testing purposes, and then build
+the defconfig labelled ``rpi_3_b_plus_defconfig``.
+
+.. code:: shell
+
+    git checkout tags/v2024.04 -b tfa_dtpm_poc
+    make CROSS_COMPILE=aarch64-linux-gnu- rpi_3_b_plus_defconfig
+
+Lastly open the ``.config`` and change ``CONFIG_TEXT_BASE`` and
+``CONFIG_SYS_UBOOT_START`` to ``0x11000000`` to match the BL33 starting point.
+
+.. code:: shell
+
+    vim .config
+    CONFIG_TEXT_BASE=0x11000000
+    CONFIG_SYS_UBOOT_START=0x11000000
+
+To build the u-boot binary, use the following command.
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
+
+**Build TF-A for Raspberry Pi 3 with Discrete TPM and Measured Boot.**
+
+Copy over the ``u-boot.bin`` file over to your TF-A working directory.
+
+.. code:: shell
+
+    cp /path/to/u-boot/build/u-boot.bin /path/to/tfa/u-boot.bin
+
+TF-A build command:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu-      \
+    make PLAT=rpi3                        \
+    RPI3_PRELOADED_DTB_BASE=0x200000      \
+    BL33=u-boot.bin                       \
+    SUPPORT_VFP=1                         \
+    DEBUG=0                               \
+    MEASURED_BOOT=1                       \
+    DISCRETE_TPM=1                        \
+    MBOOT_TPM_HASH_ALG=sha256             \
+    TPM_INTERFACE=FIFO_SPI                \
+    MBEDTLS_DIR=/path/to/mbedtls/repo     \
+    LOG_LEVEL=40                          \
+    fip all
+
+This build command is similar to the one provided in the TF-A Raspberry Pi 3
+platform port, To learn more about the platform and its build options, visit
+:ref:`Raspberry Pi 3`.
+
+   - ``RPI3_PRELOADED_DTB_BASE`` is given a different address to accommodate the
+     larger BL1 and BL2 firmware sizes, this is to accommodate the TPM drivers
+     that are packaged in BL1 and BL2 for this PoC.
+   - ``BL33`` is the non trusted firmware, in this case the U-Boot binary built
+     earlier.
+   - ``SUPPORT_VFP`` is enabled, allows Vector Floating Point operations in EL3.
+   - ``MEASURED_BOOT`` is enabled to allow the Measured Boot flow.
+   - ``DISCRETE_TPM=1`` enables the build of Discrete TPM drivers.
+   - ``MBOOT_TPM_HASH_ALG=sha256`` sets the hash algorithm to sha256, this is
+     the only algorithm supported by both TF-A Measured Boot and the SLB 9670
+     TPM 2.0.
+   - ``TPM_INTERFACE=FIFO_SPI`` specifies the use of the FIFO SPI interface.
+   - ``MBEDTLS_DIR`` is the path to your local mbedtls repo.
+   - ``LOG_LEVEL=40`` ensures that eventlog is printed at the end of BL1 and BL2.
+
+
+**Hardware Setup:**
+
+   - **TPM Connection**: Connect the LetsTrust TPM board to GPIO pins 17 - 26 on
+     the 40-pin GPIO header on the Raspberry Pi board. The 2x5 header of the TPM
+     module must be aligned to the pins in a specific orientation, match the 3v3
+     and RST pins from the TPM board to pins 17 and 18 respectively on the
+     Raspberry Pi 3 header. See `rpi3 pinout`_.
+
+   - **Serial Console**: Establish a serial connection to the Raspberry Pi 3 to
+     view serial output during the boot sequence. The GND, TXD, and RXD pins,
+     which are labelled 6, 8, and 10 on the Raspberry Pi 3 header respectively,
+     are the required pins to establish a serial connection. The recommended way
+     to connect to the board from another system is to use a USB to serial TTL
+     cable to output the serial console in a easy manner.
+
+   - **SD Card Setup**: Format a SD Card as ``FAT32`` with a default Raspbian
+     installation that is similar to the default Raspberry Pi 3 boot partition,
+     this partition will utilize the default files installed in the root
+     directory with Rasbian such as:
+
+    ::
+
+        bcm2710-rpi3-b.dtb
+        bootcode.bin
+        config.txt
+        fixup.dat
+        start.elf
+
+    Open ``config.txt`` and overwrite the file with the following lines:
+
+    ::
+
+        arm_64bit=1
+        disable_commandline_tags=2
+        enable_uart=1
+        armstub=armstub8.bin
+        device_tree_address=0x200000
+        device_tree_end=0x210000
+
+    These configurations are required to enable uart, enable 64bit mode,
+    use the build TF binary, and the modified rpi3 device tree address
+    and size.
+
+    Copy ``armstub8.bin`` from the TF-A build path to the root folder of the
+    SD card.
+
+    The SD Card is now ready to be booted.
+
+Running the PoC for the Raspberry Pi 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Insert the SD Card into the Raspberry Pi 3 SD card port and boot the system.
+
+To access the serial console output from the Raspberry Pi 3 you can either:
+
+   - Follow `instructions`_ to use PuTTY to connect to Raspberry Pi 3 serial console.
+
+   - Use the linux ``screen`` command:
+
+      .. code:: shell
+
+        screen /dev/ttyUSB0 115200
+
+Once booted the output from the serial console will look like this:
+
+.. code:: shell
+
+    Raspberry Pi Bootcode
+
+    Read File: config.txt, 153
+
+    Read File: start.elf, 2975040 (bytes)
+
+    Read File: fixup.dat, 7265 (bytes)
+
+    MESS:00:00:01.170422:0: brfs: File read: /mfs/sd/config.txt
+    MESS:00:00:01.174630:0: brfs: File read: 153 bytes
+    MESS:00:00:01.211473:0: HDMI0:EDID error reading EDID block 0 attempt 0
+    MESS:00:00:01.217639:0: HDMI0:EDID error reading EDID block 0 attempt 1
+    MESS:00:00:01.223977:0: HDMI0:EDID error reading EDID block 0 attempt 2
+    MESS:00:00:01.230313:0: HDMI0:EDID error reading EDID block 0 attempt 3
+    MESS:00:00:01.236650:0: HDMI0:EDID error reading EDID block 0 attempt 4
+    MESS:00:00:01.242987:0: HDMI0:EDID error reading EDID block 0 attempt 5
+    MESS:00:00:01.249324:0: HDMI0:EDID error reading EDID block 0 attempt 6
+    MESS:00:00:01.255660:0: HDMI0:EDID error reading EDID block 0 attempt 7
+    MESS:00:00:01.261997:0: HDMI0:EDID error reading EDID block 0 attempt 8
+    MESS:00:00:01.268334:0: HDMI0:EDID error reading EDID block 0 attempt 9
+    MESS:00:00:01.274429:0: HDMI0:EDID giving up on reading EDID block 0
+    MESS:00:00:01.282647:0: brfs: File read: /mfs/sd/config.txt
+    MESS:00:00:01.286929:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
+    MESS:00:00:01.487295:0: gpioman: gpioman_get_pin_num: pin DISPLAY_DSI_PORT not defined
+    MESS:00:00:01.494853:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
+    MESS:00:00:01.500763:0: *** Restart logging
+    MESS:00:00:01.504638:0: brfs: File read: 153 bytes
+    MESS:00:00:01.510139:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 0
+    MESS:00:00:01.517254:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 1
+    MESS:00:00:01.524112:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 2
+    MESS:00:00:01.530970:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 3
+    MESS:00:00:01.537826:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 4
+    MESS:00:00:01.544685:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 5
+    MESS:00:00:01.551543:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 6
+    MESS:00:00:01.558399:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 7
+    MESS:00:00:01.565258:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 8
+    MESS:00:00:01.572116:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 9
+    MESS:00:00:01.578730:0: hdmi: HDMI0:EDID giving up on reading EDID block 0
+    MESS:00:00:01.584634:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 0
+    MESS:00:00:01.592427:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 1
+    MESS:00:00:01.599286:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 2
+    MESS:00:00:01.606142:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 3
+    MESS:00:00:01.613001:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 4
+    MESS:00:00:01.619858:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 5
+    MESS:00:00:01.626717:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 6
+    MESS:00:00:01.633575:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 7
+    MESS:00:00:01.640431:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 8
+    MESS:00:00:01.647288:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 9
+    MESS:00:00:01.653905:0: hdmi: HDMI0:EDID giving up on reading EDID block 0
+    MESS:00:00:01.659769:0: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
+    MESS:00:00:01.668264:0: HDMI0: hdmi_pixel_encoding: 162000000
+    MESS:00:00:01.673988:0: vec: vec_middleware_power_on: vec_base: 0x7e806000 rev-id 0x00002708 @ vec: 0x7e806100 @ 0x00000420 enc: 0x7e806060 @ 0x00000220 cgmsae: 0x7e80605c @ 0x00000000
+    MESS:00:00:01.880234:0: dtb_file 'bcm2710-rpi-3-b.dtb'
+    MESS:00:00:01.889713:0: brfs: File read: /mfs/sd/bcm2710-rpi-3-b.dtb
+    MESS:00:00:01.894375:0: Loaded 'bcm2710-rpi-3-b.dtb' to 0x200000 size 0x7cb2
+    MESS:00:00:01.915761:0: brfs: File read: 31922 bytes
+    MESS:00:00:02.007202:0: brfs: File read: /mfs/sd/config.txt
+    MESS:00:00:02.017277:0: brfs: File read: 153 bytes
+    MESS:00:00:02.020772:0: Failed to open command line file 'cmdline.txt'
+    MESS:00:00:02.042302:0: gpioman: gpioman_get_pin_num: pin EMMC_ENABLE not defined
+    MESS:00:00:02.398066:0: kernel=
+    MESS:00:00:02.455255:0: brfs: File read: /mfs/sd/armstub8.bin
+    MESS:00:00:02.459284:0: Loaded 'armstub8.bin' to 0x0 size 0xdbe74
+    MESS:00:00:02.465109:0: No compatible kernel found
+    MESS:00:00:02.469610:0: Device tree loaded to 0x200000 (size 0x823f)
+    MESS:00:00:02.476805:0: uart: Set PL011 baud rate to 103448.300000 Hz
+    MESS:00:00:02.483381:0: uart: Baud rate change done...
+    MESS:00:00:02.486793:0: uart: Baud rateNOTICE:  Booting Trusted Firmware
+    NOTICE:  BL1: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+    NOTICE:  BL1: Built : 10:57:10, Jul  9 2024
+    INFO:    BL1: RAM 0x100ee000 - 0x100f9000
+    INFO:    Using crypto library 'mbed TLS'
+    NOTICE:  TPM Chip: vendor-id 0xd1, device-id 0x0, revision-id: 0x16
+    NOTICE:  rpi3: Detected: Raspberry Pi 3 Model B (1GB, Sony, UK) [0x00a02082]
+    INFO:    BL1: Loading BL2
+    INFO:    Loading image id=1 at address 0x100b4000
+    INFO:    Image id=1 loaded: 0x100b4000 - 0x100c0281
+    INFO:    TCG_EfiSpecIDEvent:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 3
+    INFO:      Digest             : 00
+    INFO:          : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:          : 00 00 00
+    INFO:      EventSize          : 33
+    INFO:      Signature          : Spec ID Event03
+    INFO:      PlatformClass      : 0
+    INFO:      SpecVersion        : 2.0.2
+    INFO:      UintnSize          : 1
+    INFO:      NumberOfAlgorithms : 1
+    INFO:      DigestSizes        :
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           DigestSize    : 32
+    INFO:      VendorInfoSize     : 0
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 3
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:          : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:      EventSize          : 17
+    INFO:      Signature          : StartupLocality
+    INFO:      StartupLocality    : 0
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 1
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : 55 11 51 d8 8b 7f 41 d3 18 16 f2 e8 80 bf 80 fa
+    INFO:          : b4 03 6d 96 4c a0 0a 98 45 cf 25 2f 1e a9 09 3e
+    INFO:      EventSize          : 5
+    INFO:      Event              : BL_2
+    NOTICE:  BL1: Booting BL2
+    INFO:    Entry point address = 0x100b4000
+    INFO:    SPSR = 0x3c5
+    NOTICE:  BL2: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+    NOTICE:  BL2: Built : 10:56:39, Jul  9 2024
+    INFO:    Using crypto library 'mbed TLS'
+    NOTICE:  TPM Chip: vendor-id 0xd1, device-id 0x0, revision-id: 0x16
+    INFO:    BL2: Doing platform setup
+    INFO:    BL2: Loading image id 3
+    INFO:    Loading image id=3 at address 0x100e0000
+    INFO:    Image id=3 loaded: 0x100e0000 - 0x100e706b
+    INFO:    BL2: Loading image id 5
+    INFO:    Loading image id=5 at address 0x11000000
+    INFO:    Image id=5 loaded: 0x11000000 - 0x110a8ad8
+    INFO:    TCG_EfiSpecIDEvent:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 3
+    INFO:      Digest             : 00
+    INFO:          : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:          : 00 00 00
+    INFO:      EventSize          : 33
+    INFO:      Signature          : Spec ID Event03
+    INFO:      PlatformClass      : 0
+    INFO:      SpecVersion        : 2.0.2
+    INFO:      UintnSize          : 1
+    INFO:      NumberOfAlgorithms : 1
+    INFO:      DigestSizes        :
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           DigestSize    : 32
+    INFO:      VendorInfoSize     : 0
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 3
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:          : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+    INFO:      EventSize          : 17
+    INFO:      Signature          : StartupLocality
+    INFO:      StartupLocality    : 0
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 1
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : 55 11 51 d8 8b 7f 41 d3 18 16 f2 e8 80 bf 80 fa
+    INFO:          : b4 03 6d 96 4c a0 0a 98 45 cf 25 2f 1e a9 09 3e
+    INFO:      EventSize          : 5
+    INFO:      Event              : BL_2
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 1
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : f3 00 5c ed a2 12 8b 76 b7 82 da c5 28 c3 02 52
+    INFO:          : 19 e4 3a 82 f2 3c ab 1e 0d 78 84 9c b5 fe e2 4f
+    INFO:      EventSize          : 14
+    INFO:      Event              : SECURE_RT_EL3
+    INFO:    PCR_Event2:
+    INFO:      PCRIndex           : 0
+    INFO:      EventType          : 1
+    INFO:      Digests Count      : 1
+    INFO:        #0 AlgorithmId   : SHA256
+    INFO:           Digest        : 90 28 81 42 12 b7 9b ca aa 0c 40 76 33 5a 69 71
+    INFO:          : b6 19 2b 90 f2 d2 69 b8 de 8e 6d 05 4d c2 73 f9
+    INFO:      EventSize          : 6
+    INFO:      Event              : BL_33
+    NOTICE:  BL1: Booting BL31
+    INFO:    Entry point address = 0x100e0000
+    INFO:    SPSR = 0x3cd
+    NOTICE:  BL31: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+    NOTICE:  BL31: Built : 10:56:58, Jul  9 2024
+    INFO:    rpi3: Checking DTB...
+    INFO:    rpi3: Reserved 0x10000000 - 0x10100000 in DTB
+    INFO:    BL31: Initializing runtime services
+    INFO:    BL31: Preparing for EL3 exit to normal world
+    INFO:    Entry point address = 0x11000000
+    INFO:    SPSR = 0x3c9
+
+
+    U-Boot 2024.04-g84314330-dirty (Apr 23 2024 - 15:41:54 -0500)
+
+    DRAM:  948 MiB
+    RPI 3 Model B (0xa02082)
+    Core:  68 devices, 14 uclasses, devicetree: embed
+    MMC:   mmc@7e202000: 0, mmc@7e300000: 1
+    Loading Environment from FAT... OK
+    In:    serial,usbkbd
+    Out:   serial,vidconsole
+    Err:   serial,vidconsole
+    Net:   No ethernet found.
+    starting USB...
+    Bus usb@7e980000: USB DWC2
+    scanning bus usb@7e980000 for devices...
+    Error: smsc95xx_eth No valid MAC address found.
+    2 USB Device(s) found
+          scanning usb for storage devices... 0 Storage Device(s) found
+    Hit any key to stop autoboot:  2  1  0
+    Card did not respond to voltage select! : -110
+    No EFI system partition
+    No EFI system partition
+    Failed to persist EFI variables
+    No EFI system partition
+    Failed to persist EFI variables
+    No EFI system partition
+    Failed to persist EFI variables
+    Missing TPMv2 device for EFI_TCG_PROTOCOL
+    ** Booting bootflow '<NULL>' with efi_mgr
+    Loading Boot0000 'mmc 0' failed
+    EFI boot manager: Cannot load any image
+    Boot failed (err=-14)
+    Card did not respond to voltage select! : -110
+    No ethernet found.
+    No ethernet found.
+    U-Boot>
+
+
+Next steps for Discrete TPM and Measured Boot development
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to automatically validate the workings of the Discrete TPM, the creation
+of test cases that compare the eventlog image hashes with what is stored in PCR0
+are a great way to test the core functionality of the Discrete TPM in Measured Boot.
+
+Development of Discrete TPM drivers such as a reference FIFO |I2C|, MMIO, and CRB
+drivers has not started, these drivers will allow a larger number of platform
+to use a Discrete TPM in TF-A.
+
+*Copyright (c) 2025, Arm Limited. All rights reserved.*
+
+.. _TCG event log: https://trustedcomputinggroup.org/resource/tcg-efi-platform-specification/
+.. _rpi3 pinout: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio
+.. _instructions: https://www.circuitbasics.com/use-putty-to-access-the-raspberry-pi-terminal-from-a-computer/
+.. _workaround:  https://github.com/mhomran/u-boot-rpi3-b-plus
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 740f3a6..b5814bb 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -784,6 +784,20 @@
 
    This option defaults to 0.
 
+-  ``DISCRETE_TPM``: Boolean flag to include support for a Discrete TPM.
+
+   This option defaults to 0.
+
+-  ``TPM_INTERFACE``: When ``DISCRETE_TPM=1``, this is a required flag to
+   select the TPM interface. Currently only one interface is supported:
+
+   ::
+
+      FIFO_SPI
+
+-  ``MBOOT_TPM_HASH_ALG``: Build flag to select the TPM hash algorithm used during
+   Measured Boot. Currently only accepts ``sha256`` as a valid algorithm.
+
 -  ``MARCH_DIRECTIVE``: used to pass a -march option from the platform build
    options to the compiler. An example usage:
 
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
index 23a91cd..ecf6d63 100644
--- a/docs/global_substitutions.txt
+++ b/docs/global_substitutions.txt
@@ -6,6 +6,7 @@
 .. |BTI| replace:: :term:`BTI`
 .. |CoT| replace:: :term:`CoT`
 .. |COT| replace:: :term:`COT`
+.. |CRB| replace:: :term:`CRB`
 .. |CSS| replace:: :term:`CSS`
 .. |CVE| replace:: :term:`CVE`
 .. |DICE| replace:: :term:`DICE`
@@ -19,11 +20,13 @@
 .. |FCONF| replace:: :term:`FCONF`
 .. |FDT| replace:: :term:`FDT`
 .. |FF-A| replace:: :term:`FF-A`
+.. |FIFO| replace:: :term:`FIFO`
 .. |FIP| replace:: :term:`FIP`
 .. |FVP| replace:: :term:`FVP`
 .. |FWU| replace:: :term:`FWU`
 .. |GIC| replace:: :term:`GIC`
 .. |HES| replace:: :term:`HES`
+.. |I2C| replace:: :term:`I2C`
 .. |ISA| replace:: :term:`ISA`
 .. |Linaro| replace:: :term:`Linaro`
 .. |MMU| replace:: :term:`MMU`
@@ -55,6 +58,7 @@
 .. |SP| replace:: :term:`SP`
 .. |SPD| replace:: :term:`SPD`
 .. |SPM| replace:: :term:`SPM`
+.. |SPI| replace:: :term:`SPI`
 .. |SRTM| replace:: :term:`SRTM`
 .. |SSBS| replace:: :term:`SSBS`
 .. |SVE| replace:: :term:`SVE`
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 20ad21c..8bb35bc 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -36,6 +36,9 @@
    CSS
       Compute Sub-System
 
+   CRB
+      Command Response Buffer
+
    CVE
       Common Vulnerabilities and Exposures. A CVE document is commonly used to
       describe a publicly-known security vulnerability.
@@ -88,6 +91,9 @@
    FF-A
       Firmware Framework for Arm A-profile
 
+   FIFO
+      First In, First Out
+
    FIP
       Firmware Image Package
 
@@ -103,6 +109,9 @@
    HES
       Arm CCA Hardware Enforced Security
 
+   I2C
+      Inter-Integrated Circuit Protocol
+
    ISA
       Instruction Set Architecture
 
@@ -211,6 +220,9 @@
    SPM
       Secure Partition Manager
 
+   SPI
+      Serial Peripheral Interface
+
    SRTM
       Static Root of Trust for Measurement
 
diff --git a/docs/resources/diagrams/rpi3_dtpm_driver.png b/docs/resources/diagrams/rpi3_dtpm_driver.png
new file mode 100644
index 0000000..36b1843
--- /dev/null
+++ b/docs/resources/diagrams/rpi3_dtpm_driver.png
Binary files differ
diff --git a/docs/threat_model/firmware_threat_model/threat_model.rst b/docs/threat_model/firmware_threat_model/threat_model.rst
index ae0219e..c0cc3be 100644
--- a/docs/threat_model/firmware_threat_model/threat_model.rst
+++ b/docs/threat_model/firmware_threat_model/threat_model.rst
@@ -928,6 +928,12 @@
      Measured Boot implementation in |TF-A| is that it does not extend the
      measurements into a |PCR| of a Discrete |TPM|, where measurements would
      be securely stored and protected against tampering.
+   - Discrete |TPM|: Implemented in |TF-A| as a proof of concept, the Discrete
+     |TPM| is used alongside the existing TCG-compliant Event Log. This
+     Measured Boot implementation extends measurement hashes to a |PCR| in the
+     |TPM|, which provides a hardware-backed root of trust. The measurements in
+     the Event Log can now be hashed and compared to the value of the |PCR| to
+     determine if tampering of the Event Log has taken place.
    - `CCA Measured Boot`_: Implemented by |TF-M|. Measurements are stored in
      |HES| secure on-chip memory. |HES| implements protection against tampering
      its on-chip memory. |HES| interface is available for BL1 and BL2.
@@ -942,6 +948,20 @@
  to protect or threats to defend against that could compromise |TF-A| execution
  environment's security.
 
+ When considering the implementation of Measured Boot using a TCG-compliant
+ Event Log backed by a discrete TPM, physical vulnerabilities come to mind.
+ Platforms have many different ways of integrating a discrete TPM, and these
+ implementations can be susceptible to man-in-the-middle attacks, where the
+ attacker intercepts the bus traffic between the discrete TPM and the host
+ machine. This can lead to PCR extend operations being modified, compromising
+ Measured Boot. This vulnerability requires physical access to the host machine.
+
+ TF-A does not provide any mitigations against these physical vulnerabilities,
+ it is the responsibility of the platform owners to address this based on their
+ specific threat model. Mitigation of this can be achieved through dedicated
+ hardware solutions, such as an encrypted AP/dTPM bus, or software-based
+ approaches designed to protect sensitive data such as parameter encryption.
+
  There are general security assets and threats associated with remote/delegated
  attestation. However, these are outside the |TF-A| security boundary and
  should be dealt with by the appropriate agent in the platform/system.
@@ -1192,7 +1212,7 @@
 
 --------------
 
-*Copyright (c) 2021-2024, Arm Limited. All rights reserved.*
+*Copyright (c) 2021-2025, Arm Limited. All rights reserved.*
 
 
 .. _STRIDE threat analysis technique: https://docs.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats#stride-model
diff --git a/drivers/gpio/gpio_spi.c b/drivers/gpio/gpio_spi.c
new file mode 100644
index 0000000..2913b41
--- /dev/null
+++ b/drivers/gpio/gpio_spi.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <drivers/gpio_spi.h>
+#include <platform_def.h>
+
+static struct spi_plat gpio_spidev;
+
+static void gpio_spi_delay_us(void)
+{
+	udelay(gpio_spidev.gpio_data.spi_delay_us);
+}
+
+static int gpio_spi_miso(void)
+{
+	return gpio_get_value(gpio_spidev.gpio_data.miso_gpio);
+}
+
+static void gpio_spi_sclk(int bit)
+{
+	gpio_set_value(gpio_spidev.gpio_data.sclk_gpio, bit);
+}
+
+static void gpio_spi_mosi(int bit)
+{
+	gpio_set_value(gpio_spidev.gpio_data.mosi_gpio, bit);
+}
+
+static void gpio_spi_cs(int bit)
+{
+	gpio_set_value(gpio_spidev.gpio_data.cs_gpio, bit);
+}
+
+static void gpio_spi_start(void)
+{
+	gpio_spi_cs(1);
+	gpio_spi_sclk(0);
+	gpio_spi_cs(0);
+}
+
+static void gpio_spi_stop(void)
+{
+	gpio_spi_cs(1);
+}
+
+/* set sclk to a known state (0) before performing any further action */
+static void gpio_spi_get_access(void)
+{
+	gpio_spi_sclk(0);
+}
+
+static void xfer(unsigned int bytes, const void *out, void *in, int cpol, int cpha)
+{
+	for (unsigned int j = 0U; j < bytes; j++) {
+		unsigned char in_byte  = 0U;
+		unsigned char out_byte = (out != NULL) ? *(const uint8_t *)out++ : 0xFF;
+
+		for (int i = 7; i >= 0; i--) {
+			if (cpha) {
+				gpio_spi_sclk(!cpol);
+			}
+
+			gpio_spi_mosi(!!(out_byte & (1 << i)));
+
+			gpio_spi_delay_us();
+			gpio_spi_sclk(cpha ? cpol : !cpol);
+			gpio_spi_delay_us();
+
+			in_byte |= gpio_spi_miso() << i;
+
+			if (!cpha) {
+				gpio_spi_sclk(cpol);
+			}
+		}
+
+		if (in != NULL) {
+			*(uint8_t *)in++ = in_byte;
+		}
+	}
+}
+
+static int gpio_spi_xfer(unsigned int bytes, const void *out, void *in)
+{
+	if ((out == NULL) && (in == NULL)) {
+		return -1;
+	}
+
+	switch (gpio_spidev.gpio_data.spi_mode) {
+	case 0:
+		xfer(bytes, out, in, 0, 0);
+		break;
+	case 1:
+		xfer(bytes, out, in, 0, 1);
+		break;
+	case 2:
+		xfer(bytes, out, in, 1, 0);
+		break;
+	case 3:
+		xfer(bytes, out, in, 1, 1);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+struct spi_ops gpio_spidev_ops = {
+	.get_access	= gpio_spi_get_access,
+	.start		= gpio_spi_start,
+	.stop		= gpio_spi_stop,
+	.xfer		= gpio_spi_xfer,
+};
+
+struct spi_plat *gpio_spi_init(struct gpio_spi_data *gpio_spi_data)
+{
+	gpio_spidev.gpio_data = *gpio_spi_data;
+	gpio_spidev.ops = &gpio_spidev_ops;
+
+	return &gpio_spidev;
+}
diff --git a/drivers/measured_boot/event_log/event_log.mk b/drivers/measured_boot/event_log/event_log.mk
index 5ea4c55..9e0d6c4 100644
--- a/drivers/measured_boot/event_log/event_log.mk
+++ b/drivers/measured_boot/event_log/event_log.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -7,15 +7,20 @@
 # Default log level to dump the event log (LOG_LEVEL_INFO)
 EVENT_LOG_LEVEL         ?= 40
 
-# Measured Boot hash algorithm.
-# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
-ifdef TPM_HASH_ALG
-    $(warning "TPM_HASH_ALG is deprecated. Please use MBOOT_EL_HASH_ALG instead.")
-    MBOOT_EL_HASH_ALG		:=	${TPM_HASH_ALG}
+# When using a TPM, adopt the TPM's hash algorithm for
+# measurements through the Event Log mechanism, ensuring
+# the TPM uses the same algorithm for measurements and
+# extends the PCR accordingly, allowing for comparison
+# between PCR value and Event Log measurements required
+# for attestation.
+ifdef MBOOT_TPM_HASH_ALG
+    MBOOT_EL_HASH_ALG		:=	${MBOOT_TPM_HASH_ALG}
 else
     MBOOT_EL_HASH_ALG		:=	sha256
 endif
 
+# Measured Boot hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
 ifeq (${MBOOT_EL_HASH_ALG}, sha512)
     TPM_ALG_ID			:=	TPM_ALG_SHA512
     TCG_DIGEST_SIZE		:=	64U
diff --git a/drivers/tpm/tpm2.mk b/drivers/tpm/tpm2.mk
new file mode 100644
index 0000000..4418b97
--- /dev/null
+++ b/drivers/tpm/tpm2.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TPM2_SRC_DIR	:= drivers/tpm/
+
+TPM2_SOURCES	:= ${TPM2_SRC_DIR}tpm2_cmds.c \
+                   ${TPM2_SRC_DIR}tpm2_chip.c
+
+# TPM Hash algorithm, used during Measured Boot
+# currently only accepts SHA-256
+ifeq (${MBOOT_TPM_HASH_ALG}, sha256)
+    TPM_ALG_ID			:=	TPM_ALG_SHA256
+    TCG_DIGEST_SIZE		:=	32U
+else
+    $(error "The selected MBOOT_TPM_HASH_ALG is invalid.")
+endif #MBOOT_TPM_HASH_ALG
+
+ifeq (${TPM_INTERFACE}, FIFO_SPI)
+    TPM2_SOURCES += ${TPM2_SRC_DIR}tpm2_fifo.c \
+                    ${TPM2_SRC_DIR}tpm2_fifo_spi.c
+else
+    $(error "The selected TPM_INTERFACE is invalid.")
+endif #TPM_INTERFACE
diff --git a/drivers/tpm/tpm2_chip.c b/drivers/tpm/tpm2_chip.c
new file mode 100644
index 0000000..537ce92
--- /dev/null
+++ b/drivers/tpm/tpm2_chip.c
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/tpm/tpm2_chip.h>
+
+/*
+ * TPM timeout values
+ * Reference: TCG PC Client Platform TPM Profile (PTP) Specification v1.05
+ */
+struct tpm_chip_data tpm_chip_data = {
+	.locality = -1,
+	.timeout_msec_a = 750,
+	.timeout_msec_b = 2000,
+	.timeout_msec_c = 200,
+	.timeout_msec_d = 30,
+	.address = 0,
+};
diff --git a/drivers/tpm/tpm2_cmds.c b/drivers/tpm/tpm2_cmds.c
new file mode 100644
index 0000000..b6422a8
--- /dev/null
+++ b/drivers/tpm/tpm2_cmds.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/libc/endian.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define CMD_SIZE_OFFSET	6
+
+#define SINGLE_BYTE	1
+#define TWO_BYTES	2
+#define FOUR_BYTES	4
+
+static struct interface_ops *interface;
+
+static int tpm_xfer(struct tpm_chip_data *chip_data, const tpm_cmd *send, tpm_cmd *receive)
+{
+	int ret;
+
+	ret = interface->send(chip_data, send);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = interface->receive(chip_data, receive);
+	if (ret < 0) {
+		return ret;
+	}
+
+	return TPM_SUCCESS;
+}
+
+int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+	int err;
+
+	interface = tpm_interface_getops(chip_data, locality);
+
+	err = interface->request_access(chip_data, locality);
+	if (err != 0) {
+		return err;
+	}
+
+	return interface->get_info(chip_data, locality);
+}
+
+int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+	return interface->release_locality(chip_data, locality);
+}
+
+static int tpm_update_buffer(tpm_cmd *buf, uint32_t new_data, size_t new_len)
+{
+	int i, j, start;
+	uint32_t command_size;
+
+	union {
+		uint8_t var8;
+		uint16_t var16;
+		uint32_t var32;
+		uint8_t array[4];
+	} tpm_new_data;
+
+	command_size = be32toh(buf->header.cmd_size);
+
+	if (command_size + new_len > MAX_SIZE_CMDBUF) {
+		ERROR("%s: buf size exceeded, increase MAX_SIZE_CMDBUF\n",
+			__func__);
+		return TPM_INVALID_PARAM;
+	}
+	/*
+	 * Subtract the cmd header size from the current command size
+	 * so the data buffer is written to starting at index 0.
+	 */
+	start = command_size - TPM_HEADER_SIZE;
+
+	/*
+	 * The TPM, according to the TCG spec, processes data in BE byte order,
+	 * in the case where the Host is LE, htobe correctly handles the byte order.
+	 * When updating the buffer, keep in mind to only pass sizeof(new_data) or
+	 * the variable type size for the new_len function parameter. This ensures
+	 * there is only the possiblility of writing 1, 2, or 4 bytes to the buffer,
+	 * and that the correct number of bytes are written to data[i].
+	 */
+	if (new_len == SINGLE_BYTE) {
+		tpm_new_data.var8 = new_data & 0xFF;
+	} else if (new_len == TWO_BYTES) {
+		tpm_new_data.var16 = htobe16(new_data & 0xFFFF);
+	} else if (new_len == FOUR_BYTES) {
+		tpm_new_data.var32 = htobe32(new_data);
+	} else {
+		ERROR("%s: Invalid data length\n", __func__);
+		return TPM_INVALID_PARAM;
+	}
+
+	for (i = start, j = 0; i < start + new_len; i++, j++) {
+		buf->data[i] = tpm_new_data.array[j];
+	}
+	buf->header.cmd_size = htobe32(command_size + new_len);
+
+	return TPM_SUCCESS;
+}
+
+
+int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode)
+{
+	tpm_cmd startup_cmd, startup_response;
+	uint32_t tpm_rc;
+	int ret;
+
+	memset(&startup_cmd, 0, sizeof(startup_cmd));
+	memset(&startup_response, 0, sizeof(startup_response));
+
+	startup_cmd.header.tag = htobe16(TPM_ST_NO_SESSIONS);
+	startup_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
+	startup_cmd.header.cmd_code = htobe32(TPM_CMD_STARTUP);
+
+	ret = tpm_update_buffer(&startup_cmd, mode, sizeof(mode));
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = tpm_xfer(chip_data, &startup_cmd, &startup_response);
+	if (ret < 0) {
+		return ret;
+	}
+
+	tpm_rc = be32toh(startup_response.header.cmd_code);
+	if (tpm_rc != TPM_RESPONSE_SUCCESS) {
+		ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
+		return TPM_ERR_RESPONSE;
+	}
+
+	return TPM_SUCCESS;
+}
+
+int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
+		uint16_t algorithm, const uint8_t *digest,
+		uint32_t digest_len)
+{
+	tpm_cmd pcr_extend_cmd, pcr_extend_response;
+	uint32_t tpm_rc;
+	int ret;
+
+	memset(&pcr_extend_cmd, 0, sizeof(pcr_extend_cmd));
+	memset(&pcr_extend_response, 0, sizeof(pcr_extend_response));
+
+	if (digest == NULL) {
+		return TPM_INVALID_PARAM;
+	}
+	pcr_extend_cmd.header.tag = htobe16(TPM_ST_SESSIONS);
+	pcr_extend_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
+	pcr_extend_cmd.header.cmd_code = htobe32(TPM_CMD_PCR_EXTEND);
+
+	/* handle (PCR Index)*/
+	ret = tpm_update_buffer(&pcr_extend_cmd, index, sizeof(index));
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* authorization size , session handle, nonce size, attributes*/
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_MIN_AUTH_SIZE, sizeof(uint32_t));
+	if (ret < 0) {
+		return ret;
+	}
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_RS_PW, sizeof(uint32_t));
+	if (ret < 0) {
+		return ret;
+	}
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_NONCE_SIZE, sizeof(uint16_t));
+	if (ret < 0) {
+		return ret;
+	}
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ATTRIBUTES_DISABLE, sizeof(uint8_t));
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* hmac/password size */
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_HMAC_SIZE, sizeof(uint16_t));
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* hashes count */
+	ret = tpm_update_buffer(&pcr_extend_cmd, TPM_SINGLE_HASH_COUNT, sizeof(uint32_t));
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* hash algorithm */
+	ret = tpm_update_buffer(&pcr_extend_cmd, algorithm, sizeof(algorithm));
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* digest */
+	for (int i = 0; i < digest_len; i++) {
+		ret = tpm_update_buffer(&pcr_extend_cmd, digest[i], sizeof(uint8_t));
+		if (ret < 0) {
+			return ret;
+		}
+	}
+
+	ret = tpm_xfer(chip_data, &pcr_extend_cmd, &pcr_extend_response);
+	if (ret < 0) {
+		return ret;
+	}
+
+	tpm_rc = be32toh(pcr_extend_response.header.cmd_code);
+	if (tpm_rc != TPM_RESPONSE_SUCCESS) {
+		ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
+		return TPM_ERR_RESPONSE;
+	}
+
+	return TPM_SUCCESS;
+}
diff --git a/drivers/tpm/tpm2_fifo.c b/drivers/tpm/tpm2_fifo.c
new file mode 100644
index 0000000..7c4b9d8
--- /dev/null
+++ b/drivers/tpm/tpm2_fifo.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/libc/endian.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define LOCALITY_START_ADDRESS(x, y) \
+	((uint16_t)(x->address + (0x1000 * y)))
+
+static int tpm2_get_info(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+	uint32_t vid_did;
+	uint8_t revision;
+	int err;
+
+	err = tpm2_fifo_read_chunk(tpm_base_addr + TPM_FIFO_REG_VENDID, DWORD, &vid_did);
+	if (err < 0) {
+		return err;
+	}
+
+	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_REVID, &revision);
+	if (err < 0) {
+		return err;
+	}
+
+	INFO("TPM Chip: vendor-id 0x%x, device-id 0x%x, revision-id: 0x%x\n",
+		0xFFFF & vid_did, vid_did >> 16, revision);
+
+	return TPM_SUCCESS;
+}
+
+static int tpm2_wait_reg_bits(uint16_t reg, uint8_t set, unsigned long timeout, uint8_t *status)
+{
+	int err;
+	uint64_t timeout_delay = timeout_init_us(timeout * 1000);
+
+	do {
+		err = tpm2_fifo_read_byte(reg, status);
+		if (err < 0) {
+			return err;
+		}
+		if ((*status & set) == set) {
+			return TPM_SUCCESS;
+		}
+	} while (!timeout_elapsed(timeout_delay));
+
+	return TPM_ERR_TIMEOUT;
+}
+
+static int tpm2_fifo_request_access(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+	uint8_t status;
+	int err;
+
+	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, TPM_ACCESS_REQUEST_USE);
+	if (err < 0) {
+		return err;
+	}
+
+	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_ACCESS,
+				TPM_ACCESS_ACTIVE_LOCALITY,
+				chip_data->timeout_msec_a, &status);
+	if (err == 0) {
+		chip_data->locality = locality;
+		return TPM_SUCCESS;
+	}
+
+	return err;
+}
+
+static int tpm2_fifo_release_locality(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+	uint8_t buf;
+	int err;
+
+	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, &buf);
+	if (err < 0) {
+		return err;
+	}
+
+	if (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
+		return tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS,
+				TPM_ACCESS_RELINQUISH_LOCALITY);
+	}
+
+	ERROR("%s: Unable to release locality\n", __func__);
+	return TPM_ERR_RESPONSE;
+}
+
+static int tpm2_fifo_prepare(struct tpm_chip_data *chip_data)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+	uint8_t status;
+	int err;
+
+	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_COMMAND_READY);
+	if (err < 0) {
+		return err;
+	}
+
+	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+				TPM_STAT_COMMAND_READY,
+				chip_data->timeout_msec_b, &status);
+	if (err < 0) {
+		ERROR("%s: TPM Status Busy\n", __func__);
+		return err;
+	}
+
+	return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_get_burstcount(struct tpm_chip_data *chip_data, uint16_t *burstcount)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+	uint64_t timeout_delay = timeout_init_us(chip_data->timeout_msec_a * 1000);
+	int err;
+
+	if (burstcount == NULL) {
+		return TPM_INVALID_PARAM;
+	}
+
+	do {
+		uint8_t byte0, byte1;
+
+		err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_LO, &byte0);
+		if (err < 0) {
+			return err;
+		}
+
+		err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_HI, &byte1);
+		if (err < 0) {
+			return err;
+		}
+
+		*burstcount = (uint16_t)((byte1 << 8) + byte0);
+		if (*burstcount != 0U) {
+			return TPM_SUCCESS;
+		}
+	} while (!timeout_elapsed(timeout_delay));
+
+	return TPM_ERR_TIMEOUT;
+}
+
+static int tpm2_fifo_send(struct tpm_chip_data *chip_data, const tpm_cmd *buf)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+	uint8_t status;
+	uint16_t burstcnt;
+	int err;
+	uint32_t len, index;
+
+	if (sizeof(buf->header) != TPM_HEADER_SIZE) {
+		ERROR("%s: invalid command header size.\n", __func__);
+		return TPM_INVALID_PARAM;
+	}
+
+	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, &status);
+	if (err < 0) {
+		return err;
+	}
+
+	if (!(status & TPM_STAT_COMMAND_READY)) {
+		err = tpm2_fifo_prepare(chip_data);
+		if (err < 0) {
+			return err;
+		}
+	}
+
+	/* write the command header to the TPM first */
+	const uint8_t *header_data = (const uint8_t *)&buf->header;
+
+	for (index = 0; index < TPM_HEADER_SIZE; index++) {
+		err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+				header_data[index]);
+		if (err < 0) {
+			return err;
+		}
+	}
+
+	len =  be32toh(buf->header.cmd_size);
+
+	while (index < len) {
+		err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
+		if (err < 0) {
+			return err;
+		}
+
+		for (; burstcnt > 0U && index < len; burstcnt--) {
+			err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+					buf->data[index - TPM_HEADER_SIZE]);
+			if (err < 0) {
+				return err;
+			}
+			index++;
+		}
+	}
+
+	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+				TPM_STAT_VALID,
+				chip_data->timeout_msec_c,
+				&status);
+	if (err < 0) {
+		return err;
+	}
+
+	if (status & TPM_STAT_EXPECT) {
+		ERROR("%s: TPM is still expecting data after command buffer is sent\n", __func__);
+		return TPM_ERR_TRANSFER;
+	}
+
+	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_GO);
+	if (err < 0) {
+		return err;
+	}
+
+	return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_read_data(struct tpm_chip_data *chip_data, tpm_cmd *buf,
+			uint16_t tpm_base_addr, uint8_t *status, int *size, int bytes_expected)
+{
+	int err, read_size, loop_index;
+	uint16_t burstcnt;
+	uint8_t *read_data;
+
+	if (bytes_expected == TPM_READ_HEADER) {
+		/* read the response header from the TPM first */
+		read_data = (uint8_t *)&buf->header;
+		read_size = TPM_HEADER_SIZE;
+		loop_index = *size;
+	} else {
+		/* process the rest of the mssg with bytes_expected */
+		read_data = buf->data;
+		read_size = bytes_expected;
+		loop_index = *size - TPM_HEADER_SIZE;
+	}
+
+	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+				TPM_STAT_AVAIL,
+				chip_data->timeout_msec_c,
+				status);
+	if (err < 0) {
+		return err;
+	}
+
+	while (*size < read_size) {
+		err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
+		if (err < 0) {
+			ERROR("%s: TPM burst count error\n", __func__);
+			return err;
+		}
+
+		for (; burstcnt > 0U && loop_index < read_size;
+		    burstcnt--, loop_index++, (*size)++) {
+			err = tpm2_fifo_read_byte(
+				tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+				(void *)&read_data[loop_index]);
+			if (err < 0) {
+				return err;
+			}
+		}
+	}
+
+	return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_receive(struct tpm_chip_data *chip_data, tpm_cmd *buf)
+{
+	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+	int size = 0, bytes_expected, err;
+	uint8_t status;
+
+	err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, TPM_READ_HEADER);
+	if (err < 0) {
+		return err;
+	}
+
+	bytes_expected = be32toh(buf->header.cmd_size);
+	if (bytes_expected > sizeof(*buf)) {
+		ERROR("%s: tpm response buffer cannot store expected response\n", __func__);
+		return TPM_INVALID_PARAM;
+	}
+
+	if (size == bytes_expected) {
+		return size;
+	}
+
+	err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, bytes_expected);
+	if (err < 0) {
+		return err;
+	}
+
+	if (size < bytes_expected) {
+		ERROR("%s: response buffer size is less than expected\n", __func__);
+		return TPM_ERR_RESPONSE;
+	}
+
+	return TPM_SUCCESS;
+}
+
+static interface_ops_t fifo_ops = {
+	.get_info = tpm2_get_info,
+	.send = tpm2_fifo_send,
+	.receive = tpm2_fifo_receive,
+	.request_access = tpm2_fifo_request_access,
+	.release_locality = tpm2_fifo_release_locality,
+};
+
+struct interface_ops *
+tpm_interface_getops(struct tpm_chip_data *chip_data,  uint8_t locality)
+{
+	return &fifo_ops;
+}
diff --git a/drivers/tpm/tpm2_fifo_spi.c b/drivers/tpm/tpm2_fifo_spi.c
new file mode 100644
index 0000000..16d87d9
--- /dev/null
+++ b/drivers/tpm/tpm2_fifo_spi.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <drivers/gpio_spi.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define ENCODE_LIMIT		128
+#define CS_ASSERT_OFFSET	0xD4
+#define RETRY_COUNT		50
+
+#define TPM_READ	false
+#define TPM_WRITE	true
+
+extern struct spi_plat *spidev;
+
+static int tpm2_spi_transfer(const void *data_out, void *data_in, uint8_t len)
+{
+	return spidev->ops->xfer(len, data_out, data_in);
+}
+
+/*
+ * Reference: TCG PC Client Platform TPM Profile (PTP) Specification v1.05
+ */
+static int tpm2_spi_start_transaction(uint16_t tpm_reg, bool write, uint8_t len)
+{
+	int rc;
+	uint8_t header[4];
+	uint8_t header_response[4];
+	uint8_t zero = 0, byte;
+	int retries;
+
+	/* check to make sure len does not exceed the encoding limit */
+	if (len > ENCODE_LIMIT) {
+		return TPM_INVALID_PARAM;
+	}
+
+	/*
+	 * 7.4.6 TPM SPI Bit protocol calls for the following header
+	 * to be sent to the TPM at the start of every attempted read/write.
+	 */
+
+	/* header[0] contains the r/w and the xfer size, if the msb is not
+	 * set, the operation is write, if it is set then it is read.
+	 * The size of the transfer is encoded, and must not overwrite
+	 * the msb, therefore an ENCODE LIMIT of 128 is present.
+	 */
+	header[0] = ((write) ? 0x00 : 0x80) | (len - 1);
+
+	/*
+	 * header[1] contains the address offset 0xD4_xxxx as defined
+	 * in the TPM spec, since the CS# is asserted.
+	 */
+	header[1] = CS_ASSERT_OFFSET;
+
+	/*
+	 * header[2] and header[3] contain the address of the register
+	 * to be read/written.
+	 */
+	header[2] = tpm_reg >> 8;
+	header[3] = tpm_reg;
+
+	rc = tpm2_spi_transfer(header, header_response, 4);
+	if (rc != 0) {
+		return TPM_ERR_TRANSFER;
+	}
+
+	/*
+	 * 7.4.5 Flow Control defines a wait state in order to accommodate
+	 * the TPM in case it needs to free its buffer.
+	 */
+	if ((header_response[3] & 0x01) != 0U) {
+		return TPM_SUCCESS;
+	}
+
+	/*
+	 * if the wait state over bit is not set in the initial header_response,
+	 * poll for the wait state over by sending a zeroed byte, if the
+	 * RETRY_COUNT is exceeded the transfer fails.
+	 */
+	for (retries = RETRY_COUNT; retries > 0; retries--) {
+		rc = tpm2_spi_transfer(&zero, &byte, 1);
+		if (rc != 0) {
+			return TPM_ERR_TRANSFER;
+		}
+		if ((byte & 0x01) != 0U) {
+			return TPM_SUCCESS;
+		}
+	}
+
+	if (retries == 0) {
+		ERROR("%s: TPM Timeout\n", __func__);
+		return TPM_ERR_TIMEOUT;
+	}
+
+	return TPM_SUCCESS;
+}
+
+static void tpm2_spi_end_transaction(void)
+{
+	spidev->ops->stop();
+}
+
+static void tpm2_spi_init(void)
+{
+	spidev->ops->get_access();
+	spidev->ops->start();
+}
+
+static int tpm2_fifo_io(uint16_t tpm_reg, bool is_write, uint8_t len, void *val)
+{
+	int rc;
+
+	tpm2_spi_init();
+	rc = tpm2_spi_start_transaction(tpm_reg, is_write, len);
+	if (rc != 0) {
+		tpm2_spi_end_transaction();
+		return rc;
+	}
+
+	rc = tpm2_spi_transfer(
+		is_write ? val : NULL,
+		is_write ? NULL : val,
+		len);
+	if (rc != 0) {
+		tpm2_spi_end_transaction();
+		return rc;
+	}
+
+	tpm2_spi_end_transaction();
+
+	return TPM_SUCCESS;
+}
+
+int tpm2_fifo_write_byte(uint16_t tpm_reg, uint8_t val)
+{
+	return tpm2_fifo_io(tpm_reg, TPM_WRITE, BYTE, &val);
+}
+
+int tpm2_fifo_read_byte(uint16_t tpm_reg, uint8_t *val)
+{
+	return tpm2_fifo_io(tpm_reg, TPM_READ, BYTE, val);
+}
+
+int tpm2_fifo_read_chunk(uint16_t tpm_reg, uint8_t len, void *val)
+{
+	if ((len != BYTE) && (len != WORD) && (len != DWORD)) {
+		return TPM_INVALID_PARAM;
+	}
+
+	return tpm2_fifo_io(tpm_reg, TPM_READ, len, val);
+}
diff --git a/drivers/tpm/tpm2_slb9670/slb9670_gpio.c b/drivers/tpm/tpm2_slb9670/slb9670_gpio.c
new file mode 100644
index 0000000..993387d
--- /dev/null
+++ b/drivers/tpm/tpm2_slb9670/slb9670_gpio.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+
+/*
+ * Infineon SLB9670 Chip Reset Parameters
+ */
+#define t_WRST	2 /* Warm Reset Time (us) */
+#define t_RSTIN	60 /* Reset Inactive Time (ms) */
+
+/*
+ * RPi3 GPIO pin configuration for TPM via bit-bang SPI
+ * References: https://pinout.xyz/pinout/spi
+ * - docs/design_documents/measured_boot_dtpm_poc.rst
+ */
+const struct gpio_spi_data tpm_rpi3_gpio_data = {
+	.cs_gpio = 7,
+	.sclk_gpio = 11,
+	.mosi_gpio = 10,
+	.miso_gpio = 9,
+	.reset_gpio = 24,
+	.spi_delay_us = 0,
+	.spi_mode = 0
+};
+
+/*
+ * When RST is asserted at certain points in time, then this
+ * triggers the TPM's security functions, in the case where
+ * multiple resets need to be asserted, there must be a wait
+ * of at least t_RSTIN between the resets
+ *
+ * In most cases this is not needed since RST is only being asserted
+ * once, ie for TPM initialization at the beginning of TFA.
+ */
+void tpm2_slb9670_reset_chip(struct gpio_spi_data *tpm_gpio_data)
+{
+	/*
+	 * since we don't know the value of the pin before it was init to 1
+	 * it is best to assume the state was 0, and account for that by
+	 * adding an initial RST inactive delay
+	 */
+	mdelay(t_RSTIN);
+	/* pull #RST pin to active low for 2us */
+	gpio_set_value(tpm_gpio_data->reset_gpio, 0);
+	udelay(t_WRST);
+	/* wait 60ms after warm reset before sending TPM commands */
+	gpio_set_value(tpm_gpio_data->reset_gpio, 1);
+	mdelay(t_RSTIN);
+}
+
+/*
+ * init GPIO pins for the Infineon slb9670 TPM
+ */
+void tpm2_slb9670_gpio_init(struct gpio_spi_data *tpm_gpio_data)
+{
+	gpio_set_value(tpm_gpio_data->cs_gpio, 1);
+	gpio_set_direction(tpm_gpio_data->cs_gpio, GPIO_DIR_OUT);
+
+	gpio_set_value(tpm_gpio_data->sclk_gpio, 0);
+	gpio_set_direction(tpm_gpio_data->sclk_gpio, GPIO_DIR_OUT);
+
+	gpio_set_value(tpm_gpio_data->mosi_gpio, 1);
+	gpio_set_direction(tpm_gpio_data->mosi_gpio, GPIO_DIR_OUT);
+
+	gpio_set_direction(tpm_gpio_data->miso_gpio, GPIO_DIR_IN);
+
+	gpio_set_value(tpm_gpio_data->reset_gpio, 1);
+	gpio_set_direction(tpm_gpio_data->reset_gpio, GPIO_DIR_OUT);
+}
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 67fdead..3707520 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -697,6 +697,7 @@
 #define MDCR_TDOSA_BIT		(ULL(1) << 10)
 #define MDCR_TDA_BIT		(ULL(1) << 9)
 #define MDCR_TPM_BIT		(ULL(1) << 6)
+#define MDCR_RLTE_BIT		(ULL(1) << 0)
 #define MDCR_EL3_RESET_VAL	MDCR_MTPME_BIT
 
 /* MDCR_EL2 definitions */
diff --git a/include/drivers/arm/smmu_v3.h b/include/drivers/arm/smmu_v3.h
index 37da56f..5a36e26 100644
--- a/include/drivers/arm/smmu_v3.h
+++ b/include/drivers/arm/smmu_v3.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -58,6 +58,8 @@
 
 /* SMMU_ROOT_IDR0 register fields */
 #define SMMU_ROOT_IDR0_ROOT_IMPL	(1UL << 0)
+#define SMMU_ROOT_IDR0_BA_REALM_SHIFT	22U
+#define SMMU_ROOT_IDR0_BA_REALM_MASK	GENMASK_32(31U, SMMU_ROOT_IDR0_BA_REALM_SHIFT)
 
 /* SMMU_ROOT_CR0 register fields */
 #define SMMU_ROOT_CR0_GPCEN		(1UL << 1)
diff --git a/include/drivers/gpio_spi.h b/include/drivers/gpio_spi.h
new file mode 100644
index 0000000..a926553
--- /dev/null
+++ b/include/drivers/gpio_spi.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPIO_SPI_H
+#define GPIO_SPI_H
+
+#include <stdint.h>
+
+struct gpio_spi_data {
+	uint8_t cs_gpio, sclk_gpio, mosi_gpio, miso_gpio, reset_gpio;
+	uint32_t spi_delay_us;
+	unsigned int spi_mode;
+};
+
+struct spi_ops {
+	void (*get_access)(void);
+	void (*start)(void);
+	void (*stop)(void);
+	int (*xfer)(unsigned int bitlen, const void *dout, void *din);
+};
+
+struct spi_plat {
+	struct gpio_spi_data gpio_data;
+	const struct spi_ops *ops;
+};
+
+struct spi_plat *gpio_spi_init(struct gpio_spi_data *gpio_spi_data);
+
+#endif /* GPIO_SPI_H */
diff --git a/include/drivers/tpm/tpm2.h b/include/drivers/tpm/tpm2.h
new file mode 100644
index 0000000..c91acf8
--- /dev/null
+++ b/include/drivers/tpm/tpm2.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TPM2_H
+#define TPM2_H
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/tpm/tpm2_chip.h>
+
+/* Return values */
+enum tpm_ret_value {
+	TPM_SUCCESS = 0,
+	TPM_ERR_RESPONSE = -1,
+	TPM_INVALID_PARAM = -2,
+	TPM_ERR_TIMEOUT = -3,
+	TPM_ERR_TRANSFER = -4,
+};
+
+/*
+ * TPM FIFO register space address offsets
+ */
+#define TPM_FIFO_REG_ACCESS		0x00
+#define TPM_FIFO_REG_INTR_ENABLE	0x08
+#define TPM_FIFO_REG_INTR_VECTOR	0x0C
+#define TPM_FIFO_REG_INTR_STS		0x10
+#define TPM_FIFO_REG_INTF_CAPS		0x14
+#define TPM_FIFO_REG_STATUS		0x18
+#define TPM_FIFO_REG_BURST_COUNT_LO	0x19
+#define TPM_FIFO_REG_BURST_COUNT_HI	0x20
+#define TPM_FIFO_REG_DATA_FIFO		0x24
+#define TPM_FIFO_REG_VENDID		0xF00
+#define TPM_FIFO_REG_DEVID		0xF02
+#define TPM_FIFO_REG_REVID		0xF04
+
+#define TPM_ST_NO_SESSIONS		U(0x8001)
+#define TPM_ST_SESSIONS			U(0x8002)
+
+#define TPM_SU_CLEAR			U(0x0000)
+#define TPM_SU_STATE			U(0x0001)
+
+#define TPM_MIN_AUTH_SIZE		9
+#define TPM_RS_PW			0x40000009
+#define TPM_ZERO_NONCE_SIZE		0
+#define TPM_ATTRIBUTES_DISABLE		0
+#define TPM_ZERO_HMAC_SIZE		0
+#define TPM_SINGLE_HASH_COUNT		1
+
+
+#define TPM_CMD_STARTUP			U(0x0144)
+#define TPM_CMD_PCR_READ		U(0x017E)
+#define TPM_CMD_PCR_EXTEND		U(0x0182)
+
+#define TPM_RESPONSE_SUCCESS		U(0x0000)
+
+#define TPM_ACCESS_ACTIVE_LOCALITY	U(1 << 5)
+#define TPM_ACCESS_VALID		U(1 << 7)
+#define TPM_ACCESS_RELINQUISH_LOCALITY	U(1 << 5)
+#define TPM_ACCESS_REQUEST_USE		U(1 << 1)
+#define TPM_ACCESS_REQUEST_PENDING	U(1 << 2)
+
+#define TPM_STAT_VALID			U(1 << 7)
+#define TPM_STAT_COMMAND_READY		U(1 << 6)
+#define TPM_STAT_GO			U(1 << 5)
+#define TPM_STAT_AVAIL			U(1 << 4)
+#define TPM_STAT_EXPECT			U(1 << 3)
+
+#define TPM_READ_HEADER -1
+
+#define TPM_HEADER_SIZE			10
+#define MAX_SIZE_CMDBUF			256
+#define MAX_CMD_DATA			(MAX_SIZE_CMDBUF - TPM_HEADER_SIZE)
+
+#pragma pack(1)
+typedef struct tpm_cmd_hdr {
+	uint16_t tag;
+	uint32_t cmd_size;
+	uint32_t cmd_code;
+} tpm_cmd_hdr;
+
+typedef struct tpm_cmd {
+	tpm_cmd_hdr header;
+	uint8_t data[MAX_CMD_DATA];
+} tpm_cmd;
+#pragma pack()
+
+int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode);
+
+int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
+		   uint16_t algorithm, const uint8_t *digest,
+		   uint32_t digest_len);
+
+#endif /* TPM2_H */
diff --git a/include/drivers/tpm/tpm2_chip.h b/include/drivers/tpm/tpm2_chip.h
new file mode 100644
index 0000000..ce052ad
--- /dev/null
+++ b/include/drivers/tpm/tpm2_chip.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifndef TPM2_CHIP_H
+#define TPM2_CHIP_H
+
+#define BYTE		U(0x1)
+#define WORD		U(0x2)
+#define DWORD		U(0x4)
+
+struct tpm_chip_data {
+	uint8_t locality;
+	unsigned long timeout_msec_a, timeout_msec_b;
+	unsigned long timeout_msec_c, timeout_msec_d;
+	uint16_t address;
+};
+
+#endif /* TPM2_CHIP_H */
diff --git a/include/drivers/tpm/tpm2_interface.h b/include/drivers/tpm/tpm2_interface.h
new file mode 100644
index 0000000..6bfbf6c
--- /dev/null
+++ b/include/drivers/tpm/tpm2_interface.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TPM2_INTERFACE_H
+#define TPM2_INTERFACE_H
+
+#include "tpm2_chip.h"
+
+typedef struct interface_ops {
+	int (*get_info)(struct tpm_chip_data *chip_data, uint8_t locality);
+	int (*send)(struct tpm_chip_data *chip_data, const tpm_cmd *buf);
+	int (*receive)(struct tpm_chip_data *chip_data, tpm_cmd *buf);
+	int (*request_access)(struct tpm_chip_data *chip_data, uint8_t locality);
+	int (*release_locality)(struct tpm_chip_data *chip_data, uint8_t locality);
+} interface_ops_t;
+
+struct interface_ops *tpm_interface_getops(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm2_fifo_write_byte(uint16_t tpm_reg, uint8_t val);
+
+int tpm2_fifo_read_byte(uint16_t tpm_reg, uint8_t *val);
+
+int tpm2_fifo_read_chunk(uint16_t tpm_reg, uint8_t len, void *val);
+
+#endif /* TPM2_INTERFACE_H */
diff --git a/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h b/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
new file mode 100644
index 0000000..59ae125
--- /dev/null
+++ b/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "drivers/gpio_spi.h"
+
+#ifndef SLB9670_GPIO_H
+#define SLB9670_GPIO_H
+
+void tpm2_slb9670_reset_chip(struct gpio_spi_data *tpm_gpio_data);
+
+void tpm2_slb9670_gpio_init(struct gpio_spi_data *tpm_gpio_data);
+
+#endif /* SLB9670_GPIO_H */
diff --git a/include/lib/libc/string.h b/include/lib/libc/string.h
index 8129404..bba9816 100644
--- a/include/lib/libc/string.h
+++ b/include/lib/libc/string.h
@@ -30,5 +30,7 @@
 size_t strlcpy(char * dst, const char * src, size_t dsize);
 size_t strlcat(char * dst, const char * src, size_t dsize);
 char *strtok_r(char *s, const char *delim, char **last);
+size_t strnlen_secure(const char *str, size_t maxlen);
+int strcpy_secure(char *restrict dest, size_t dest_size, const char *restrict src);
 
 #endif /* STRING_H */
diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
index c403031..bdc6349 100644
--- a/include/lib/transfer_list.h
+++ b/include/lib/transfer_list.h
@@ -62,6 +62,8 @@
 	TL_TAG_EXEC_EP_INFO64 = 0x102,
 	TL_TAG_SRAM_LAYOUT64 = 0x104,
 	TL_TAG_MBEDTLS_HEAP_INFO = 0x105,
+	TL_TAG_EXEC_EP_INFO32 = 0x106,
+	TL_TAG_SRAM_LAYOUT32 = 0x107,
 };
 
 enum transfer_list_ops {
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 1d7a59d..2e72de2 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -298,8 +298,8 @@
 void arm_tsp_early_platform_setup(void);
 
 /* SP_MIN utility functions */
-void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config,
-				uintptr_t hw_config, void *plat_params_from_bl2);
+void arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3);
 void arm_sp_min_plat_runtime_setup(void);
 void arm_sp_min_plat_arch_setup(void);
 
diff --git a/include/services/rmm_core_manifest.h b/include/services/rmm_core_manifest.h
index 2d6e71f..c094f6a 100644
--- a/include/services/rmm_core_manifest.h
+++ b/include/services/rmm_core_manifest.h
@@ -14,20 +14,21 @@
 #include <lib/cassert.h>
 
 #define RMMD_MANIFEST_VERSION_MAJOR		U(0)
-#define RMMD_MANIFEST_VERSION_MINOR		U(4)
+#define RMMD_MANIFEST_VERSION_MINOR		U(5)
 
 #define RMM_CONSOLE_MAX_NAME_LEN		U(8)
 
 /*
- * Manifest version encoding:
+ * Version encoding:
  *	- Bit[31] RES0
  *	- Bits [30:16] Major version
  *	- Bits [15:0] Minor version
  */
-#define SET_RMMD_MANIFEST_VERSION(_major, _minor)		\
+#define SET_VERSION(_major, _minor)				\
 	((((_major) & 0x7FFF) << 16) | ((_minor) & 0xFFFF))
 
-#define RMMD_MANIFEST_VERSION	SET_RMMD_MANIFEST_VERSION(	\
+/* Boot Manifest version */
+#define RMMD_MANIFEST_VERSION	SET_VERSION(			\
 				RMMD_MANIFEST_VERSION_MAJOR,	\
 				RMMD_MANIFEST_VERSION_MINOR)
 
@@ -37,9 +38,17 @@
 #define RMMD_GET_MANIFEST_VERSION_MINOR(_version)		\
 	(_version & 0xFFFF)
 
+#define PCIE_RC_INFO_VERSION_MAJOR		U(0)
+#define PCIE_RC_INFO_VERSION_MINOR		U(1)
+
+/* PCIe Root Complex info structure version */
+#define PCIE_RC_INFO_VERSION	SET_VERSION(			\
+				PCIE_RC_INFO_VERSION_MAJOR,	\
+				PCIE_RC_INFO_VERSION_MINOR)
+
 /* Memory bank/device region structure */
 struct memory_bank {
-	uintptr_t base;			/* Base address */
+	uint64_t base;			/* Base address */
 	uint64_t size;			/* Size of memory bank/device region */
 };
 
@@ -64,7 +73,7 @@
 
 /* Console info structure */
 struct console_info {
-	uintptr_t base;			/* Console base address */
+	uint64_t base;			/* Console base address */
 	uint64_t map_pages;		/* Num of pages to be mapped in RMM for the console MMIO */
 	char name[RMM_CONSOLE_MAX_NAME_LEN];	/* Name of console */
 	uint64_t clk_in_hz;		/* UART clock (in Hz) for the console */
@@ -98,11 +107,105 @@
 CASSERT(offsetof(struct console_list, checksum) == 16UL,
 			rmm_manifest_console_list_checksum);
 
-/* Boot manifest core structure as per v0.4 */
+/* SMMUv3 Info structure */
+struct smmu_info {
+	uint64_t smmu_base;		/* SMMUv3 base address */
+	uint64_t smmu_r_base;		/* SMMUv3 Realm Pages base address */
+};
+
+CASSERT(offsetof(struct smmu_info, smmu_base) == 0UL,
+			rmm_manifest_smmu_base);
+CASSERT(offsetof(struct smmu_info, smmu_r_base) == 8UL,
+			rmm_manifest_smmu_r_base);
+
+/* SMMUv3 Info List structure */
+struct smmu_list {
+	uint64_t num_smmus;		/* Number of smmu_info entries */
+	struct smmu_info *smmus;	/* Pointer to smmu_info[] array */
+	uint64_t checksum;		/* Checksum of smmu_list data */
+};
+
+CASSERT(offsetof(struct smmu_list, num_smmus) == 0UL,
+			rmm_manifest_num_smmus);
+CASSERT(offsetof(struct smmu_list, smmus) == 8UL,
+			rmm_manifest_smmus);
+CASSERT(offsetof(struct smmu_list, checksum) == 16UL,
+			rmm_manifest_smmu_list_checksum);
+
+/* PCIe BDF Mapping Info structure */
+struct bdf_mapping_info {
+	uint16_t mapping_base;	/* Base of BDF mapping (inclusive) */
+	uint16_t mapping_top;	/* Top of BDF mapping (exclusive) */
+	uint16_t mapping_off;	/* Mapping offset, as per Arm Base System Architecture: */
+				/* StreamID = zero_extend(RequesterID[N-1:0]) + (1<<N)*Constant_B */
+	uint16_t smmu_idx;	/* SMMU index in smmu_info[] array */
+};
+
+CASSERT(offsetof(struct bdf_mapping_info, mapping_base) == 0UL,
+			rmm_manifest_mapping_base);
+CASSERT(offsetof(struct bdf_mapping_info, mapping_top) == 2UL,
+			rmm_manifest_mapping_top);
+CASSERT(offsetof(struct bdf_mapping_info, mapping_off) == 4UL,
+			rmm_manifest_mapping_off);
+CASSERT(offsetof(struct bdf_mapping_info, smmu_idx) == 6UL,
+			rmm_manifest_smmu_ptr);
+
+/* PCIe Root Port Info structure */
+struct root_port_info {
+	uint16_t root_port_id;			/* Root Port identifier */
+	uint16_t padding;			/* RES0 */
+	uint32_t num_bdf_mappings;		/* Number of BDF mappings */
+	struct bdf_mapping_info *bdf_mappings;	/* Pointer to bdf_mapping_info[] array */
+};
+
+CASSERT(offsetof(struct root_port_info, root_port_id) == 0UL,
+			rmm_manifest_root_port_id);
+CASSERT(offsetof(struct root_port_info, num_bdf_mappings) == 4UL,
+			rmm_manifest_num_bdf_mappingss);
+CASSERT(offsetof(struct root_port_info, bdf_mappings) == 8UL,
+			rmm_manifest_bdf_mappings);
+
+/* PCIe Root Complex info structure v0.1 */
+struct root_complex_info {
+	uint64_t ecam_base;			/* ECAM base address. Size is implicitly 256MB */
+	uint8_t segment;			/* PCIe segment identifier */
+	uint8_t padding[3];			/* RES0 */
+	uint32_t num_root_ports;		/* Number of root ports */
+	struct root_port_info *root_ports;	/* Pointer to root_port_info[] array */
+};
+
+CASSERT(offsetof(struct root_complex_info, ecam_base) == 0UL,
+			rmm_manifest_ecam_base);
+CASSERT(offsetof(struct root_complex_info, segment) == 8UL,
+			rmm_manifest_segment);
+CASSERT(offsetof(struct root_complex_info, num_root_ports) == 12UL,
+			rmm_manifest_num_root_ports);
+CASSERT(offsetof(struct root_complex_info, root_ports) == 16UL,
+			rmm_manifest_root_ports);
+
+/* PCIe Root Complex List structure */
+struct root_complex_list {
+	uint64_t num_root_complex;		/* Number of pci_rc_info entries */
+	uint32_t rc_info_version;		/* PCIe Root Complex info structure version */
+	uint32_t padding;			/* RES0 */
+	struct root_complex_info *root_complex;	/* Pointer to pci_rc_info[] array */
+	uint64_t checksum;			/* Checksum of pci_rc_list data */
+};
+
+CASSERT(offsetof(struct root_complex_list, num_root_complex) == 0UL,
+			rmm_manifest_num_root_complex);
+CASSERT(offsetof(struct root_complex_list, rc_info_version) == 8UL,
+			rmm_manifest_rc_info_version);
+CASSERT(offsetof(struct root_complex_list, root_complex) == 16UL,
+			rmm_manifest_root_complex);
+CASSERT(offsetof(struct root_complex_list, checksum) == 24UL,
+			rmm_manifest_root_complex_list_checksum);
+
+/* Boot manifest core structure as per v0.5 */
 struct rmm_manifest {
 	uint32_t version;			/* Manifest version */
 	uint32_t padding;			/* RES0 */
-	uintptr_t plat_data;			/* Manifest platform data */
+	uint64_t plat_data;			/* Manifest platform data */
 	/* Platform NS DRAM data (v0.2) */
 	struct memory_info plat_dram;
 	/* Platform console list (v0.3) */
@@ -110,6 +213,10 @@
 	/* Platform device address ranges (v0.4) */
 	struct memory_info plat_ncoh_region;
 	struct memory_info plat_coh_region;
+	/* Platform SMMUv3 list (v0.5) */
+	struct smmu_list plat_smmu;
+	/* Platform PCIe Root Complex list (v0.5) */
+	struct root_complex_list plat_root_complex;
 };
 
 CASSERT(offsetof(struct rmm_manifest, version) == 0UL,
@@ -124,5 +231,9 @@
 			rmm_manifest_plat_ncoh_region_unaligned);
 CASSERT(offsetof(struct rmm_manifest, plat_coh_region) == 88UL,
 			rmm_manifest_plat_coh_region_unaligned);
+CASSERT(offsetof(struct rmm_manifest, plat_smmu) == 112UL,
+			rmm_manifest_plat_smmu_unaligned);
+CASSERT(offsetof(struct rmm_manifest, plat_root_complex) == 136UL,
+			rmm_manifest_plat_root_complex);
 
 #endif /* RMM_CORE_MANIFEST_H */
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 93771df..f95fb6e 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -21,10 +21,6 @@
 	.globl	disable_mmu_icache_el1
 	.globl	disable_mmu_icache_el3
 	.globl	fixup_gdt_reloc
-#if SUPPORT_VFP
-	.globl	enable_vfp
-#endif
-
 func smc
 	smc	#0
 endfunc smc
@@ -456,24 +452,6 @@
 endfunc disable_mmu_icache_el1
 
 /* ---------------------------------------------------------------------------
- * Enable the use of VFP at EL3
- * ---------------------------------------------------------------------------
- */
-#if SUPPORT_VFP
-func enable_vfp
-	mrs	x0, cpacr_el1
-	orr	x0, x0, #CPACR_VFP_BITS
-	msr	cpacr_el1, x0
-	mrs	x0, cptr_el3
-	mov	x1, #AARCH64_CPTR_TFP
-	bic	x0, x0, x1
-	msr	cptr_el3, x0
-	isb
-	ret
-endfunc enable_vfp
-#endif
-
-/* ---------------------------------------------------------------------------
  * Helper to fixup Global Descriptor table (GDT) and dynamic relocations
  * (.rela.dyn) at runtime.
  *
diff --git a/lib/cpus/aarch64/cortex_a710.S b/lib/cpus/aarch64/cortex_a710.S
index e8f5a80..23f7850 100644
--- a/lib/cpus/aarch64/cortex_a710.S
+++ b/lib/cpus/aarch64/cortex_a710.S
@@ -31,13 +31,6 @@
 
 cpu_reset_prologue cortex_a710
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_a710, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_A710_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_a710,  CVE(2024, 5660)
-
-check_erratum_ls cortex_a710, CVE(2024, 5660), CPU_REV(2, 1)
-
 workaround_reset_start cortex_a710, ERRATUM(1987031), ERRATA_A710_1987031
 	ldr x0,=0x6
 	msr S3_6_c15_c8_0,x0
@@ -213,6 +206,10 @@
 
 check_erratum_ls cortex_a710, ERRATUM(2778471), CPU_REV(2, 1)
 
+add_erratum_entry cortex_a710, ERRATUM(3701772), ERRATA_A710_3701772
+
+check_erratum_ls cortex_a710, ERRATUM(3701772), CPU_REV(2, 1)
+
 workaround_reset_start cortex_a710, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
@@ -225,9 +222,12 @@
 
 check_erratum_chosen cortex_a710, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-add_erratum_entry cortex_a710, ERRATUM(3701772), ERRATA_A710_3701772
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_a710, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_A710_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_a710,  CVE(2024, 5660)
 
-check_erratum_ls cortex_a710, ERRATUM(3701772), CPU_REV(2, 1)
+check_erratum_ls cortex_a710, CVE(2024, 5660), CPU_REV(2, 1)
 
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
diff --git a/lib/cpus/aarch64/cortex_a77.S b/lib/cpus/aarch64/cortex_a77.S
index 7fb964d..82a20ec 100644
--- a/lib/cpus/aarch64/cortex_a77.S
+++ b/lib/cpus/aarch64/cortex_a77.S
@@ -28,13 +28,6 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A77_BHB_LOOP_COUNT, cortex_a77
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_a77, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_A77_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_a77, CVE(2024, 5660)
-
-check_erratum_ls cortex_a77, CVE(2024, 5660), CPU_REV(1, 1)
-
 workaround_reset_start cortex_a77, ERRATUM(1508412), ERRATA_A77_1508412
 	/* move cpu revision in again and compare against r0p0 */
 	mov	x0, x7
@@ -150,6 +143,13 @@
 
 check_erratum_chosen cortex_a77, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_a77, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_A77_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_a77, CVE(2024, 5660)
+
+check_erratum_ls cortex_a77, CVE(2024, 5660), CPU_REV(1, 1)
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A77. Must follow AAPCS.
 	 * -------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a78.S b/lib/cpus/aarch64/cortex_a78.S
index a66214b..36b0a04 100644
--- a/lib/cpus/aarch64/cortex_a78.S
+++ b/lib/cpus/aarch64/cortex_a78.S
@@ -26,13 +26,6 @@
 
 cpu_reset_prologue cortex_a78
 
-/* Disable hardware page aggregation.Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_a78, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_A78_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_a78, CVE(2024, 5660)
-
-check_erratum_ls cortex_a78, CVE(2024, 5660), CPU_REV(1, 2)
-
 workaround_reset_start cortex_a78, ERRATUM(1688305), ERRATA_A78_1688305
 	sysreg_bit_set CORTEX_A78_ACTLR2_EL1, CORTEX_A78_ACTLR2_EL1_BIT_1
 workaround_reset_end cortex_a78, ERRATUM(1688305)
@@ -176,6 +169,13 @@
 
 check_erratum_chosen cortex_a78, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation.Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_a78, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_A78_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_a78, CVE(2024, 5660)
+
+check_erratum_ls cortex_a78, CVE(2024, 5660), CPU_REV(1, 2)
+
 cpu_reset_func_start cortex_a78
 #if ENABLE_FEAT_AMU
 	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
diff --git a/lib/cpus/aarch64/cortex_a78_ae.S b/lib/cpus/aarch64/cortex_a78_ae.S
index c537967..63bc936 100644
--- a/lib/cpus/aarch64/cortex_a78_ae.S
+++ b/lib/cpus/aarch64/cortex_a78_ae.S
@@ -24,13 +24,6 @@
 
 cpu_reset_prologue cortex_a78_ae
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_a78_ae, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_A78_AE_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_a78_ae, CVE(2024, 5660)
-
-check_erratum_ls cortex_a78_ae, CVE(2024, 5660), CPU_REV(0, 3)
-
 workaround_reset_start cortex_a78_ae, ERRATUM(1941500), ERRATA_A78_AE_1941500
 	sysreg_bit_set CORTEX_A78_AE_CPUECTLR_EL1, CORTEX_A78_AE_CPUECTLR_EL1_BIT_8
 workaround_reset_end cortex_a78_ae, ERRATUM(1941500)
@@ -105,6 +98,13 @@
 
 check_erratum_chosen cortex_a78_ae, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_a78_ae, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_A78_AE_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_a78_ae, CVE(2024, 5660)
+
+check_erratum_ls cortex_a78_ae, CVE(2024, 5660), CPU_REV(0, 3)
+
 cpu_reset_func_start cortex_a78_ae
 #if ENABLE_FEAT_AMU
 	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
diff --git a/lib/cpus/aarch64/cortex_a78c.S b/lib/cpus/aarch64/cortex_a78c.S
index aba7d25..8f2dea8 100644
--- a/lib/cpus/aarch64/cortex_a78c.S
+++ b/lib/cpus/aarch64/cortex_a78c.S
@@ -23,13 +23,6 @@
 
 cpu_reset_prologue cortex_a78c
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_a78c, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_A78C_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_a78c, CVE(2024, 5660)
-
-check_erratum_ls cortex_a78c, CVE(2024, 5660), CPU_REV(0, 2)
-
 workaround_reset_start cortex_a78c, ERRATUM(1827430), ERRATA_A78C_1827430
 	/* Disable allocation of splintered pages in the L2 TLB */
 	sysreg_bit_set CORTEX_A78C_CPUECTLR_EL1, CORTEX_A78C_CPUECTLR_EL1_MM_ASP_EN
@@ -127,6 +120,13 @@
 #endif /* IMAGE_BL31 */
 workaround_reset_end cortex_a78c, CVE(2022, 23960)
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_a78c, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_A78C_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_a78c, CVE(2024, 5660)
+
+check_erratum_ls cortex_a78c, CVE(2024, 5660), CPU_REV(0, 2)
+
 cpu_reset_func_start cortex_a78c
 cpu_reset_func_end cortex_a78c
 
diff --git a/lib/cpus/aarch64/cortex_x1.S b/lib/cpus/aarch64/cortex_x1.S
index 27d181a..cb759cc 100644
--- a/lib/cpus/aarch64/cortex_x1.S
+++ b/lib/cpus/aarch64/cortex_x1.S
@@ -25,13 +25,6 @@
 
 cpu_reset_prologue cortex_x1
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_x1, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_X1_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_x1, CVE(2024, 5660)
-
-check_erratum_ls cortex_x1, CVE(2024, 5660), CPU_REV(1, 2)
-
 workaround_reset_start cortex_x1, ERRATUM(1688305), ERRATA_X1_1688305
 	sysreg_bit_set CORTEX_X1_ACTLR2_EL1, BIT(1)
 workaround_reset_end cortex_x1, ERRATUM(1688305)
@@ -62,6 +55,13 @@
 #endif /* IMAGE_BL31 */
 workaround_reset_end cortex_x1, CVE(2022, 23960)
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_x1, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_X1_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_x1, CVE(2024, 5660)
+
+check_erratum_ls cortex_x1, CVE(2024, 5660), CPU_REV(1, 2)
+
 cpu_reset_func_start cortex_x1
 cpu_reset_func_end cortex_x1
 
diff --git a/lib/cpus/aarch64/cortex_x2.S b/lib/cpus/aarch64/cortex_x2.S
index b11c37d..ccdd3b8 100644
--- a/lib/cpus/aarch64/cortex_x2.S
+++ b/lib/cpus/aarch64/cortex_x2.S
@@ -25,23 +25,12 @@
 
 .global check_erratum_cortex_x2_3701772
 
-add_erratum_entry cortex_x2, ERRATUM(3701772), ERRATA_X2_3701772
-
-check_erratum_ls cortex_x2, ERRATUM(3701772), CPU_REV(2, 1)
-
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table CORTEX_X2_BHB_LOOP_COUNT, cortex_x2
 #endif /* WORKAROUND_CVE_2022_23960 */
 
 cpu_reset_prologue cortex_x2
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_x2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_X2_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_x2, CVE(2024, 5660)
-
-check_erratum_ls cortex_x2, CVE(2024, 5660), CPU_REV(2, 1)
-
 workaround_reset_start cortex_x2, ERRATUM(2002765), ERRATA_X2_2002765
 	ldr	x0, =0x6
 	msr	S3_6_C15_C8_0, x0 /* CPUPSELR_EL3 */
@@ -127,6 +116,15 @@
 
 check_erratum_ls cortex_x2, ERRATUM(2282622), CPU_REV(2, 1)
 
+workaround_reset_start cortex_x2, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end cortex_x2, ERRATUM(2313941)
+
+check_erratum_custom_start cortex_x2, ERRATUM(2313941)
+	check_errata_dsu_2313941_impl
+	ret
+check_erratum_custom_end cortex_x2, ERRATUM(2313941)
+
 workaround_reset_start cortex_x2, ERRATUM(2371105), ERRATA_X2_2371105
 	/* Set bit 40 in CPUACTLR2_EL1 */
 	sysreg_bit_set CORTEX_X2_CPUACTLR2_EL1, CORTEX_X2_CPUACTLR2_EL1_BIT_40
@@ -155,6 +153,10 @@
 
 check_erratum_ls cortex_x2, ERRATUM(2778471), CPU_REV(2, 1)
 
+add_erratum_entry cortex_x2, ERRATUM(3701772), ERRATA_X2_3701772
+
+check_erratum_ls cortex_x2, ERRATUM(3701772), CPU_REV(2, 1)
+
 workaround_reset_start cortex_x2, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
@@ -167,14 +169,12 @@
 
 check_erratum_chosen cortex_x2, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-workaround_reset_start cortex_x2, ERRATUM(2313941), ERRATA_DSU_2313941
-	errata_dsu_2313941_wa_impl
-workaround_reset_end cortex_x2, ERRATUM(2313941)
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_x2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_X2_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_x2, CVE(2024, 5660)
 
-check_erratum_custom_start cortex_x2, ERRATUM(2313941)
-	check_errata_dsu_2313941_impl
-	ret
-check_erratum_custom_end cortex_x2, ERRATUM(2313941)
+check_erratum_ls cortex_x2, CVE(2024, 5660), CPU_REV(2, 1)
 
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
diff --git a/lib/cpus/aarch64/cortex_x3.S b/lib/cpus/aarch64/cortex_x3.S
index 3d52dae..628642b 100644
--- a/lib/cpus/aarch64/cortex_x3.S
+++ b/lib/cpus/aarch64/cortex_x3.S
@@ -24,23 +24,12 @@
 
 .global check_erratum_cortex_x3_3701769
 
-add_erratum_entry cortex_x3, ERRATUM(3701769), ERRATA_X3_3701769
-
-check_erratum_ls cortex_x3, ERRATUM(3701769), CPU_REV(1, 2)
-
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table CORTEX_X3_BHB_LOOP_COUNT, cortex_x3
 #endif /* WORKAROUND_CVE_2022_23960 */
 
 cpu_reset_prologue cortex_x3
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_x3, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_X3_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_x3, CVE(2024, 5660)
-
-check_erratum_ls cortex_x3, CVE(2024, 5660), CPU_REV(1, 2)
-
 workaround_reset_start cortex_x3, ERRATUM(2070301), ERRATA_X3_2070301
 	sysreg_bitfield_insert CORTEX_X3_CPUECTLR2_EL1, CORTEX_X3_CPUECTLR2_EL1_PF_MODE_CNSRV, \
 	CORTEX_X3_CPUECTLR2_EL1_PF_MODE_LSB, CORTEX_X3_CPUECTLR2_EL1_PF_MODE_WIDTH
@@ -114,6 +103,10 @@
 
 check_erratum_ls cortex_x3, ERRATUM(2779509), CPU_REV(1, 1)
 
+add_erratum_entry cortex_x3, ERRATUM(3701769), ERRATA_X3_3701769
+
+check_erratum_ls cortex_x3, ERRATUM(3701769), CPU_REV(1, 2)
+
 workaround_reset_start cortex_x3, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	override_vector_table wa_cve_vbar_cortex_x3
@@ -122,6 +115,13 @@
 
 check_erratum_chosen cortex_x3, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_x3, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_X3_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_x3, CVE(2024, 5660)
+
+check_erratum_ls cortex_x3, CVE(2024, 5660), CPU_REV(1, 2)
+
 workaround_reset_start cortex_x3, CVE(2024, 7881), WORKAROUND_CVE_2024_7881
 	/* ---------------------------------
 	 * Sets BIT41 of CPUACTLR6_EL1 which
diff --git a/lib/cpus/aarch64/cortex_x4.S b/lib/cpus/aarch64/cortex_x4.S
index c067981..fbbe925 100644
--- a/lib/cpus/aarch64/cortex_x4.S
+++ b/lib/cpus/aarch64/cortex_x4.S
@@ -35,13 +35,6 @@
 
 check_erratum_ls cortex_x4, ERRATUM(2726228), CPU_REV(0, 1)
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start cortex_x4, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set CORTEX_X4_CPUECTLR_EL1, BIT(46)
-workaround_reset_end cortex_x4, CVE(2024, 5660)
-
-check_erratum_ls cortex_x4, CVE(2024, 5660), CPU_REV(0, 2)
-
 workaround_runtime_start cortex_x4, ERRATUM(2740089), ERRATA_X4_2740089
 	/* dsb before isb of power down sequence */
 	dsb	sy
@@ -100,6 +93,10 @@
 
 check_erratum_ls cortex_x4, ERRATUM(3076789), CPU_REV(0, 1)
 
+add_erratum_entry cortex_x4, ERRATUM(3701758), ERRATA_X4_3701758
+
+check_erratum_ls cortex_x4, ERRATUM(3701758), CPU_REV(0, 3)
+
 workaround_reset_start cortex_x4, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
@@ -112,6 +109,13 @@
 
 check_erratum_chosen cortex_x4, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start cortex_x4, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set CORTEX_X4_CPUECTLR_EL1, BIT(46)
+workaround_reset_end cortex_x4, CVE(2024, 5660)
+
+check_erratum_ls cortex_x4, CVE(2024, 5660), CPU_REV(0, 2)
+
 workaround_reset_start cortex_x4, CVE(2024, 7881), WORKAROUND_CVE_2024_7881
 	/* ---------------------------------
 	 * Sets BIT41 of CPUACTLR6_EL1 which
@@ -123,10 +127,6 @@
 
 check_erratum_chosen cortex_x4, CVE(2024, 7881), WORKAROUND_CVE_2024_7881
 
-add_erratum_entry cortex_x4, ERRATUM(3701758), ERRATA_X4_3701758
-
-check_erratum_ls cortex_x4, ERRATUM(3701758), CPU_REV(0, 3)
-
 cpu_reset_func_start cortex_x4
 	/* Disable speculative loads */
 	msr	SSBS, xzr
diff --git a/lib/cpus/aarch64/neoverse_n2.S b/lib/cpus/aarch64/neoverse_n2.S
index 9c6f01a..4f1d53d 100644
--- a/lib/cpus/aarch64/neoverse_n2.S
+++ b/lib/cpus/aarch64/neoverse_n2.S
@@ -23,34 +23,12 @@
 
 .global check_erratum_neoverse_n2_3701773
 
-add_erratum_entry neoverse_n2, ERRATUM(3701773), ERRATA_N2_3701773
-
-check_erratum_ls neoverse_n2, ERRATUM(3701773), CPU_REV(0, 3)
-
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_N2_BHB_LOOP_COUNT, neoverse_n2
 #endif /* WORKAROUND_CVE_2022_23960 */
 
 cpu_reset_prologue neoverse_n2
 
-workaround_reset_start neoverse_n2, ERRATUM(2313941), ERRATA_DSU_2313941
-	errata_dsu_2313941_wa_impl
-workaround_reset_end neoverse_n2, ERRATUM(2313941)
-
-check_erratum_custom_start neoverse_n2, ERRATUM(2313941)
-	branch_if_scu_not_present 2f /* label 1 is used in the macro */
-	check_errata_dsu_2313941_impl
-	2:
-	ret
-check_erratum_custom_end neoverse_n2, ERRATUM(2313941)
-
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start neoverse_n2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set NEOVERSE_N2_CPUECTLR_EL1, BIT(46)
-workaround_reset_end neoverse_n2, CVE(2024, 5660)
-
-check_erratum_ls neoverse_n2, CVE(2024, 5660), CPU_REV(0, 3)
-
 workaround_reset_start neoverse_n2, ERRATUM(2002655), ERRATA_N2_2002655
 	/* Apply instruction patching sequence */
 	ldr x0,=0x6
@@ -73,18 +51,6 @@
 
 check_erratum_ls neoverse_n2, ERRATUM(2002655), CPU_REV(0, 0)
 
-workaround_reset_start neoverse_n2, ERRATUM(2025414), ERRATA_N2_2025414
-	sysreg_bit_set NEOVERSE_N2_CPUECTLR_EL1, NEOVERSE_N2_CPUECTLR_EL1_PFSTIDIS_BIT
-workaround_reset_end neoverse_n2, ERRATUM(2025414)
-
-check_erratum_ls neoverse_n2, ERRATUM(2025414), CPU_REV(0, 0)
-
-workaround_reset_start neoverse_n2, ERRATUM(2067956), ERRATA_N2_2067956
-	sysreg_bit_set NEOVERSE_N2_CPUACTLR_EL1, NEOVERSE_N2_CPUACTLR_EL1_BIT_46
-workaround_reset_end neoverse_n2, ERRATUM(2067956)
-
-check_erratum_ls neoverse_n2, ERRATUM(2067956), CPU_REV(0, 0)
-
 workaround_runtime_start neoverse_n2, ERRATUM(2009478), ERRATA_N2_2009478
 	/* Stash ERRSELR_EL1 in x2 */
 	mrs     x2, ERRSELR_EL1
@@ -101,6 +67,18 @@
 
 check_erratum_ls neoverse_n2, ERRATUM(2009478), CPU_REV(0, 0)
 
+workaround_reset_start neoverse_n2, ERRATUM(2025414), ERRATA_N2_2025414
+	sysreg_bit_set NEOVERSE_N2_CPUECTLR_EL1, NEOVERSE_N2_CPUECTLR_EL1_PFSTIDIS_BIT
+workaround_reset_end neoverse_n2, ERRATUM(2025414)
+
+check_erratum_ls neoverse_n2, ERRATUM(2025414), CPU_REV(0, 0)
+
+workaround_reset_start neoverse_n2, ERRATUM(2067956), ERRATA_N2_2067956
+	sysreg_bit_set NEOVERSE_N2_CPUACTLR_EL1, NEOVERSE_N2_CPUACTLR_EL1_BIT_46
+workaround_reset_end neoverse_n2, ERRATUM(2067956)
+
+check_erratum_ls neoverse_n2, ERRATUM(2067956), CPU_REV(0, 0)
+
 workaround_reset_start neoverse_n2, ERRATUM(2138953), ERRATA_N2_2138953
 	/* Apply instruction patching sequence */
 	mrs	x1, NEOVERSE_N2_CPUECTLR2_EL1
@@ -175,6 +153,17 @@
 
 check_erratum_ls neoverse_n2, ERRATUM(2280757), CPU_REV(0, 0)
 
+workaround_reset_start neoverse_n2, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end neoverse_n2, ERRATUM(2313941)
+
+check_erratum_custom_start neoverse_n2, ERRATUM(2313941)
+	branch_if_scu_not_present 2f /* label 1 is used in the macro */
+	check_errata_dsu_2313941_impl
+	2:
+	ret
+check_erratum_custom_end neoverse_n2, ERRATUM(2313941)
+
 .global erratum_neoverse_n2_2326639_wa
 workaround_runtime_start neoverse_n2, ERRATUM(2326639), ERRATA_N2_2326639
 	/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
@@ -240,6 +229,10 @@
 
 check_erratum_ls neoverse_n2, ERRATUM(2779511), CPU_REV(0, 2)
 
+add_erratum_entry neoverse_n2, ERRATUM(3701773), ERRATA_N2_3701773
+
+check_erratum_ls neoverse_n2, ERRATUM(3701773), CPU_REV(0, 3)
+
 workaround_reset_start neoverse_n2, CVE(2022,23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
@@ -252,6 +245,13 @@
 
 check_erratum_chosen neoverse_n2, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start neoverse_n2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set NEOVERSE_N2_CPUECTLR_EL1, BIT(46)
+workaround_reset_end neoverse_n2, CVE(2024, 5660)
+
+check_erratum_ls neoverse_n2, CVE(2024, 5660), CPU_REV(0, 3)
+
 	/* -------------------------------------------
 	 * The CPU Ops reset function for Neoverse N2.
 	 * -------------------------------------------
diff --git a/lib/cpus/aarch64/neoverse_v1.S b/lib/cpus/aarch64/neoverse_v1.S
index e1e8214..a3b05e1 100644
--- a/lib/cpus/aarch64/neoverse_v1.S
+++ b/lib/cpus/aarch64/neoverse_v1.S
@@ -28,13 +28,6 @@
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V1_BHB_LOOP_COUNT, neoverse_v1
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start neoverse_v1, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set NEOVERSE_V1_CPUECTLR_EL1, BIT(46)
-workaround_reset_end neoverse_v1, CVE(2024, 5660)
-
-check_erratum_ls neoverse_v1, CVE(2024, 5660), CPU_REV(1, 2)
-
 workaround_reset_start neoverse_v1, ERRATUM(1618635), ERRATA_V1_1618635
 	/* Inserts a DMB SY before and after MRS PAR_EL1 */
 	ldr	x0, =0x0
@@ -252,6 +245,13 @@
 
 check_erratum_chosen neoverse_v1, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start neoverse_v1, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set NEOVERSE_V1_CPUECTLR_EL1, BIT(46)
+workaround_reset_end neoverse_v1, CVE(2024, 5660)
+
+check_erratum_ls neoverse_v1, CVE(2024, 5660), CPU_REV(1, 2)
+
 	/* ---------------------------------------------
 	 * HW will do the cache maintenance while powering down
 	 * ---------------------------------------------
diff --git a/lib/cpus/aarch64/neoverse_v2.S b/lib/cpus/aarch64/neoverse_v2.S
index 06521ec..a320d44 100644
--- a/lib/cpus/aarch64/neoverse_v2.S
+++ b/lib/cpus/aarch64/neoverse_v2.S
@@ -24,13 +24,6 @@
 
 cpu_reset_prologue neoverse_v2
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start neoverse_v2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set NEOVERSE_V2_CPUECTLR_EL1, BIT(46)
-workaround_reset_end neoverse_v2, CVE(2024, 5660)
-
-check_erratum_ls neoverse_v2, CVE(2024, 5660), CPU_REV(0, 2)
-
 workaround_reset_start neoverse_v2, ERRATUM(2331132), ERRATA_V2_2331132
 	sysreg_bitfield_insert NEOVERSE_V2_CPUECTLR2_EL1, NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_CNSRV, \
 		NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_LSB, NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_WIDTH
@@ -95,6 +88,13 @@
 
 check_erratum_chosen neoverse_v2, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start neoverse_v2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set NEOVERSE_V2_CPUECTLR_EL1, BIT(46)
+workaround_reset_end neoverse_v2, CVE(2024, 5660)
+
+check_erratum_ls neoverse_v2, CVE(2024, 5660), CPU_REV(0, 2)
+
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V2_BHB_LOOP_COUNT, neoverse_v2
 #endif /* WORKAROUND_CVE_2022_23960 */
diff --git a/lib/cpus/aarch64/neoverse_v3.S b/lib/cpus/aarch64/neoverse_v3.S
index 29bfd0e..2ead062 100644
--- a/lib/cpus/aarch64/neoverse_v3.S
+++ b/lib/cpus/aarch64/neoverse_v3.S
@@ -26,10 +26,6 @@
 
 .global check_erratum_neoverse_v3_3701767
 
-add_erratum_entry neoverse_v3, ERRATUM(3701767), ERRATA_V3_3701767
-
-check_erratum_ls neoverse_v3, ERRATUM(3701767), CPU_REV(0, 2)
-
 workaround_reset_start neoverse_v3, ERRATUM(2970647), ERRATA_V3_2970647
 	/* Add ISB before MRS reads of MPIDR_EL1/MIDR_EL1 */
 	ldr x0, =0x1
@@ -45,17 +41,14 @@
 
 check_erratum_ls neoverse_v3, ERRATUM(2970647), CPU_REV(0, 0)
 
+add_erratum_entry neoverse_v3, ERRATUM(3701767), ERRATA_V3_3701767
+
+check_erratum_ls neoverse_v3, ERRATUM(3701767), CPU_REV(0, 2)
+
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V3_BHB_LOOP_COUNT, neoverse_v3
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
-workaround_reset_start neoverse_v3, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
-	sysreg_bit_set NEOVERSE_V3_CPUECTLR_EL1, BIT(46)
-workaround_reset_end neoverse_v3, CVE(2024, 5660)
-
-check_erratum_ls neoverse_v3, CVE(2024, 5660), CPU_REV(0, 1)
-
 workaround_reset_start neoverse_v3, CVE(2022,23960), WORKAROUND_CVE_2022_23960
 #if IMAGE_BL31
 	/*
@@ -69,6 +62,13 @@
 
 check_erratum_chosen neoverse_v3, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
+/* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
+workaround_reset_start neoverse_v3, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
+	sysreg_bit_set NEOVERSE_V3_CPUECTLR_EL1, BIT(46)
+workaround_reset_end neoverse_v3, CVE(2024, 5660)
+
+check_erratum_ls neoverse_v3, CVE(2024, 5660), CPU_REV(0, 1)
+
 workaround_reset_start neoverse_v3, CVE(2024, 7881), WORKAROUND_CVE_2024_7881
        /* ---------------------------------
         * Sets BIT41 of CPUACTLR6_EL1 which
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index e0a9076..03d18ec 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -77,7 +77,6 @@
 	uint32_t last_erratum_id = 0;
 	uint16_t last_cve_yr = 0;
 	bool check_cve = false;
-	bool failed = false;
 #endif /* FEATURE_DETECTION */
 
 	for (; entry != end; entry += 1) {
@@ -100,30 +99,20 @@
 		if (entry->cve) {
 			if (last_cve_yr > entry->cve ||
 			   (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
-				ERROR("CVE %u_%u was out of order!\n",
+				WARN("CVE %u_%u was out of order!\n",
 				      entry->cve, entry->id);
-				failed = true;
 			}
 			check_cve = true;
 			last_cve_yr = entry->cve;
 		} else {
 			if (last_erratum_id >= entry->id || check_cve) {
-				ERROR("Erratum %u was out of order!\n",
+				WARN("Erratum %u was out of order!\n",
 				      entry->id);
-				failed = true;
 			}
 		}
 		last_erratum_id = entry->id;
 #endif /* FEATURE_DETECTION */
 	}
-
-#if FEATURE_DETECTION
-	/*
-	 * enforce errata and CVEs are in ascending order and that CVEs are
-	 * after errata
-	 */
-	assert(!failed);
-#endif /* FEATURE_DETECTION */
 }
 
 /*
diff --git a/lib/extensions/trf/aarch64/trf.c b/lib/extensions/trf/aarch64/trf.c
index d36853a..dbafca1 100644
--- a/lib/extensions/trf/aarch64/trf.c
+++ b/lib/extensions/trf/aarch64/trf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,8 +22,12 @@
 	 * MDCR_EL3.TTRF = b0
 	 * Allow access of trace filter control registers from NS-EL2
 	 * and NS-EL1 when NS-EL2 is implemented but not used
+	 *
+	 * MDCR_EL3.RLTE = b0
+	 * Trace prohibited in Realm state, unless overridden by the
+	 * IMPLEMENTATION DEFINED authentication interface.
 	 */
-	mdcr_el3_val &= ~(MDCR_STE_BIT | MDCR_TTRF_BIT);
+	mdcr_el3_val &= ~(MDCR_STE_BIT | MDCR_TTRF_BIT | MDCR_RLTE_BIT);
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
 }
 
diff --git a/lib/libc/libc_common.mk b/lib/libc/libc_common.mk
index 5f44bd5..3b83216 100644
--- a/lib/libc/libc_common.mk
+++ b/lib/libc/libc_common.mk
@@ -21,9 +21,11 @@
 			snprintf.c			\
 			strchr.c			\
 			strcmp.c			\
+			strcpy_secure.c		\
 			strlcat.c			\
 			strlcpy.c			\
 			strlen.c			\
+			strnlen_secure.c	\
 			strncmp.c			\
 			strnlen.c			\
 			strrchr.c			\
diff --git a/lib/libc/strcpy_secure.c b/lib/libc/strcpy_secure.c
new file mode 100644
index 0000000..6f8de29
--- /dev/null
+++ b/lib/libc/strcpy_secure.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdint.h>
+
+int strcpy_secure(char *restrict dest, size_t dest_size, const char *restrict src)
+{
+	/* Check for null pointers */
+	if ((dest == NULL) || (src == NULL)) {
+		return -EINVAL;
+	}
+
+	/* Check the destination size valid range */
+	if (dest_size == 0) {
+		return -ERANGE;
+	}
+
+	/* Calculate the length of the source string */
+	size_t src_len = strnlen_secure(src, dest_size);
+
+	/* Check if the source string fits in the destination buffer */
+	if (src_len >= dest_size) {
+		/* Set destination to an empty string */
+		dest[0] = '\0';
+		return -ERANGE;
+	}
+
+	/* Copy the source string to the destination */
+	for (dest[src_len] = '\0'; src_len > 0; src_len--) {
+		dest[src_len - 1] = src[src_len - 1];
+	}
+
+	return 0;
+}
diff --git a/lib/libc/strnlen_secure.c b/lib/libc/strnlen_secure.c
new file mode 100644
index 0000000..36b3571
--- /dev/null
+++ b/lib/libc/strnlen_secure.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+size_t strnlen_secure(const char *str, size_t maxlen)
+{
+	size_t len = 0;
+
+	if (str == NULL) {
+		return 0;
+	}
+
+	while ((len < maxlen) && (str[len] != '\0')) {
+		len++;
+	}
+
+	return len;
+}
diff --git a/lib/transfer_list/transfer_list.c b/lib/transfer_list/transfer_list.c
index 3817861..4d4a167 100644
--- a/lib/transfer_list/transfer_list.c
+++ b/lib/transfer_list/transfer_list.c
@@ -176,35 +176,32 @@
 	}
 
 	if (tl->signature != TRANSFER_LIST_SIGNATURE) {
-		ERROR("Bad transfer list signature 0x%x\n", tl->signature);
+		VERBOSE("Bad transfer list signature 0x%x\n", tl->signature);
 		return TL_OPS_NON;
 	}
 
 	if (!tl->max_size) {
-		ERROR("Bad transfer list max size 0x%x\n",
-		      tl->max_size);
+		VERBOSE("Bad transfer list max size 0x%x\n", tl->max_size);
 		return TL_OPS_NON;
 	}
 
 	if (tl->size > tl->max_size) {
-		ERROR("Bad transfer list size 0x%x\n", tl->size);
+		VERBOSE("Bad transfer list size 0x%x\n", tl->size);
 		return TL_OPS_NON;
 	}
 
 	if (tl->hdr_size != sizeof(struct transfer_list_header)) {
-		ERROR("Bad transfer list header size 0x%x\n",
-		      tl->hdr_size);
+		VERBOSE("Bad transfer list header size 0x%x\n", tl->hdr_size);
 		return TL_OPS_NON;
 	}
 
 	if (!transfer_list_verify_checksum(tl)) {
-		ERROR("Bad transfer list checksum 0x%x\n",
-		      tl->checksum);
+		VERBOSE("Bad transfer list checksum 0x%x\n", tl->checksum);
 		return TL_OPS_NON;
 	}
 
 	if (tl->version == 0) {
-		ERROR("Transfer list version is invalid\n");
+		VERBOSE("Transfer list version is invalid\n");
 		return TL_OPS_NON;
 	} else if (tl->version == TRANSFER_LIST_VERSION) {
 		INFO("Transfer list version is valid for all operations\n");
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index ec2aa1b..906e5d7 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -192,6 +192,9 @@
 # Option to build TF with Measured Boot support
 MEASURED_BOOT			:= 0
 
+# Option to build TF with Discrete TPM support
+DISCRETE_TPM			:= 0
+
 # Option to enable the DICE Protection Environmnet as a Measured Boot backend
 DICE_PROTECTION_ENVIRONMENT	:=0
 
diff --git a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
index a951dc7..1b8699a 100644
--- a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
+++ b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,7 +11,7 @@
 void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
 			u_register_t arg2, u_register_t arg3)
 {
-	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+	arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
 
 	/* enable snoop control unit */
 	enable_snoop_ctrl_unit(A5DS_SCU_BASE);
diff --git a/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c b/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c
index 2fc0e0d..221e132 100644
--- a/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c
+++ b/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,5 +9,5 @@
 void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
 			u_register_t arg2, u_register_t arg3)
 {
-	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+	arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
 }
diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
index 662b8a4..e0b7750 100644
--- a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
@@ -343,7 +343,7 @@
 	for (unsigned long i = 0UL; i < dram_layout.num_banks; i++) {
 		int err = fdt_get_reg_props_by_index(
 				hw_config_dtb, node, (int)i,
-				&dram_layout.dram_bank[i].base,
+				(uintptr_t *)&dram_layout.dram_bank[i].base,
 				(size_t *)&dram_layout.dram_bank[i].size);
 		if (err < 0) {
 			ERROR("FCONF: Failed to read 'reg' property #%lu of 'memory' node\n", i);
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 98d4bbc..9d0463d 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -14,6 +14,7 @@
 #include <drivers/arm/ccn.h>
 #include <drivers/arm/gicv2.h>
 #include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/arm/smmu_v3.h>
 #include <drivers/generic_delay_timer.h>
 #include <fconf_hw_config_getter.h>
 #include <lib/mmio.h>
@@ -43,6 +44,15 @@
 #define FVP_RMM_CONSOLE_NAME		"pl011"
 #define FVP_RMM_CONSOLE_COUNT		UL(1)
 
+/* Defines for RMM PCIe ECAM */
+#define FVP_RMM_ECAM_BASE		PCIE_EXP_BASE
+#define FVP_RMM_ECAM_SEGMENT		UL(0x0)
+#define FVP_RMM_ECAM_BDF		UL(0x0)
+
+/* Defines for RMM SMMUv3 */
+#define FVP_RMM_SMMU_BASE		PLAT_FVP_SMMUV3_BASE
+#define FVP_RMM_SMMU_COUNT		UL(1)
+
 /*******************************************************************************
  * arm_config holds the characteristics of the differences between the three FVP
  * platforms (Base, A53_A57 & Foundation). It will be populated during cold boot
@@ -563,6 +573,41 @@
 }
 
 #if ENABLE_RME
+
+/* BDF mappings for RP0 RC0 */
+const struct bdf_mapping_info rc0rp0_bdf_data[] = {
+	/* BDF0 */
+	{0U,		/* mapping_base */
+	 0x8000U,	/* mapping_top */
+	 0U,		/* mapping_off */
+	 0U		/* smmu_idx */
+	}
+};
+
+/* Root ports for RC0 */
+const struct root_port_info rc0rp_data[] = {
+	/* RP0 */
+	{0U,						/* root_port_id */
+	 0U,						/* padding */
+	 ARRAY_SIZE(rc0rp0_bdf_data),			/* num_bdf_mappings */
+	 (struct bdf_mapping_info *)rc0rp0_bdf_data	/* bdf_mappings */
+	}
+};
+
+/* Root complexes */
+const struct root_complex_info rc_data[] = {
+	/* RC0 */
+	{PCIE_EXP_BASE,				/* ecam_base */
+	 0U,					/* segment */
+	 {0U, 0U, 0U},				/* padding */
+	 ARRAY_SIZE(rc0rp_data),		/* num_root_ports */
+	 (struct root_port_info *)rc0rp_data	/* root_ports */
+	}
+};
+
+/* Number of PCIe Root Complexes */
+#define FVP_RMM_RC_COUNT	ARRAY_SIZE(rc_data)
+
 /*
  * Get a pointer to the RMM-EL3 Shared buffer and return it
  * through the pointer passed as parameter.
@@ -593,14 +638,14 @@
 	return sum;
 }
 /*
- * Boot Manifest structure illustration, with two DRAM banks,
+ * Boot Manifest v0.5 structure illustration, with two DRAM banks,
  * a single console and one device memory with two PCIe device
  * non-coherent address ranges.
  *
  * +--------------------------------------------------+
  * | offset |        field       |      comment       |
  * +--------+--------------------+--------------------+
- * |   0    |       version      |     0x00000004     |
+ * |   0    |       version      |     0x00000005     |
  * +--------+--------------------+--------------------+
  * |   4    |       padding      |     0x00000000     |
  * +--------+--------------------+--------------------+
@@ -629,42 +674,95 @@
  * |   96   |       banks        |   plat_coh_region  |  |  |  |
  * +--------+--------------------+                    |  |  |  |
  * |   104  |      checksum      |                    |  |  |  |
- * +--------+--------------------+--------------------+<-+  |  |
- * |   112  |       base 0       |                    |     |  |
- * +--------+--------------------+     mem_bank[0]    |     |  |
- * |   120  |       size 0       |                    |     |  |
- * +--------+--------------------+--------------------+     |  |
- * |   128  |       base 1       |                    |     |  |
- * +--------+--------------------+     mem_bank[1]    |     |  |
- * |   136  |       size 1       |                    |     |  |
- * +--------+--------------------+--------------------+<----+  |
- * |   144  |       base         |                    |        |
- * +--------+--------------------+                    |        |
- * |   152  |      map_pages     |                    |        |
- * +--------+--------------------+                    |        |
- * |   160  |       name         |                    |        |
- * +--------+--------------------+     consoles[0]    |        |
- * |   168  |     clk_in_hz      |                    |        |
- * +--------+--------------------+                    |        |
- * |   176  |     baud_rate      |                    |        |
- * +--------+--------------------+                    |        |
- * |   184  |       flags        |                    |        |
- * +--------+--------------------+--------------------+<-------+
- * |   192  |       base 0       |                    |
- * +--------+--------------------+   ncoh_region[0]   |
- * |   200  |       size 0       |                    |
- * +--------+--------------------+--------------------+
- * |   208  |       base 1       |                    |
- * +--------+--------------------+   ncoh_region[1]   |
- * |   216  |       size 1       |                    |
+ * +--------+--------------------+--------------------+  |  |  |
+ * |   112  |     num_smmus      |                    |  |  |  |
+ * +--------+--------------------+                    |  |  |  |
+ * |   120  |       smmus        |     plat_smmu      +--|--|--|--+
+ * +--------+--------------------+                    |  |  |  |  |
+ * |   128  |      checksum      |                    |  |  |  |  |
+ * +--------+--------------------+--------------------+  |  |  |  |
+ * |   136  |  num_root_complex  |                    |  |  |  |  |
+ * +--------+--------------------+                    |  |  |  |  |
+ * |   144  |   rc_info_version  |                    |  |  |  |  |
+ * +--------+--------------------+                    |  |  |  |  |
+ * |   148  |      padding       | plat_root_complex  +--|--|--|--|--+
+ * +--------+--------------------+                    |  |  |  |  |  |
+ * |   152  |    root_complex    |                    |  |  |  |  |  |
+ * +--------+--------------------+                    |  |  |  |  |  |
+ * |   160  |      checksum      |                    |  |  |  |  |  |
+ * +--------+--------------------+--------------------+<-+  |  |  |  |
+ * |   168  |       base 0       |                    |     |  |  |  |
+ * +--------+--------------------+     mem_bank[0]    |     |  |  |  |
+ * |   176  |       size 0       |                    |     |  |  |  |
+ * +--------+--------------------+--------------------+     |  |  |  |
+ * |   184  |       base 1       |                    |     |  |  |  |
+ * +--------+--------------------+     mem_bank[1]    |     |  |  |  |
+ * |   192  |       size 1       |                    |     |  |  |  |
+ * +--------+--------------------+--------------------+<----+  |  |  |
+ * |   200  |       base         |                    |        |  |  |
+ * +--------+--------------------+                    |        |  |  |
+ * |   208  |      map_pages     |                    |        |  |  |
+ * +--------+--------------------+                    |        |  |  |
+ * |   216  |       name         |                    |        |  |  |
+ * +--------+--------------------+     consoles[0]    |        |  |  |
+ * |   224  |     clk_in_hz      |                    |        |  |  |
+ * +--------+--------------------+                    |        |  |  |
+ * |   232  |     baud_rate      |                    |        |  |  |
+ * +--------+--------------------+                    |        |  |  |
+ * |   240  |       flags        |                    |        |  |  |
+ * +--------+--------------------+--------------------+<-------+  |  |
+ * |   248  |       base 0       |                    |           |  |
+ * +--------+--------------------+    ncoh_region[0]  |           |  |
+ * |   256  |       size 0       |                    |           |  |
+ * +--------+--------------------+--------------------+           |  |
+ * |   264  |       base 1       |                    |           |  |
+ * +--------+--------------------+    ncoh_region[1]  |           |  |
+ * |   272  |       size 1       |                    |           |  |
+ * +--------+--------------------+--------------------+<----------+  |
+ * |   280  |     smmu_base      |                    |              |
+ * +--------+--------------------+      smmus[0]      |              |
+ * |   288  |     smmu_r_base    |                    |              |
+ * +--------+--------------------+--------------------+<-------------+
+ * |   296  |     ecam_base      |                    |
+ * +--------+--------------------+                    |
+ * |   304  |      segment       |                    |
+ * +--------+--------------------+                    |
+ * |   305  |      padding       |   root_complex[0]  +--+
+ * +--------+--------------------+                    |  |
+ * |   308  |   num_root_ports   |                    |  |
+ * +--------+--------------------+                    |  |
+ * |   312  |     root_ports     |                    |  |
+ * +--------+--------------------+--------------------+<-+
+ * |   320  |    root_port_id    |                    |
+ * +--------+--------------------+                    |
+ * |   322  |      padding       |                    |
+ * +--------+--------------------+   root_ports[0]    +--+
+ * |   324  |  num_bdf_mappings  |                    |  |
+ * +--------+--------------------+                    |  |
+ * |   328  |    bdf_mappings    |                    |  |
+ * +--------+--------------------+--------------------+<-+
+ * |   336  |    mapping_base    |                    |
+ * +--------+--------------------+                    |
+ * |   338  |    mapping_top     |                    |
+ * +--------+--------------------+   bdf_mappings[0]  |
+ * |   340  |    mapping_off     |                    |
+ * +--------+--------------------+                    |
+ * |   342  |     smmu_idx       |                    |
  * +--------+--------------------+--------------------+
  */
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
 {
 	uint64_t checksum, num_banks, num_consoles;
 	uint64_t num_ncoh_regions, num_coh_regions;
-	struct memory_bank *bank_ptr, *ncoh_region_ptr;
+	uint64_t num_smmus, num_root_complex;
+	unsigned int num_root_ports, num_bdf_mappings;
+	uint32_t o_realm;
+	struct memory_bank *bank_ptr, *ncoh_region_ptr, *coh_region_ptr;
 	struct console_info *console_ptr;
+	struct smmu_info *smmu_ptr;
+	struct root_complex_info *root_complex_ptr, *rc_ptr;
+	struct root_port_info *root_port_ptr, *rp_ptr;
+	struct bdf_mapping_info *bdf_mapping_ptr, *bdf_ptr;
 
 	assert(manifest != NULL);
 
@@ -678,12 +776,36 @@
 	/* Set number of device non-coherent address ranges based on DT */
 	num_ncoh_regions = FCONF_GET_PROPERTY(hw_config, pci_props, num_ncoh_regions);
 
+	/* Set number of SMMUs */
+	num_smmus = FVP_RMM_SMMU_COUNT;
+
+	/* Set number of PCIe root complexes */
+	num_root_complex = FVP_RMM_RC_COUNT;
+
+	/* Calculate and set number of all PCIe root ports and BDF mappings */
+	num_root_ports = 0U;
+	num_bdf_mappings = 0U;
+
+	/* Scan all root complex entries */
+	for (unsigned long i = 0UL; i < num_root_complex; i++) {
+		num_root_ports += rc_data[i].num_root_ports;
+
+		/* Scan all root ports entries in root complex */
+		for (unsigned int j = 0U; j < rc_data[i].num_root_ports; j++) {
+			num_bdf_mappings += rc_data[i].root_ports[j].num_bdf_mappings;
+		}
+	}
+
 	manifest->version = RMMD_MANIFEST_VERSION;
 	manifest->padding = 0U; /* RES0 */
 	manifest->plat_data = 0UL;
 	manifest->plat_dram.num_banks = num_banks;
 	manifest->plat_console.num_consoles = num_consoles;
 	manifest->plat_ncoh_region.num_banks = num_ncoh_regions;
+	manifest->plat_smmu.num_smmus = num_smmus;
+	manifest->plat_root_complex.num_root_complex = num_root_complex;
+	manifest->plat_root_complex.rc_info_version = PCIE_RC_INFO_VERSION;
+	manifest->plat_root_complex.padding = 0U; /* RES0 */
 
 	/* FVP does not support device coherent address ranges */
 	num_coh_regions = 0UL;
@@ -699,9 +821,27 @@
 	ncoh_region_ptr = (struct memory_bank *)
 			((uintptr_t)console_ptr + (num_consoles *
 						sizeof(struct console_info)));
+	coh_region_ptr = (struct memory_bank *)
+			((uintptr_t)ncoh_region_ptr + (num_ncoh_regions *
+						sizeof(struct memory_bank)));
+	smmu_ptr = (struct smmu_info *)
+			((uintptr_t)coh_region_ptr + (num_coh_regions *
+						sizeof(struct memory_bank)));
+	root_complex_ptr = (struct root_complex_info *)
+			((uintptr_t)smmu_ptr + (num_smmus *
+						sizeof(struct smmu_info)));
+	root_port_ptr = (struct	root_port_info *)
+			((uintptr_t)root_complex_ptr + (num_root_complex *
+						sizeof(struct root_complex_info)));
+	bdf_mapping_ptr = (struct bdf_mapping_info *)
+			((uintptr_t)root_port_ptr + (num_root_ports *
+						sizeof(struct root_port_info)));
+
 	manifest->plat_dram.banks = bank_ptr;
 	manifest->plat_console.consoles = console_ptr;
 	manifest->plat_ncoh_region.banks = ncoh_region_ptr;
+	manifest->plat_smmu.smmus = smmu_ptr;
+	manifest->plat_root_complex.root_complex = root_complex_ptr;
 
 	/* Ensure the manifest is not larger than the shared buffer */
 	assert((sizeof(struct rmm_manifest) +
@@ -712,7 +852,13 @@
 		(sizeof(struct memory_bank) *
 			manifest->plat_ncoh_region.num_banks) +
 		(sizeof(struct memory_bank) *
-			manifest->plat_coh_region.num_banks))
+			manifest->plat_coh_region.num_banks) +
+		(sizeof(struct smmu_info) *
+			manifest->plat_smmu.num_smmus) +
+		(sizeof(struct root_complex_info) *
+			manifest->plat_root_complex.num_root_complex) +
+		(sizeof(struct root_port_info) * num_root_ports) +
+		(sizeof(struct bdf_mapping_info) * num_bdf_mappings))
 		<= ARM_EL3_RMM_SHARED_SIZE);
 
 	/* Calculate checksum of plat_dram structure */
@@ -775,6 +921,87 @@
 	/* Checksum must be 0 */
 	manifest->plat_ncoh_region.checksum = ~checksum + 1UL;
 
+	/* Calculate the checksum of the plat_smmu structure */
+	checksum = num_smmus + (uint64_t)smmu_ptr;
+
+	smmu_ptr[0].smmu_base = FVP_RMM_SMMU_BASE;
+
+	/* Read SMMU_ROOT_IDR0.BA_REALM[31:22] register field */
+	o_realm = mmio_read_32(FVP_RMM_SMMU_BASE + SMMU_ROOT_IDR0) &
+				SMMU_ROOT_IDR0_BA_REALM_MASK;
+	/*
+	 * Calculate the base address offset of Realm Register Page 0.
+	 * O_REALM = 0x20000 + (BA_REALM * 0x10000)
+	 * SMMU_REALM_BASE = SMMU_PAGE_0_BASE + O_REALM
+	 */
+	o_realm = 0x20000 + (o_realm >> (SMMU_ROOT_IDR0_BA_REALM_SHIFT - 16U));
+
+	smmu_ptr[0].smmu_r_base = FVP_RMM_SMMU_BASE + o_realm;
+
+	/* Update checksum */
+	checksum += checksum_calc((uint64_t *)smmu_ptr,
+					sizeof(struct smmu_info) * num_smmus);
+	/* Checksum must be 0 */
+	manifest->plat_smmu.checksum = ~checksum + 1UL;
+
+	/* Calculate the checksum of the plat_root_complex structure */
+	checksum = num_root_complex + (uint64_t)root_complex_ptr;
+
+	/* Zero out PCIe root complex info structures */
+	(void)memset((void *)root_complex_ptr, 0,
+			sizeof(struct root_complex_info) * num_root_complex);
+
+	/* Set pointers for data in manifest */
+	rc_ptr = root_complex_ptr;
+	rp_ptr = root_port_ptr;
+	bdf_ptr = bdf_mapping_ptr;
+
+	/* Fill PCIe root complex info structures */
+	for (unsigned long i = 0U; i < num_root_complex; i++) {
+		const struct root_complex_info *rc_info = &rc_data[i];
+		const struct root_port_info *rp_info = rc_info->root_ports;
+
+		/* Copy root complex data, except root_ports pointer */
+		(void)memcpy((void *)rc_ptr, (void *)rc_info,
+			sizeof(struct root_complex_info) - sizeof(struct root_port_info *));
+
+		/* Set root_ports for root complex */
+		rc_ptr->root_ports = rp_ptr;
+
+		/* Scan root ports */
+		for (unsigned int j = 0U; j < rc_ptr->num_root_ports; j++) {
+			const struct bdf_mapping_info *bdf_info = rp_info->bdf_mappings;
+
+			/* Copy root port data, except bdf_mappings pointer */
+			(void)memcpy((void *)rp_ptr, (void *)rp_info,
+				sizeof(struct root_port_info) - sizeof(struct bdf_mapping_info *));
+
+			/* Set bdf_mappings for root port */
+			rp_ptr->bdf_mappings = bdf_ptr;
+
+			/* Copy all BDF mappings for root port */
+			(void)memcpy((void *)bdf_ptr, (void *)bdf_info,
+				sizeof(struct bdf_mapping_info) * rp_ptr->num_bdf_mappings);
+
+			bdf_ptr += rp_ptr->num_bdf_mappings;
+			rp_ptr++;
+			rp_info++;
+		}
+		rc_ptr++;
+	}
+
+	/* Check that all data are written in manifest */
+	assert(rc_ptr == (root_complex_ptr + num_root_complex));
+	assert(rp_ptr == (root_port_ptr + num_root_ports));
+	assert(bdf_ptr == (bdf_mapping_ptr + num_bdf_mappings));
+
+	/* Update checksum for all PCIe data */
+	checksum += checksum_calc((uint64_t *)root_complex_ptr,
+				(uintptr_t)bdf_ptr - (uintptr_t)root_complex_ptr);
+
+	/* Checksum must be 0 */
+	manifest->plat_root_complex.checksum = ~checksum + 1UL;
+
 	return 0;
 }
 
@@ -789,4 +1016,4 @@
 	 */
 	return 0;
 }
-#endif	/* ENABLE_RME */
+#endif /* ENABLE_RME */
diff --git a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
index 705ec38..76ca5b5 100644
--- a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
+++ b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,7 +34,7 @@
 	}
 #endif /* !RESET_TO_SP_MIN && !RESET_TO_BL2 */
 
-	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+	arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
 
 	/* Initialize the platform config for future decision making */
 	fvp_config_setup();
diff --git a/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
index e6a1bbe..eba122f 100644
--- a/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
+++ b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,5 +11,5 @@
 void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
 			u_register_t arg2, u_register_t arg3)
 {
-	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+	arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
 }
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
index 1ddd0e4..c587a55 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
@@ -178,5 +178,6 @@
 ifeq (${SPD},spmd)
 ifeq (${SPMD_SPM_AT_SEL2},1)
 override CTX_INCLUDE_SVE_REGS	:= 0
+override CTX_INCLUDE_FPREGS	:= 0
 endif
 endif
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index b8e5027..75d6a53 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -90,7 +90,7 @@
 	bl1_tzram_layout.total_size = ARM_BL_RAM_SIZE;
 
 #if TRANSFER_LIST
-	secure_tl = transfer_list_ensure((void *)PLAT_ARM_EL3_FW_HANDOFF_BASE,
+	secure_tl = transfer_list_init((void *)PLAT_ARM_EL3_FW_HANDOFF_BASE,
 					 PLAT_ARM_FW_HANDOFF_SIZE);
 	assert(secure_tl != NULL);
 #endif
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 0503acf..b67df36 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -382,8 +382,8 @@
 	struct transfer_list_entry *te __unused;
 
 #if TRANSFER_LIST && !RESET_TO_BL31
-	ns_tl = transfer_list_ensure((void *)FW_NS_HANDOFF_BASE,
-				       PLAT_ARM_FW_HANDOFF_SIZE);
+	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!\n");
 		panic();
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
index 4cd514b..78fc88e 100644
--- a/plat/arm/common/sp_min/arm_sp_min_setup.c
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -61,8 +61,8 @@
 /*******************************************************************************
  * Utility function to perform early platform setup.
  ******************************************************************************/
-void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config,
-			uintptr_t hw_config, void *plat_params_from_bl2)
+void arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
 {
 	/* Initialize the console to provide early debug support */
 	arm_console_boot_init();
@@ -99,7 +99,7 @@
 	/*
 	 * Check params passed from BL2 should not be NULL,
 	 */
-	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
 	assert(params_from_bl2 != NULL);
 	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
 	assert(params_from_bl2->h.version >= VERSION_2);
@@ -132,7 +132,7 @@
 void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
 			u_register_t arg2, u_register_t arg3)
 {
-	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+	arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
 
 	/*
 	 * Initialize Interconnect for this cluster during cold boot.
diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c
index 4e3c9f2..4908354 100644
--- a/plat/rpi/common/rpi3_common.c
+++ b/plat/rpi/common/rpi3_common.c
@@ -75,6 +75,9 @@
 #endif
 	MAP_DEVICE0,
 	MAP_FIP,
+#if MEASURED_BOOT
+	RPI3_MAP_BL1_RW,
+#endif
 	MAP_NS_DRAM0,
 #ifdef BL32_BASE
 	MAP_BL32_MEM,
diff --git a/plat/rpi/rpi3/include/platform_def.h b/plat/rpi/rpi3/include/platform_def.h
index 757c64a..eb2914a 100644
--- a/plat/rpi/rpi3/include/platform_def.h
+++ b/plat/rpi/rpi3/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -172,6 +172,14 @@
 #define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
 
 /*
+ * In order to access the TCG Event Log in BL2, we need to expose the BL1_RW region
+ * where the log resides.
+ */
+#define RPI3_MAP_BL1_RW		MAP_REGION_FLAT(BL1_RW_BASE,		\
+					BL1_RW_LIMIT - BL1_RW_BASE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
  * BL2 specific defines.
  *
  * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug
@@ -261,4 +269,15 @@
  */
 #define SYS_COUNTER_FREQ_IN_TICKS	ULL(19200000)
 
+/*
+ * TCG Event Log
+ */
+#define PLAT_ARM_EVENT_LOG_MAX_SIZE UL(0x400)
+
+/*
+ * NT_FW_CONFIG magic dram addr and max size
+ */
+#define PLAT_RPI3_DTO_BASE          ULL(0x11530000)
+#define PLAT_RPI3_DTO_MAX_SIZE      ULL(0x001000)
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi3/include/rpi3_measured_boot.h b/plat/rpi/rpi3/include/rpi3_measured_boot.h
new file mode 100644
index 0000000..67ad479
--- /dev/null
+++ b/plat/rpi/rpi3/include/rpi3_measured_boot.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_MEASURED_BOOT_H
+#define RPI3_MEASURED_BOOT_H
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+void rpi3_mboot_fetch_eventlog_info(uint8_t **eventlog_addr, size_t *eventlog_size);
+
+int rpi3_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr);
+
+#endif /* RPI3_MEASURED_BOOT_H */
diff --git a/plat/rpi/rpi3/platform.mk b/plat/rpi/rpi3/platform.mk
index fc51bec..5297177 100644
--- a/plat/rpi/rpi3/platform.mk
+++ b/plat/rpi/rpi3/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -8,7 +8,8 @@
 include lib/xlat_tables_v2/xlat_tables.mk
 
 PLAT_INCLUDES		:=	-Iplat/rpi/common/include		\
-				-Iplat/rpi/rpi3/include
+				-Iplat/rpi/rpi3/include			\
+				-Iinclude/lib/libfdt
 
 PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/aarch64/16550_console.S	\
 				drivers/arm/pl011/aarch64/pl011_console.S \
@@ -20,6 +21,40 @@
 				plat/rpi/common/rpi3_console_dual.c	\
 				${XLAT_TABLES_LIB_SRCS}
 
+ifeq (${DISCRETE_TPM},1)
+TPM2_MK := drivers/tpm/tpm2.mk
+$(info Including ${TPM2_MK})
+include ${TPM2_MK}
+endif
+
+ifeq (${TPM_INTERFACE},FIFO_SPI)
+PLAT_BL_COMMON_SOURCES	+=	drivers/gpio/gpio_spi.c		\
+				drivers/tpm/tpm2_slb9670/slb9670_gpio.c
+endif
+
+ifeq (${MEASURED_BOOT},1)
+MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
+$(info Including ${MEASURED_BOOT_MK})
+include ${MEASURED_BOOT_MK}
+
+PLAT_BL_COMMON_SOURCES	+=	$(TPM2_SOURCES)				\
+				${EVENT_LOG_SOURCES}
+
+BL1_SOURCES		+= 	plat/rpi/rpi3/rpi3_bl1_mboot.c
+BL2_SOURCES		+= 	plat/rpi/rpi3/rpi3_bl2_mboot.c		\
+				plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c	\
+				common/fdt_wrappers.c			\
+				common/fdt_fixup.c
+
+CRYPTO_SOURCES		:=	drivers/auth/crypto_mod.c
+
+BL1_SOURCES		+=	${CRYPTO_SOURCES}
+BL2_SOURCES		+=	${CRYPTO_SOURCES}
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+
+endif
+
 BL1_SOURCES		+=	drivers/io/io_fip.c			\
 				drivers/io/io_memmap.c			\
 				drivers/io/io_storage.c			\
diff --git a/plat/rpi/rpi3/rpi3_bl1_mboot.c b/plat/rpi/rpi3/rpi3_bl1_mboot.c
new file mode 100644
index 0000000..4294365
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl1_mboot.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <common/ep_info.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/gpio_spi.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <rpi_shared.h>
+
+/* Event Log data */
+uint8_t event_log[PLAT_ARM_EVENT_LOG_MAX_SIZE];
+
+/* RPI3 table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t rpi3_event_log_metadata[] = {
+	{ FW_CONFIG_ID, MBOOT_FW_CONFIG_STRING, PCR_0 },
+	{ TB_FW_CONFIG_ID, MBOOT_TB_FW_CONFIG_STRING, PCR_0 },
+	{ BL2_IMAGE_ID, MBOOT_BL2_IMAGE_STRING, PCR_0 },
+
+	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+};
+
+#if DISCRETE_TPM
+extern struct tpm_chip_data tpm_chip_data;
+#if (TPM_INTERFACE == FIFO_SPI)
+extern struct gpio_spi_data tpm_rpi3_gpio_data;
+struct spi_plat *spidev;
+#endif
+
+static void rpi3_bl1_tpm_early_interface_setup(void)
+{
+#if (TPM_INTERFACE == FIFO_SPI)
+	tpm2_slb9670_gpio_init(&tpm_rpi3_gpio_data);
+
+	tpm2_slb9670_reset_chip(&tpm_rpi3_gpio_data);
+
+	spidev = gpio_spi_init(&tpm_rpi3_gpio_data);
+#endif
+}
+#endif
+
+void bl1_plat_mboot_init(void)
+{
+#if DISCRETE_TPM
+	int rc;
+
+	rpi3_bl1_tpm_early_interface_setup();
+	rc = tpm_interface_init(&tpm_chip_data, 0);
+	if (rc != 0) {
+		ERROR("BL1: TPM interface init failed\n");
+		panic();
+	}
+	rc = tpm_startup(&tpm_chip_data, TPM_SU_CLEAR);
+	if (rc != 0) {
+		ERROR("BL1: TPM Startup failed\n");
+		panic();
+	}
+#endif
+
+	event_log_init(event_log, event_log + sizeof(event_log));
+	event_log_write_header();
+}
+
+void bl1_plat_mboot_finish(void)
+{
+	size_t event_log_cur_size;
+	image_desc_t *image_desc;
+	entry_point_info_t *ep_info;
+
+	event_log_cur_size = event_log_get_cur_size(event_log);
+	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(image_desc != NULL);
+
+	/* Get the entry point info */
+	ep_info = &image_desc->ep_info;
+	ep_info->args.arg2 = (uint64_t) event_log;
+	ep_info->args.arg3 = (uint32_t) event_log_cur_size;
+
+#if DISCRETE_TPM
+	int rc;
+
+	/* relinquish control of TPM locality 0 and close interface */
+	rc = tpm_interface_close(&tpm_chip_data, 0);
+	if (rc != 0) {
+		ERROR("BL1: TPM interface close failed\n");
+		panic();
+	}
+#endif
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+	int rc = 0;
+	unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+	const event_log_metadata_t *metadata_ptr = rpi3_event_log_metadata;
+
+	rc = event_log_measure(image_data->image_base, image_data->image_size, hash_data);
+	if (rc != 0) {
+		return rc;
+	}
+
+#if DISCRETE_TPM
+	rc = tpm_pcr_extend(&tpm_chip_data, 0, TPM_ALG_ID, hash_data, TCG_DIGEST_SIZE);
+	if (rc != 0) {
+		ERROR("BL1: TPM PCR-0 extend failed\n");
+		panic();
+	}
+#endif
+
+	while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+		(metadata_ptr->id != image_id)) {
+		metadata_ptr++;
+	}
+	assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+	event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+	/* Dump Event Log for user view */
+	dump_event_log((uint8_t *)event_log, event_log_get_cur_size(event_log));
+
+	return rc;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_mboot.c b/plat/rpi/rpi3/rpi3_bl2_mboot.c
new file mode 100644
index 0000000..55c6923
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl2_mboot.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "./include/rpi3_measured_boot.h"
+
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/gpio_spi.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/tbbr_oid.h>
+
+/* RPI3 table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t rpi3_event_log_metadata[] = {
+	{ BL31_IMAGE_ID, MBOOT_BL31_IMAGE_STRING, PCR_0 },
+	{ BL33_IMAGE_ID, MBOOT_BL33_IMAGE_STRING, PCR_0 },
+	{ NT_FW_CONFIG_ID, MBOOT_NT_FW_CONFIG_STRING, PCR_0 },
+
+	{ EVLOG_INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+};
+
+#if DISCRETE_TPM
+extern struct tpm_chip_data tpm_chip_data;
+#if (TPM_INTERFACE == FIFO_SPI)
+extern struct gpio_spi_data tpm_rpi3_gpio_data;
+struct spi_plat *spidev;
+#endif
+
+static void rpi3_bl2_tpm_early_interface_setup(void)
+{
+#if (TPM_INTERFACE == FIFO_SPI)
+	tpm2_slb9670_gpio_init(&tpm_rpi3_gpio_data);
+
+	spidev = gpio_spi_init(&tpm_rpi3_gpio_data);
+#endif
+}
+#endif
+
+static uint8_t *event_log_start;
+static size_t event_log_size;
+
+void bl2_plat_mboot_init(void)
+{
+	uint8_t *bl2_event_log_start;
+	uint8_t *bl2_event_log_finish;
+
+#if DISCRETE_TPM
+	int rc;
+
+	rpi3_bl2_tpm_early_interface_setup();
+	rc = tpm_interface_init(&tpm_chip_data, 0);
+	if (rc != 0) {
+		ERROR("BL2: TPM interface init failed\n");
+		panic();
+	}
+#endif
+
+	rpi3_mboot_fetch_eventlog_info(&event_log_start, &event_log_size);
+	bl2_event_log_start = event_log_start + event_log_size;
+	bl2_event_log_finish = event_log_start + PLAT_ARM_EVENT_LOG_MAX_SIZE;
+	event_log_init(bl2_event_log_start, bl2_event_log_finish);
+}
+
+void bl2_plat_mboot_finish(void)
+{
+	int rc;
+
+	/* Event Log address in Non-Secure memory */
+	uintptr_t ns_log_addr;
+
+	/* Event Log filled size */
+	size_t event_log_cur_size;
+
+	event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_start);
+
+	/* write the eventlog addr and size to NT_FW_CONFIG TPM entry */
+	rc = rpi3_set_nt_fw_info(event_log_cur_size, &ns_log_addr);
+	if (rc != 0) {
+		ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+			__func__, "NT");
+		/*
+		 * fatal error due to Bl33 maintaining the assumption
+		 * that the eventlog is successfully passed via
+		 * NT_FW_CONFIG.
+		 */
+		panic();
+	}
+
+	/* Copy Event Log to Non-secure memory */
+	(void)memcpy((void *)ns_log_addr, (const void *)event_log_start,
+		     event_log_cur_size);
+
+	/* Ensure that the Event Log is visible in Non-secure memory */
+	flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+	/* Dump Event Log for user view */
+	dump_event_log((uint8_t *)event_log_start, event_log_cur_size);
+
+#if DISCRETE_TPM
+	/* relinquish control of TPM locality 0 and close interface */
+	rc = tpm_interface_close(&tpm_chip_data, 0);
+	if (rc != 0) {
+		ERROR("BL2: TPM interface close failed\n");
+		panic();
+	}
+#endif
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+	int rc = 0;
+
+	unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+	const event_log_metadata_t *metadata_ptr = rpi3_event_log_metadata;
+
+	/* Measure the payload with algorithm selected by EventLog driver */
+	rc = event_log_measure(image_data->image_base, image_data->image_size, hash_data);
+	if (rc != 0) {
+		return rc;
+	}
+
+#if DISCRETE_TPM
+	rc = tpm_pcr_extend(&tpm_chip_data, 0, TPM_ALG_ID, hash_data, TCG_DIGEST_SIZE);
+	if (rc != 0) {
+		ERROR("BL2: TPM PCR-0 extend failed\n");
+		panic();
+	}
+#endif
+
+	while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+		(metadata_ptr->id != image_id)) {
+		metadata_ptr++;
+	}
+	assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+	event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+	return rc;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c
index 80e4d8d..2f57b32 100644
--- a/plat/rpi/rpi3/rpi3_bl2_setup.c
+++ b/plat/rpi/rpi3/rpi3_bl2_setup.c
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <assert.h>
 
-#include <platform_def.h>
+#include "./include/rpi3_measured_boot.h"
 
 #include <arch_helpers.h>
 #include <common/bl_common.h>
@@ -18,6 +18,7 @@
 #include <drivers/generic_delay_timer.h>
 #include <drivers/rpi3/gpio/rpi3_gpio.h>
 #include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+#include <platform_def.h>
 
 #include <rpi_shared.h>
 
@@ -27,6 +28,10 @@
 /* Data structure which holds the MMC info */
 static struct mmc_device_info mmc_info;
 
+/* Variables that hold the eventlog addr and size for use in BL2 Measured Boot */
+static uint8_t *event_log_start;
+static size_t event_log_size;
+
 static void rpi3_sdhost_setup(void)
 {
 	struct rpi3_sdhost_params params;
@@ -41,6 +46,12 @@
 	rpi3_sdhost_init(&params, &mmc_info);
 }
 
+void rpi3_mboot_fetch_eventlog_info(uint8_t **eventlog_addr, size_t *eventlog_size)
+{
+	*eventlog_addr = event_log_start;
+	*eventlog_size = event_log_size;
+}
+
 /*******************************************************************************
  * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
  * in x0. This memory layout is sitting at the base of the free trusted SRAM.
@@ -67,6 +78,10 @@
 	/* Setup SDHost driver */
 	rpi3_sdhost_setup();
 
+	/* populate eventlog addr and size for use in bl2 mboot */
+	event_log_start = (uint8_t *)(uintptr_t)arg2;
+	event_log_size = arg3;
+
 	plat_rpi3_io_setup();
 }
 
diff --git a/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c b/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
new file mode 100644
index 0000000..7c2e6e7
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <platform_def.h>
+
+#define DTB_PROP_HW_LOG_ADDR	"tpm_event_log_addr"
+#define DTB_PROP_HW_LOG_SIZE	"tpm_event_log_size"
+
+static int rpi3_event_log_fdt_init_overlay(uintptr_t dt_base, int dt_size)
+{
+	int ret;
+	int offset;
+	void *dtb = (void *)dt_base;
+
+	ret = fdt_create_empty_tree(dtb, dt_size);
+	if (ret < 0) {
+		ERROR("cannot create empty dtb tree: %s\n",
+		       fdt_strerror(ret));
+		return ret;
+	}
+
+	offset = fdt_path_offset(dtb, "/");
+	if (offset < 0) {
+		ERROR("cannot find root of the tree: %s\n",
+		       fdt_strerror(offset));
+		return offset;
+	}
+
+	offset = fdt_add_subnode(dtb, offset, "fragment@0");
+	if (offset < 0) {
+		ERROR("cannot add fragment node: %s\n",
+		       fdt_strerror(offset));
+		return offset;
+	}
+
+	ret = fdt_setprop_string(dtb, offset, "target-path", "/");
+	if (ret < 0) {
+		ERROR("cannot set target-path property: %s\n",
+		       fdt_strerror(ret));
+		return ret;
+	}
+
+	offset = fdt_add_subnode(dtb, offset, "__overlay__");
+	if (offset < 0) {
+		ERROR("cannot add __overlay__ node: %s\n",
+		       fdt_strerror(offset));
+		return ret;
+	}
+
+	offset = fdt_add_subnode(dtb, offset, "tpm_event_log");
+	if (offset < 0) {
+		ERROR("cannot add tpm_event_log node: %s\n",
+		       fdt_strerror(offset));
+		return offset;
+	}
+
+	ret = fdt_setprop_string(dtb, offset, "compatible",
+				 "arm,tpm_event_log");
+	if (ret < 0) {
+		ERROR("cannot set compatible property: %s\n",
+		       fdt_strerror(ret));
+		return ret;
+	}
+
+	ret = fdt_setprop_u64(dtb, offset, "tpm_event_log_addr", 0);
+	if (ret < 0) {
+		ERROR("cannot set tpm_event_log_addr property: %s\n",
+		       fdt_strerror(ret));
+		return ret;
+	}
+
+	ret = fdt_setprop_u32(dtb, offset, "tpm_event_log_size", 0);
+	if (ret < 0) {
+		ERROR("cannot set tpm_event_log_size property: %s\n",
+		       fdt_strerror(ret));
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * Write the Event Log address and its size in the DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *	0 = success
+ *    < 0 = error
+ */
+static int rpi3_set_event_log_info(uintptr_t config_base,
+				  uintptr_t log_addr, size_t log_size)
+{
+	/* As libfdt uses void *, we can't avoid this cast */
+	void *dtb = (void *)config_base;
+	/* compatible is set based on the following tpm_tis_spi guidelines from
+	 * https://www.kernel.org/doc/Documentation/devicetree/bindings
+	 * /security/tpm/tpm_tis_spi.txt
+	 */
+	const char *compatible_tpm = "arm,tpm_event_log";
+	uint64_t base = cpu_to_fdt64(log_addr);
+	uint32_t sz = cpu_to_fdt32(log_size);
+	int err, node;
+
+	err = fdt_open_into(dtb, dtb, PLAT_RPI3_DTO_MAX_SIZE);
+	if (err < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
+		return err;
+	}
+
+	/*
+	 * Verify that the DTB is valid, before attempting to write to it,
+	 * and get the DTB root node.
+	 */
+
+	/* Check if the pointer to DT is correct */
+	err = fdt_check_header(dtb);
+	if (err < 0) {
+		WARN("Invalid DTB file passed\n");
+		return err;
+	}
+
+	/*
+	 * Find the TPM node in device tree.
+	 */
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm);
+	if (node < 0) {
+		ERROR("The compatible property '%s' not%s", compatible_tpm,
+			" found in the config\n");
+		return node;
+	}
+
+	err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8);
+	if (err < 0) {
+		ERROR("Failed to add log addr err %d\n", err);
+		return err;
+	}
+
+	err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4);
+	if (err < 0) {
+		ERROR("Failed to add log size err %d\n", err);
+		return err;
+	}
+
+	err = fdt_pack(dtb);
+	if (err < 0) {
+		ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, err);
+		return err;
+	}
+
+	/*
+	 * Ensure that the info written to the DTB is visible
+	 * to other images.
+	 */
+	flush_dcache_range(config_base, fdt_totalsize(dtb));
+
+	return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the RPi3 DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *	0 = success
+ *    < 0 = error
+ */
+int rpi3_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr)
+{
+	uintptr_t ns_addr;
+	int err;
+
+	assert(ns_log_addr != NULL);
+
+	ns_addr = PLAT_RPI3_DTO_BASE + PLAT_RPI3_DTO_MAX_SIZE;
+
+	rpi3_event_log_fdt_init_overlay(PLAT_RPI3_DTO_BASE,
+					  PLAT_RPI3_DTO_MAX_SIZE);
+
+	/* Write the Event Log address and its size in the DTB */
+	err = rpi3_set_event_log_info(PLAT_RPI3_DTO_BASE,
+					ns_addr, log_size);
+
+	/* Return Event Log address in Non-secure memory */
+	*ns_log_addr = (err < 0) ? 0UL : ns_addr;
+	return err;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
index 5ffd9ef..849e38a 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
@@ -1,6 +1,6 @@
 /*
  * 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-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -123,7 +123,7 @@
 		.name = "qspi0",
 		.regval = 0x02,
 		.group_base = PINCTRL_GRP_QSPI0_0,
-		.group_size = PINCTRL_GRP_QSPI0_0 - PINCTRL_GRP_QSPI0_0 + 1U,
+		.group_size = PINCTRL_GRP_QSPI0_1 - PINCTRL_GRP_QSPI0_0 + 1U,
 	},
 	[PINCTRL_FUNC_QSPI_FBCLK] = {
 		.name = "qspi_fbclk",
@@ -135,7 +135,7 @@
 		.name = "qspi_ss",
 		.regval = 0x02,
 		.group_base = PINCTRL_GRP_QSPI_SS,
-		.group_size = PINCTRL_GRP_QSPI_SS - PINCTRL_GRP_QSPI_SS + 1U,
+		.group_size = PINCTRL_GRP_QSPI_SS_1 - PINCTRL_GRP_QSPI_SS + 1U,
 	},
 	[PINCTRL_FUNC_SPI0] = {
 		.name = "spi0",
@@ -383,6 +383,7 @@
 	[PINCTRL_PIN_0] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_QSPI0_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
@@ -401,6 +402,7 @@
 	[PINCTRL_PIN_1] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_QSPI0_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
@@ -419,6 +421,7 @@
 	[PINCTRL_PIN_2] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_QSPI0_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
@@ -437,6 +440,7 @@
 	[PINCTRL_PIN_3] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_QSPI0_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
@@ -455,6 +459,7 @@
 	[PINCTRL_PIN_4] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_QSPI0_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
@@ -473,6 +478,7 @@
 	[PINCTRL_PIN_5] = {
 		.groups = &((uint16_t []) {
 			PINCTRL_GRP_QSPI_SS,
+			PINCTRL_GRP_QSPI_SS_1,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_RESERVED,
 			PINCTRL_GRP_TESTSCAN0_0,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
index 277af4b..cb3b62e 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -184,7 +185,9 @@
 	PINCTRL_GRP_MDIO2_0,
 	PINCTRL_GRP_MDIO3_0,
 	PINCTRL_GRP_QSPI0_0,
+	PINCTRL_GRP_QSPI0_1,
 	PINCTRL_GRP_QSPI_SS,
+	PINCTRL_GRP_QSPI_SS_1,
 	PINCTRL_GRP_QSPI_FBCLK,
 	PINCTRL_GRP_SPI0_0,
 	PINCTRL_GRP_SPI0_1,