Merge changes from topic "xlnx_fix_plat_single_ret" into integration

* changes:
  fix(versal2): modify function to have single return
  fix(versal-net): modify function to have single return
  fix(versal): modify function to have single return
  fix(xilinx): modify function to have single return
  fix(zynqmp): modify function to have single return
  fix(versal-net): add unsigned suffix to match data type
  fix(versal): add unsigned suffix to match data type
  fix(versal2): add missing curly braces
  fix(versal-net): add missing curly braces
  fix(zynqmp): add missing curly braces
diff --git a/Makefile b/Makefile
index 6f080b4..51c7b2e 100644
--- a/Makefile
+++ b/Makefile
@@ -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
 #
@@ -23,7 +23,6 @@
 
 MAKE_HELPERS_DIRECTORY := make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}build-rules.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 
@@ -99,15 +98,15 @@
 
 # Variables for use with Certificate Generation Tool
 CRTTOOLPATH		?=	tools/cert_create
-CRTTOOL			?=	${CRTTOOLPATH}/cert_create${BIN_EXT}
+CRTTOOL			?=	${CRTTOOLPATH}/cert_create$(.exe)
 
 # Variables for use with Firmware Encryption Tool
 ENCTOOLPATH		?=	tools/encrypt_fw
-ENCTOOL			?=	${ENCTOOLPATH}/encrypt_fw${BIN_EXT}
+ENCTOOL			?=	${ENCTOOLPATH}/encrypt_fw$(.exe)
 
 # Variables for use with Firmware Image Package
 FIPTOOLPATH		?=	tools/fiptool
-FIPTOOL			?=	${FIPTOOLPATH}/fiptool${BIN_EXT}
+FIPTOOL			?=	${FIPTOOLPATH}/fiptool$(.exe)
 
 # Variables for use with sptool
 SPTOOLPATH		?=	tools/sptool
@@ -514,6 +513,12 @@
 endif
 
 ################################################################################
+# Include the platform specific Makefile after the SPD Makefile (the platform
+# makefile may use all previous definitions in this file)
+################################################################################
+include ${PLAT_MAKEFILE_FULL}
+
+################################################################################
 # Process BRANCH_PROTECTION value and set
 # Pointer Authentication and Branch Target Identification flags
 ################################################################################
@@ -558,12 +563,6 @@
 endif
 
 ################################################################################
-# Include the platform specific Makefile after the SPD Makefile (the platform
-# makefile may use all previous definitions in this file)
-################################################################################
-include ${PLAT_MAKEFILE_FULL}
-
-################################################################################
 # Setup arch_features based on ARM_ARCH_MAJOR, ARM_ARCH_MINOR provided from
 # platform.
 ################################################################################
@@ -599,11 +598,6 @@
 ################################################################################
 # FEAT_RME
 ifeq (${ENABLE_RME},1)
-	# RME doesn't support PIE
-	ifneq (${ENABLE_PIE},0)
-                $(error ENABLE_RME does not support PIE)
-	endif
-
 	# RME requires AARCH64
 	ifneq (${ARCH},aarch64)
                 $(error ENABLE_RME requires AArch64)
@@ -959,6 +953,14 @@
 	ifneq (${ENABLE_FEAT_FPMR},0)
                 $(error "ENABLE_FEAT_FPMR cannot be used with ARCH=aarch32")
 	endif
+
+	ifeq (${ARCH_FEATURE_AVAILABILITY},1)
+                $(error "ARCH_FEATURE_AVAILABILITY cannot be used with ARCH=aarch32")
+	endif
+	# FEAT_MOPS is only supported on AArch64
+	ifneq (${ENABLE_FEAT_MOPS},0)
+		$(error "ENABLE_FEAT_MOPS cannot be used with ARCH=aarch32")
+	endif
 endif #(ARCH=aarch32)
 
 ifneq (${ENABLE_FEAT_FPMR},0)
@@ -1207,6 +1209,7 @@
 	PROGRAMMABLE_RESET_ADDRESS \
 	PSCI_EXTENDED_STATE_ID \
 	PSCI_OS_INIT_MODE \
+	ARCH_FEATURE_AVAILABILITY \
 	RESET_TO_BL31 \
 	SAVE_KEYS \
 	SEPARATE_CODE_AND_RODATA \
@@ -1284,6 +1287,7 @@
 	ENABLE_FEAT_FPMR \
 	ENABLE_FEAT_HCX \
 	ENABLE_FEAT_LS64_ACCDATA \
+	ENABLE_FEAT_MOPS \
 	ENABLE_FEAT_MTE2 \
 	ENABLE_FEAT_PAN \
 	ENABLE_FEAT_RNG \
@@ -1388,6 +1392,7 @@
 	PROGRAMMABLE_RESET_ADDRESS \
 	PSCI_EXTENDED_STATE_ID \
 	PSCI_OS_INIT_MODE \
+	ARCH_FEATURE_AVAILABILITY \
 	RESET_TO_BL31 \
 	RME_GPT_BITLOCK_BLOCK \
 	RME_GPT_MAX_BLOCK \
@@ -1461,6 +1466,7 @@
 	ENABLE_FEAT_SCTLR2 \
 	ENABLE_FEAT_D128 \
 	ENABLE_FEAT_GCS \
+	ENABLE_FEAT_MOPS \
 	ENABLE_FEAT_MTE2 \
 	FEATURE_DETECTION \
 	TWED_DELAY \
@@ -1645,29 +1651,17 @@
 
 clean:
 	$(s)echo "  CLEAN"
-	$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
-ifdef UNIX_MK
+	$(q)rm -rf $(BUILD_PLAT)
 	$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
-else
-# Clear the MAKEFLAGS as we do not want
-# to pass the gnumake flags to nmake.
-	$(q)set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL)) clean
-endif #(UNIX_MK)
 	$(q)${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
 	$(q)${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} clean
 	$(q)${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
 
 realclean distclean:
 	$(s)echo "  REALCLEAN"
-	$(call SHELL_REMOVE_DIR,${BUILD_BASE})
-	$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
-ifdef UNIX_MK
+	$(q)rm -rf $(BUILD_BASE)
+	$(q)rm -rf $(CURDIR)/cscope.*
 	$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
-else
-# Clear the MAKEFLAGS as we do not want
-# to pass the gnumake flags to nmake.
-	$(q)set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL)) realclean
-endif #(UNIX_MK)
 	$(q)${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} realclean
 	$(q)${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean
 	$(q)${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
@@ -1752,25 +1746,14 @@
 fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME}
 
 ${FIPTOOL}: FORCE
-ifdef UNIX_MK
 	$(q)${MAKE} PLAT=${PLAT} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" FIPTOOL=${FIPTOOL} OPENSSL_DIR=${OPENSSL_DIR} DEBUG=${DEBUG} --no-print-directory -C ${FIPTOOLPATH} all
-else
-# Clear the MAKEFLAGS as we do not want
-# to pass the gnumake flags to nmake.
-	$(q)set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL))
-endif #(UNIX_MK)
 
 $(BUILD_PLAT)/romlib/romlib.bin $(BUILD_PLAT)/lib/libwrappers.a $&: $(BUILD_PLAT)/lib/libfdt.a $(BUILD_PLAT)/lib/libc.a $(CRYPTO_LIB)
 	$(q)${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} CRYPTO_SUPPORT=${CRYPTO_SUPPORT} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES=$(call escape-shell,$(INCLUDES)) DEFINES=$(call escape-shell,$(DEFINES)) --no-print-directory -C ${ROMLIBPATH} all
 
 memmap: all
-ifdef UNIX_MK
 	$(q)PYTHONPATH=${CURDIR}/tools/memory \
 		${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
-else
-	$(q)set PYTHONPATH=${CURDIR}/tools/memory && \
-		${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
-endif
 
 tl: ${BUILD_PLAT}/tl.bin
 ${BUILD_PLAT}/tl.bin: ${HW_CONFIG}
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 0f6be9f..821ccb8 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -286,6 +286,12 @@
 			     ID_AA64PFR2_EL1_FPMR_MASK);
 }
 
+static unsigned int read_feat_mops_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64isar2_el1(), ID_AA64ISAR2_EL1_MOPS_SHIFT,
+			     ID_AA64ISAR2_EL1_MOPS_MASK);
+}
+
 /***********************************************************************************
  * TF-A supports many Arm architectural features starting from arch version
  * (8.0 till 8.7+). These features are mostly enabled through build flags. This
@@ -343,6 +349,8 @@
 	check_feature(ENABLE_FEAT_DIT, read_feat_dit_id_field(), "DIT", 1, 1);
 	check_feature(ENABLE_FEAT_AMU, read_feat_amu_id_field(),
 		      "AMUv1", 1, 2);
+	check_feature(ENABLE_FEAT_MOPS, read_feat_mops_id_field(),
+		      "MOPS", 1, 1);
 	check_feature(ENABLE_FEAT_MPAM, read_feat_mpam_version(),
 		      "MPAM", 1, 17);
 	check_feature(CTX_INCLUDE_NEVE_REGS, read_feat_nv_id_field(),
diff --git a/docs/about/index.rst b/docs/about/index.rst
index 06973ef..7cf2a68 100644
--- a/docs/about/index.rst
+++ b/docs/about/index.rst
@@ -7,6 +7,7 @@
 
    features
    release-information
+   lts
    maintainers
    contact
    acknowledgements
diff --git a/docs/about/lts.rst b/docs/about/lts.rst
new file mode 100644
index 0000000..f5e5f8e
--- /dev/null
+++ b/docs/about/lts.rst
@@ -0,0 +1,364 @@
+LTS - Long-Term Support
+=======================
+
+.. table:: Table 1: Document History
+
+  +-------------+--------------------+-------------------------------------------------------+
+  | Date        | Author             | Description                                           |
+  +=============+====================+=======================================================+
+  | 2022-07-20  | Okash Khawaja,     | Initial draft.                                        |
+  |             | Varun Wadekar      |                                                       |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2022-07-21  | Varun Wadekar      | Refine the Maintainership guidelines and planning     |
+  |             |                    | sections. Introduce a new section documenting a day   |
+  |             |                    | in the life of a LTS branch maintainer                |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2022-08-05  | Okash Khawaja,     | Merge two drafts (draft 1 and 2), address comments    |
+  |             | Varun Wadekar      | made by both authors, cosmetic changes to the content |
+  |             |                    | all over the document                                 |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2022-08-05  | Okash Khawaja      | Add note about testing support available from TF.org  |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2022-08-05  | Varun Wadekar      | Changed the “Future plans” section to “FAQ” and       |
+  |             |                    | answered some of the questions with feedback from     |
+  |             |                    | the community.                                        |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2025-01-07  | Govindraj Raja     | Convert from pdf to rst.                              |
+  +-------------+--------------------+-------------------------------------------------------+
+  | 2025-01-07  | Govindraj Raja     | Updates based on learnings and suggestions.           |
+  +-------------+--------------------+-------------------------------------------------------+
+
+This document proposes a plan for long-term support (LTS) of the |TF-A| project.
+
+Why is LTS required?
+--------------------
+LTS is needed for commercial reasons. More specifically, on the device side,
+when a product is released, the companies have to support that in-market product
+such that the amount of changes to the firmware are kept to a minimum to avoid
+the risk of regression. At the same time the companies don't want to exclude
+critical patches such as those for security advisories. Similarly on the server side,
+companies want to minimize the churn when deploying fixes during incident
+response, e.g. due to critical security bugs.
+
+Also, the European Cyber Resilience Act (CRA) is a new EU legislation that mandates
+cybersecurity standards for products containing digital elements, aiming to
+protect consumers and businesses by ensuring manufacturers build security into
+their hardware and software throughout their lifecycle, including automatic
+updates and incident reporting; essentially requiring all digital products
+sold in the EU to meet specific cybersecurity requirements.
+
+This means that companies have to maintain and backport critical updates to
+old branches internally. As this effort is duplicated across different companies
+using TF-A, it makes sense to factor out this effort into a community-wide LTS.
+
+What does LTS mean for TF-A?
+----------------------------
+In this section we will define exactly what constitutes LTS for TF-A.
+Specifically, we will define the following characteristics:
+
+- criteria for selecting patches which will be backported to LTS branches
+- lifetime and frequency of LTS branches
+
+**Criteria**
+
+We must have an objective criterion for selecting patches to be backported to
+LTS branches. This will make maintenance easy because:
+
+a. there will be less -- ideally no -- discussion when selecting patches to backport
+b. large parts of the process can be automated
+
+Below is the criteria
+
+#. No features will be backported.
+#. Security advisories: Any patch that makes it into :ref:`Security Advisories`
+   is automatically selected for back porting. This includes patches to external
+   components too, e.g. libfdt.
+#. Workarounds for CPU and other ARM IP errata
+#. Workarounds for non-ARM IP errata, e.g. TI UART
+#. Fixes for platform bugs. These patches must not modify any code outside of
+   the specific platform that the fix applies to.
+#. Patches can only be backported from the master branch. In other words, the
+   master branch will be a superset of all the changes in any LTS branch.
+
+**Lifetime and frequency**
+
+This section approaches three questions: for how long should an LTS release be
+supported, how frequently should LTS releases be made and at which time(s) of
+the year should the releases be made.
+
+1. For how long should an LTS release be supported?
+
+The Linux kernel maintainers supports an LTS branch for 2 years. Since firmware
+tends to have less churn and longer lifetime than a HLOS, TF-A is trying to
+support at-least 7 years for its LTS. Initially it was intended to support
+5 years but there has been no objections to extend LTS support to 7 years.
+There are many challenges that may influence the 7 year support from CI
+infrastructure to availability of maintainers.
+
+2. How frequently should LTS releases be made?
+
+Given that many products that have a release cycle, have a yearly release
+cycle, it would make sense to have yearly TF-A releases.
+
+3. Which time(s) of the year should the releases be made?
+
+TF-A releases are cut twice a year: May and November. Basing LTS release
+on the November TF-A release has a few benefits. First, it aligns with Linux
+LTS releases which happen towards the end of each year. Second, it aligns
+with Android releases which tend to fall in Q3 each year. Since product
+releases are timed with Android release, this gives enough time to harden
+the TF-A LTS release during development so that it's ready for launch in
+Q3 following year. On the other hand, if the May release of TF-A is chosen as
+the basis for LTS then developers will have little time -- about a month,
+taking into account the test-and-debug phase before LTS is cut (see below) --
+before Android release.
+
+To summarize, there will be one LTS release per year. It will be supported for
+5 years and we can discuss extending it to 7 years later on. The LTS release
+will be based on the November release of TF-A.
+
+**Testing Criteria**
+
+Every patch merged to the LTS branch will complete the following tests before
+getting approved.
+
+#. TFTF tests currently running in the testing farm
+#. CI/CD static analysis scans
+#. Coverity scans
+#. Platform tests
+
+Platforms that are not maintained upstream will undergo testing downstream in a
+pre-defined window. The platform maintainer will complete the testing and provide
+a verified score on the patch once testing is completed.
+
+** A note about test coverage from TF.org **
+
+Currently TF.org maintains a CI system to run TF-A automated tests on a
+selection of HW boards donated by TF.org members (a benefit reserved to project
+members, see the project charter for more details). This automated test coverage
+will be extended to cover testing for LTS as well for boards that are part of
+the CI system.
+
+**TFTF Branching**
+
+A note about testing here. After a patch is backported to an LTS branch, that
+branch will need to be regression tested. Since TFTF moves forward with latest
+TF-A changes, newer TFTF tests may not apply to old LTS branches. Therefore
+TFTF will also need to be branched, in-sync with TF-A LTS branches. In other
+words, there will be one TFTF LTS branch corresponding to each TF-A LTS branch.
+The TFTF LTS branch will be used to regression test the corresponding TF-A LTS
+branch.
+
+As we work with the LTS branch of TFTF, we might also need fixes for TFTF
+itself to be ported to LTS. However, decision-making about those patches need
+not be as stringent as for TF-A.
+
+**CI Scripts**
+
+CI Scripts moves forward with TF-A changes, since we need to checkout the
+corresponding release version of CI scripts for LTS.
+
+Though we are unlikely to update CI scripts, but time to time migrating a newer
+FVP version or deprecating certain tests due to unavailability of platforms may
+influence updates to CI Scripts.
+
+**Hafnium / OP-TEE**
+
+Both Hafnium and OP-TEE move forward with TF-A changes so we need to freeze their
+corresponding version from TF-A release for a LTS.
+
+**MbedTLS**
+
+Updates to the version of MbedTLS used with LTS will happen time to time based on
+maintainers call to update them or not.
+
+Release details
+---------------
+This section goes into details of what the LTS release process will look like.
+
+
+**Test-and-debug period**
+
+Since the LTS branch will be used in product releases, it is expected that more
+testing and debugging will be done on the November release of TF-A. Therefore
+it would make sense to leave at least a month after the November release and
+then cut the LTS branch. We recommend two months, given that one of the months
+is December which tends to be slower due to holidays. So, an end-of-November
+TF-A release would result in a beginning-of-February LTS release. Note that
+the LTS branch will be created at the same time as the TF-A November release,
+but it will be officially released at the end of January or early February.
+Going forward we should strive to make the period smaller and smaller until
+ideally it coincides with TF-A November release which means that our test
+and CI/CD infra is good enough to allow that to happen.
+
+**Example timeline**
+
+Below is an example timeline starting from the November 2022 release of TF-A.
+
+.. image:: ../resources/diagrams/lts-timeline-example.png
+
+- Nov 2022: TF-A 2.8 is released towards the end of Nov, 2022. Not shown in the
+  diagram, at the same time LTS release candidate branch is made which is based
+  on TF-A 2.8. This means new features going in 2.8 won’t go in the LTS branch.
+  We can call it `LTS 2.8-rc`.
+- Feb 2023: After testing and debugging LTS 2.8-rc for a couple of months,
+  LTS 2.8.0 is officially released in early Feb 2023.
+- May 2023: TF-A 2.9 is released but since this is not an LTS branch it doesn’t
+  affect LTS.
+- Somewhere between May and Nov of 2023: A security advisory comes up and the
+  related patches go into TF-A master branch. Since these patches fall under
+  LTS criteria, they are backported to LTS 2.8.0 which results in LTS 2.8.1
+  being released. Note that here we don’t allow the extra testing and debugging
+  time that we had between Nov 2022 and early Feb 2023. This is because there
+  isn’t as much to test and debug as an annual LTS release has. Also companies
+  might want to deploy critical patches soon.
+- Nov 2023: TF-A 2.10 is released. Not shown in the diagram, at the same time
+  LTS 2.10-rc is made. It’s tested by partners for a couple of months.
+- Feb 2024: LTS 2.10.1 is released in early Feb. Now there are two LTS
+  branches: 2.8.1 and 2.10.1.
+
+Note that TFTF will follow similar branching model as TF-A LTS, i.e. there will
+be TFTF LTS 2.8.0 in Feb 2023, 2.8.1 (if new TFTF tests need to be added for
+the security advisory) when there is TF-A LTS 2.8.1 and so on.
+
+Maintainership
+--------------
+
+**Guidelines & Responsibilities**
+
+#. Maintainers shall be impartial and strive to work for the benefit of
+   the community
+#. Objective and well-defined merge criteria to avoid confusion and discussions
+   at random points in time when there is a "candidate" patch
+#. The maintainers shall explain the lifecycle of a patch to the community,
+   with a detailed description of the maximum time spent in each step
+#. Automate, automate, automate
+#. Reviewers should not focus too much on "what" and instead focus on "how"
+#. Constantly refine the merge criteria to include more partner use cases
+#. Ensure that all candidate patches flow from the main branch to all LTS branches
+#. Maintainers collaborate in the following discord channel -
+   https://discord.com/channels/1106321706588577904/1162029539761852436
+#. Maintainers discuss and provide updates about upcoming LTS releases in the above
+   mentioned discord channel.
+
+**Options**
+
+These are some options in the order of preference.
+
+#. Current set of :ref:`lts maintainers` from tf.org(or hired contractor) take care of the LTS
+#. From the community, create a set of maintainers focused solely on the LTS branches
+
+A day in the life of a maintainer
+*********************************
+This section documents the daily tasks that a maintainer might perform to
+support the LTS program. It is expected that a maintainer follows clearly laid
+down steps and does not have to make policy level decisions for merge, testing,
+or candidate patch selection.
+
+#. Monitor the main branch to identify candidate patches for the LTS branches
+#. Monitor emails from LTS triage report to choose patches that should be
+   cherry-picked for LTS branches.
+#. Cherry-pick agreed patches to LTS branches co-ordinate review process and Monitor
+   CI results.
+#. Monitor the mailing list for any LTS related issues
+#. Propose or solicit patches to the main branch and tag them as candidates for LTS
+
+Execution Plan
+**************
+This section lists the steps needed to put the LTS system in place. However,
+to kick start LTS in Nov ‘22, only a few steps are needed. The rest can follow
+in the background.
+
+Initial release steps
+*********************
+
+The following steps are necessary to kickstart the project and potentially
+create the first LTS from the Nov’22 release.
+
+#. Create a TF-A LTS release-candidate branch and a TFTF LTS branch immediately
+   after the Nov’22 release
+#. Request all platform-owners to test and debug the RC branch
+#. Gather feedback from the test and debug cycle
+#. Mark the TF-A LTS branch ready by the end of January
+#. Announce the official LTS release availability on the mailing lists
+
+Long term release plan
+**********************
+Above will buy us time to then work on the rest of the execution plan which
+is given below.
+
+#. The review criteria for LTS patches must be the same as TF-A patches
+#. The maintainers shall publish the well-defined merge criteria to allow
+   the community to choose candidate patches
+#. The maintainers shall publish a well-defined test specification for any
+   patch entering the LTS branch
+
+   a. Tests required to pass in the CI/CD flow
+   b. Static analysis scans
+   c. Coverity scans
+
+#. The maintainers shall publish a mechanism to choose candidate patches for
+   the LTS branch
+#. The maintainers shall publish a mechanism to report bugs `[1]`_ seen with
+   an LTS branch
+#. The maintainers shall publish a versioning mechanism for the LTS branch
+
+   a. Bump minor version for any “logical” `[2]`_ fix(es) that gets merged
+
+#. The CI/CD infrastructure shall provide test support for all “live” LTS
+   branches at any given point in time
+#. The CI/CD infrastructure shall provide means to
+
+   a. notify all maintainers that a patch is ready for review
+   b. automatically cherry-pick a patch to a given LTS branch
+   c. get it through the CI/CD testing flow
+   d. gentle ping in LTS discord channel asking for reviews to ensure
+      cherry-picks are merged.
+
+FAQ
+***
+
+In our discussions, in addition to the above points we also considered some
+questions. They have been discussed on the mailing list too.
+
+| Q. What happens when a bug fix applies just to a LTS branch and not to the
+     master branch?
+| A. This will be treated as a special case and the bug, and the fix will be
+     discussed
+
+| Q. When testing a backported patch, what if one of the partners needs more
+     time while the patch fix is time-critical and, hence slowing other
+     partners?
+| A. The maintainers will add more detail to the review and merge process to
+     handle this scenario.
+
+| Q. How do we handle the increasing version numbers for errata fixes?
+| A. Too many CPU errata workarounds resulting in too many LTS releases.
+     We propose bumping the version number for each logical fix as
+     described in the section “Long term release plan” above because
+     that will help accurately track what changes have been deployed in-field.
+
+| Q. What if LTS support duration needs to be extended to longer than 5 years?
+| A. Still under discussion.
+
+These are uncharted waters, and we will face some unseen problems. When they
+become real problems, then we will have concrete data and be better able to
+address them. This means that our LTS definition as presented in this document
+is not the final one. We will constantly be discussing it and deciding how to
+adapt it as we see practical problems.
+
+.. _[1]:
+
+[1] The plan is to create a system where reviewers can tag a patch on mainline which
+gets automatically rebased on LTS and pushed to Gerrit. On seeing this patch,
+the CI/CD starts tests and provides a score. In parallel, the system also sends
+an email to the maintainers announcing the arrival of a candidate patch for the
+LTS branch.
+
+.. _[2]:
+
+[2] Logical will be a patch or patches implementing a certain fix. For example, if a
+security mitigation is fixed with the help of three patches, then all of them are
+considered as one "logical" fix. The version is incremented only after all these
+patches are merged. with the maintainers. If agreed unanimously, the bug fix
+will be merged to the affected LTS branches after completing the review process.
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index a8f1676..c45a757 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -58,6 +58,8 @@
 :|M|: Govindraj Raja <govindraj.raja@arm.com>
 :|G|: `govindraj-arm`_
 
+.. _lts maintainers:
+
 LTS Maintainers
 ---------------
 
@@ -653,8 +655,8 @@
 
 Marvell platform ports and SoC drivers
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-:|M|: Konstantin Porotchkin <kostap@marvell.com>
-:|G|: `kostapr`_
+:|M|: Jaiprakash Singh <jaiprakashs@marvell.com>
+:|G|: `sjaypee208`_
 :|F|: docs/plat/marvell/
 :|F|: plat/marvell/
 :|F|: drivers/marvell/
@@ -1128,6 +1130,7 @@
 .. _vishnu-banavath: https://github.com/vishnu-banavath
 .. _vwadekar: https://github.com/vwadekar
 .. _Yann-lms: https://github.com/Yann-lms
+.. _sjaypee208: https://github.com/sjaypee208
 
 --------------
 
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index 9d6bbf6..dc2b2fd 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -35,7 +35,7 @@
 
 For example, TF-A v2.10 has VERSION_MAJOR=2, VERSION_MINOR=10 and VERSION_PATCH=0.
 
-This VERSION_PATCH macro is only increased for LTS releases.
+This VERSION_PATCH macro is only increased for :ref:`LTS - Long-Term Support` releases.
 
 Upcoming Releases
 ~~~~~~~~~~~~~~~~~
@@ -120,4 +120,4 @@
 
 --------------
 
-*Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/design/trusted-board-boot-build.rst b/docs/design/trusted-board-boot-build.rst
index caf367b..1cc1ba6 100644
--- a/docs/design/trusted-board-boot-build.rst
+++ b/docs/design/trusted-board-boot-build.rst
@@ -54,16 +54,34 @@
       On Juno board, the default value corresponds to an ECDSA-SECP256R1 public
       key hash, whose private part is not currently available.
 
-   -  ``ARM_ROTPK_LOCATION=devel_rsa``: use the default hash located in
-      ``plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin``. Enforce
-      generation of the new hash if ``ROT_KEY`` is specified.
+   -  ``ARM_ROTPK_LOCATION=devel_rsa``: the ROTPK is a hash of the
+      RSA public key corresponding to the private key specified by
+      ``ROT_KEY``. If ``ROT_KEY`` is not specified, the private key is
+      the development key ``plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem``.
+      There are also 3k and 4k RSA development keys in ``plat/arm/board/common/rotpk/``.
+      The hashing algorithm is selected by ``HASH_ALG``; sha256 is used if
+      ``HASH_ALG`` is not specified.
 
-   -  ``ARM_ROTPK_LOCATION=devel_ecdsa``: use the default hash located in
-      ``plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin``. Enforce
-      generation of the new hash if ``ROT_KEY`` is specified.
+   -  ``ARM_ROTPK_LOCATION=devel_ecdsa``: the ROTPK is a hash of the
+      ECDSA public key corresponding to the private key specified by
+      ``ROT_KEY``. If ``ROT_KEY`` is not specified, the private key is
+      the development key ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem`` by default,
+      a 384 bit key ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa_secp384r1.pem`` also exists,
+      and can be specified by ``ROT_KEY``. The hashing algorithm is selected by ``HASH_ALG``;
+      sha256 is used if ``HASH_ALG`` is not specified.
 
-   -  ``ARM_ROTPK_LOCATION=devel_full_dev_rsa_key``: use the key located in
-      ``plat/arm/board/common/rotpk/arm_full_dev_rsa_rotpk.S``.
+   -  ``ARM_ROTPK_LOCATION=devel_full_dev_rsa_key``: the ROTPK is an unhashed
+      RSA public key corresponding to the private key specified by ``ROT_KEY``.
+      If ``ROT_KEY`` is not specified, the private key is the development key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem``. There are also
+      3k and 4k RSA development keys in ``plat/arm/board/common/rotpk/``.
+
+   -  ``ARM_ROTPK_LOCATION=devel_full_dev_ecdsa_key``: the ROTPK is an unhashed
+      RSA public key corresponding to the private key specified by ``ROT_KEY``.
+      If ``ROT_KEY`` is not specified, the private key is the development key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem``, a 384 bit key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa_secp384r1.pem`` also exists,
+      and can be specified by ``ROT_KEY``.
 
    Example of command line using RSA development keys:
 
@@ -119,7 +137,7 @@
 
 --------------
 
-*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
 
 .. _mbed TLS Repository: https://github.com/ARMmbed/mbedtls.git
 .. _mbed TLS Security Center: https://tls.mbed.org/security
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
index f10d2e7..f3e094c 100644
--- a/docs/design/trusted-board-boot.rst
+++ b/docs/design/trusted-board-boot.rst
@@ -39,7 +39,8 @@
 
 -  A Root of Trust Public Key (ROTPK), or a hash of it.
 
-   On Arm development platforms, a SHA-256 hash of the ROTPK is stored in the
+   On Arm development platforms, a hash of the ROTPK (hash algorithm selected by
+   the ``HASH_ALG`` build option, with sha256 as default) is stored in the
    trusted root-key storage registers. Alternatively, a development ROTPK might
    be used and its hash embedded into the BL1 and BL2 images (only for
    development purposes).
@@ -330,7 +331,7 @@
 
 --------------
 
-*Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.*
 
 .. _X.509 v3: https://tools.ietf.org/rfc/rfc5280.txt
 .. _Trusted Board Boot Requirements (TBBR): https://developer.arm.com/docs/den0006/latest
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 14eac5f..58321e7 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -378,6 +378,16 @@
    flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
    mechanism. Default value is ``0``.
 
+- ``ENABLE_FEAT_MOPS``: Numeric value to enable FEAT_MOPS (Standardization
+   of memory operations) when INIT_UNUSED_NS_EL2=1.
+   This feature is mandatory from v8.8 and enabling of FEAT_MOPS does not
+   require any settings from EL3 as the controls are present in EL2 registers
+   (HCRX_EL2.{MSCEn,MCE2} and SCTLR_EL2.MSCEn) and in most configurations
+   we expect EL2 to be present. But in case of INIT_UNUSED_NS_EL2=1 ,
+   EL3 should configure the EL2 registers. This flag
+   can take values 0 to 2, to align with the ``ENABLE_FEAT`` mechanism.
+   Default value is ``0``.
+
 -  ``ENABLE_FEAT_MTE2``: Numeric value to enable Memory Tagging Extension2
    if the platform wants to use this feature and MTE2 is enabled at ELX.
    This flag can take values 0 to 2, to align with the ``ENABLE_FEAT``
@@ -737,9 +747,9 @@
    +---------------------------+------------------------------------+
    |          ecdsa            |         256 (default), 384         |
    +---------------------------+------------------------------------+
-   |  ecdsa-brainpool-regular  |            unavailable             |
+   |  ecdsa-brainpool-regular  |            256 (default)           |
    +---------------------------+------------------------------------+
-   |  ecdsa-brainpool-twisted  |            unavailable             |
+   |  ecdsa-brainpool-twisted  |            256 (default)           |
    +---------------------------+------------------------------------+
 
 -  ``HASH_ALG``: This build flag enables the user to select the secure hash
@@ -858,6 +868,11 @@
 -  ``PSCI_OS_INIT_MODE``: Boolean flag to enable support for optional PSCI
    OS-initiated mode. This option defaults to 0.
 
+-  ``ARCH_FEATURE_AVAILABILITY``: Boolean flag to enable support for the
+   optional SMCCC_ARCH_FEATURE_AVAILABILITY call. This option implicitly
+   interacts with IMPDEF_SYSREG_TRAP and software emulation. This option
+   defaults to 0.
+
 -  ``ENABLE_FEAT_RAS``: Boolean flag to enable Armv8.2 RAS features. RAS features
    are an optional extension for pre-Armv8.2 CPUs, but are mandatory for Armv8.2
    or later CPUs. This flag can take the values 0 or 1. The default value is 0.
diff --git a/docs/glossary.rst b/docs/glossary.rst
index f19897c..20ad21c 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -130,6 +130,9 @@
       Memory Tagging Extension. An optional Armv8.5 extension that enables
       hardware-assisted memory tagging.
 
+   LTS
+      Long-Term Support
+
    OEN
       Owning Entity Number
 
diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst
index afbb157..a086a98 100644
--- a/docs/plat/arm/arm-build-options.rst
+++ b/docs/plat/arm/arm-build-options.rst
@@ -65,25 +65,26 @@
    -  ``regs`` : return the ROTPK hash stored in the Trusted root-key storage
       registers.
    -  ``devel_rsa`` : return a development public key hash embedded in the BL1
-      and BL2 binaries. This hash has been obtained from the RSA public key
-      ``arm_rotpk_rsa.der``, located in ``plat/arm/board/common/rotpk``. To use
-      this option, ``arm_rotprivk_rsa.pem`` must be specified as ``ROT_KEY``
-      when creating the certificates.
+      and BL2 binaries. This hash corresponds to the development private key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem``.
+      The hashing algorithm is selected by ``HASH_ALG``; sha256 is used if
+      ``HASH_ALG`` is not specified. A different RSA key can be specified by setting
+      ``ROT_KEY``, there are 3k and 4k RSA keys in ``plat/arm/board/common/rotpk/``.
    -  ``devel_ecdsa`` : return a development public key hash embedded in the BL1
-      and BL2 binaries. This hash has been obtained from the ECDSA public key
-      ``arm_rotpk_ecdsa.der``, located in ``plat/arm/board/common/rotpk``. To
-      use this option, ``arm_rotprivk_ecdsa.pem`` must be specified as
-      ``ROT_KEY`` when creating the certificates.
-   -  ``devel_full_dev_rsa_key`` : returns a development public key embedded in
-      the BL1 and BL2 binaries. This key has been obtained from the RSA public
-      key ``arm_rotpk_rsa.der``, located in ``plat/arm/board/common/rotpk``.
-
--  ``ARM_ROTPK_HASH``: used when ``ARM_ROTPK_LOCATION=devel_*``, excluding
-   ``devel_full_dev_rsa_key``. Specifies the location of the ROTPK hash. Not
-   expected to be a build option. This defaults to
-   ``plat/arm/board/common/rotpk/*_sha256.bin`` depending on the specified
-   algorithm. Providing ``ROT_KEY`` enforces generation of the hash from the
-   ``ROT_KEY`` and overwrites the default hash file.
+      and BL2 binaries. This hash corresponds to the development private key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem`` unless a different key
+      is specified with ``ROT_KEY``, such as the 384 bit key in the same directory.
+      he hashing algorithm is selected by ``HASH_ALG``; sha256 is used if ``HASH_ALG``
+      is not specified.
+   -  ``devel_full_dev_rsa_key`` : return a development public key embedded in
+      the BL1 and BL2 binaries. This key corresponds to the RSA private
+      key ``plat/arm/board/common/rotpk/arm_rotprivk.pem`` by default, but can
+      be changed by setting ``ROT_KEY``, there are 3k and 4k RSA keys in
+      ``plat/arm/board/common/rotpk/``.
+   - ``devel_full_dev_ecdsa_key`` : return a development public key embedded in
+      the BL1 and BL2 binaries. This key corresponds to the EC private key
+      ``plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem``, unless a different
+      ECDSA key is specified by ``ROT_KEY``, such as the 384 bit key in the same directory.
 
 -  ``ARM_TSP_RAM_LOCATION``: location of the TSP binary. Options:
 
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 5cb20fd..6d03f44 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2454,7 +2454,7 @@
 The value should be obtained from a reliable source of randomness.
 
 This function is only needed if ARMv8.3 pointer authentication is used in the
-Trusted Firmware by building with ``BRANCH_PROTECTION`` option set to non-zero.
+Trusted Firmware by building with ``BRANCH_PROTECTION`` option set to 1, 2 or 3.
 
 Function : plat_get_syscnt_freq2() [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3553,7 +3553,10 @@
 This function is invoked by BL31's exception handler when there is a synchronous
 system register trap caused by access to the implementation defined registers.
 It allows platforms enabling ``IMPDEF_SYSREG_TRAP`` to emulate those system
-registers choosing to program bits of their choice.
+registers choosing to program bits of their choice. If using in combination with
+``ARCH_FEATURE_AVAILABILITY``, the macros
+{SCR,MDCR,CPTR}_PLAT_{BITS,IGNORED,FLIPPED} should be defined to report correct
+results.
 
 The first parameter (``uint64_t esr_el3``) contains the content of the ESR_EL3
 syndrome register, which encodes the instruction that was trapped.
diff --git a/docs/resources/diagrams/lts-timeline-example.png b/docs/resources/diagrams/lts-timeline-example.png
new file mode 100644
index 0000000..edb1145
--- /dev/null
+++ b/docs/resources/diagrams/lts-timeline-example.png
Binary files differ
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
index 9fe8b37..fbcbdc7 100644
--- a/drivers/arm/css/scp/css_pm_scmi.c
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -312,7 +312,7 @@
 	/*
 	 * Send powerdown request to online secondary core(s)
 	 */
-	ret = psci_stop_other_cores(0, css_raise_pwr_down_interrupt);
+	ret = psci_stop_other_cores(plat_my_core_pos(), 0, css_raise_pwr_down_interrupt);
 	if (ret != PSCI_E_SUCCESS) {
 		ERROR("Failed to powerdown secondary core(s)\n");
 	}
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
index ef04c4d..adca4fd 100644
--- a/drivers/arm/smmu/smmu_v3.c
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -124,22 +124,35 @@
 				      gptbr_el3 << 12);
 
 			/*
-			 * ACCESSEN=1: SMMU- and client-originated accesses are
-			 *             not terminated by this mechanism.
 			 * GPCEN=1: All clients and SMMU-originated accesses,
 			 *          except GPT-walks, are subject to GPC.
+			 *
+			 * It is recommended to set GPCEN and wait for completion
+			 * prior to setting ACCESSEN.
 			 */
 			mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
+					SMMU_ROOT_CR0_GPCEN);
+
+			/* Poll for GPCEN ack bit. */
+			if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
+					SMMU_ROOT_CR0_GPCEN,
+					SMMU_ROOT_CR0_GPCEN) != 0) {
+				WARN("Failed enabling SMMU GPC.\n");
+			}
+
+			/*
+			 * ACCESSEN=1: SMMU- and client-originated accesses are
+			 *             not terminated by this mechanism.
+			 */
+			mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
 					SMMU_ROOT_CR0_GPCEN |
 					SMMU_ROOT_CR0_ACCESSEN);
 
-			/* Poll for ACCESSEN and GPCEN ack bits. */
+			/* Poll for ACCESSEN ack bit. */
 			if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
-					SMMU_ROOT_CR0_GPCEN |
 					SMMU_ROOT_CR0_ACCESSEN,
-					SMMU_ROOT_CR0_GPCEN |
 					SMMU_ROOT_CR0_ACCESSEN) != 0) {
-				WARN("Failed enabling SMMU GPC.\n");
+				WARN("Failed enabling SMMU ACCESS.\n");
 
 				/*
 				 * Do not return in error, but fall back to
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index 9b57607..235b988 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -7,6 +7,7 @@
 #include <common/debug.h>
 #include <drivers/clk.h>
 #include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
 #include <s32cc-clk-ids.h>
 #include <s32cc-clk-modules.h>
 #include <s32cc-clk-regs.h>
@@ -1464,7 +1465,39 @@
 	return 0;
 }
 
-void s32cc_clk_register_drv(void)
+static int s32cc_clk_mmap_regs(const struct s32cc_clk_drv *drv)
+{
+	const uintptr_t base_addrs[11] = {
+		drv->fxosc_base,
+		drv->armpll_base,
+		drv->periphpll_base,
+		drv->armdfs_base,
+		drv->cgm0_base,
+		drv->cgm1_base,
+		drv->cgm5_base,
+		drv->ddrpll_base,
+		drv->mc_me,
+		drv->mc_rgm,
+		drv->rdc,
+	};
+	size_t i;
+	int ret;
+
+	for (i = 0U; i < ARRAY_SIZE(base_addrs); i++) {
+		ret = mmap_add_dynamic_region(base_addrs[i], base_addrs[i],
+					      PAGE_SIZE,
+					      MT_DEVICE | MT_RW | MT_SECURE);
+		if (ret != 0) {
+			ERROR("Failed to map clock module 0x%" PRIuPTR "\n",
+			      base_addrs[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int s32cc_clk_register_drv(bool mmap_regs)
 {
 	static const struct clk_ops s32cc_clk_ops = {
 		.enable		= s32cc_clk_enable,
@@ -1475,7 +1508,19 @@
 		.get_parent	= s32cc_clk_get_parent,
 		.set_parent	= s32cc_clk_set_parent,
 	};
+	const struct s32cc_clk_drv *drv;
 
 	clk_register(&s32cc_clk_ops);
+
+	drv = get_drv();
+	if (drv == NULL) {
+		return -EINVAL;
+	}
+
+	if (mmap_regs) {
+		return s32cc_clk_mmap_regs(drv);
+	}
+
+	return 0;
 }
 
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index 02b9df9..f001568 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -180,11 +180,14 @@
 	return ret;
 }
 
-int s32cc_init_early_clks(void)
+int s32cc_init_core_clocks(void)
 {
 	int ret;
 
-	s32cc_clk_register_drv();
+	ret = s32cc_clk_register_drv(false);
+	if (ret != 0) {
+		return ret;
+	}
 
 	ret = setup_fxosc();
 	if (ret != 0) {
@@ -206,6 +209,18 @@
 		return ret;
 	}
 
+	return ret;
+}
+
+int s32cc_init_early_clks(void)
+{
+	int ret;
+
+	ret = s32cc_clk_register_drv(true);
+	if (ret != 0) {
+		return ret;
+	}
+
 	ret = setup_periph_pll();
 	if (ret != 0) {
 		return ret;
diff --git a/fdts/tc-base.dtsi b/fdts/tc-base.dtsi
index e898399..691a3b8 100644
--- a/fdts/tc-base.dtsi
+++ b/fdts/tc-base.dtsi
@@ -387,7 +387,7 @@
 	soc_uartclk: uartclk {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
-		clock-frequency = <UARTCLK_FREQ>;
+		clock-frequency = <TC_UARTCLK>;
 		clock-output-names = "uartclk";
 	};
 
diff --git a/fdts/tc-fpga.dtsi b/fdts/tc-fpga.dtsi
index af140bb..a3feacc 100644
--- a/fdts/tc-fpga.dtsi
+++ b/fdts/tc-fpga.dtsi
@@ -25,7 +25,7 @@
 		stdout-path = "serial0:38400n8";
 	};
 
-#if TC_FPGA_ANDROID_IMG_IN_RAM
+#if TC_FPGA_FS_IMG_IN_RAM
 	reserved-memory {
 		phram@0x880000000 {
 			/*
@@ -36,7 +36,7 @@
 			no-map;
 		};
 	};
-#endif /* TC_FPGA_ANDROID_IMG_IN_RAM */
+#endif /* TC_FPGA_FS_IMG_IN_RAM */
 
 	ethernet: ethernet@ETHERNET_ADDR {
 		compatible = "smsc,lan9115";
diff --git a/fdts/tc2.dts b/fdts/tc2.dts
index c492274..003efdc 100644
--- a/fdts/tc2.dts
+++ b/fdts/tc2.dts
@@ -36,7 +36,6 @@
 #define BIG_CPU_PMU_COMPATIBLE		"arm,cortex-x4-pmu"
 
 #define MPAM_ADDR			0x1 0x00010000 /* 0x1_0001_0000 */
-#define UARTCLK_FREQ			5000000
 
 #define DPU_ADDR			2cc00000
 #define DPU_IRQ				69
diff --git a/fdts/tc3-4-base.dtsi b/fdts/tc3-4-base.dtsi
index c7f3084..049a4c6 100644
--- a/fdts/tc3-4-base.dtsi
+++ b/fdts/tc3-4-base.dtsi
@@ -18,15 +18,12 @@
 #define MHU_RX_INT_NAME			"combined"
 
 #define MPAM_ADDR			0x0 0x5f010000 /* 0x5f01_0000 */
-#define UARTCLK_FREQ			3750000
 
 #if TARGET_FLAVOUR_FVP
 #define DPU_ADDR			4000000000
 #define DPU_IRQ				579
-#elif TARGET_FLAVOUR_FPGA
-#define DPU_ADDR			2cc00000
-#define DPU_IRQ				69
 #endif
+
 #include "tc-base.dtsi"
 
 / {
diff --git a/fdts/tc3.dts b/fdts/tc3.dts
index b8fe587..22d4d10 100644
--- a/fdts/tc3.dts
+++ b/fdts/tc3.dts
@@ -40,6 +40,11 @@
 #define VIRTIO_BLOCK_ADDR		1c130000
 #define VIRTIO_BLOCK_INT		204
 
+#if TARGET_FLAVOUR_FPGA
+#define DPU_ADDR			2cc00000
+#define DPU_IRQ				69
+#endif
+
 #include "tc-common.dtsi"
 #if TARGET_FLAVOUR_FVP
 #include "tc-fvp.dtsi"
diff --git a/fdts/tc4.dts b/fdts/tc4.dts
index 5ab58d5..ab93391 100644
--- a/fdts/tc4.dts
+++ b/fdts/tc4.dts
@@ -20,14 +20,21 @@
 #define RSE_MHU_TX_ADDR			49020000 /* hex */
 #define RSE_MHU_RX_ADDR			49030000 /* hex */
 
+#if TARGET_FLAVOUR_FVP
 #define ETHERNET_ADDR			64000000
 #define ETHERNET_INT			799
-
 #define SYS_REGS_ADDR			60080000
-
 #define MMC_ADDR			600b0000
 #define MMC_INT_0			778
 #define MMC_INT_1			779
+#else /* TARGET_FLAVOUR_FPGA */
+#define ETHERNET_ADDR			18000000
+#define ETHERNET_INT			109
+#define SYS_REGS_ADDR			1c010000
+#define MMC_ADDR			1c050000
+#define MMC_INT_0			107
+#define MMC_INT_1			108
+#endif /* TARGET_FLAVOUR_FVP */
 
 #define RTC_ADDR			600a0000
 #define RTC_INT				777
@@ -40,6 +47,11 @@
 #define VIRTIO_BLOCK_ADDR		60020000
 #define VIRTIO_BLOCK_INT		769
 
+#if TARGET_FLAVOUR_FPGA
+#define DPU_ADDR			4000000000
+#define DPU_IRQ				579
+#endif
+
 #include "tc-common.dtsi"
 #if TARGET_FLAVOUR_FVP
 #include "tc-fvp.dtsi"
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 3a7e2eb..4d26153 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -317,6 +317,10 @@
 
 /* ID_AA64ISAR2_EL1 definitions */
 #define ID_AA64ISAR2_EL1		S3_0_C0_C6_2
+#define ID_AA64ISAR2_EL1_MOPS_SHIFT	U(16)
+#define ID_AA64ISAR2_EL1_MOPS_MASK	ULL(0xf)
+
+#define MOPS_IMPLEMENTED		ULL(0x1)
 
 /* ID_AA64PFR2_EL1 definitions */
 #define ID_AA64PFR2_EL1			S3_0_C0_C4_2
@@ -654,15 +658,18 @@
 
 /* MDCR_EL3 definitions */
 #define MDCR_EBWE_BIT		(ULL(1) << 43)
-#define MDCR_E3BREC		(ULL(1) << 38)
-#define MDCR_E3BREW		(ULL(1) << 37)
+#define MDCR_E3BREC_BIT		(ULL(1) << 38)
+#define MDCR_E3BREW_BIT		(ULL(1) << 37)
 #define MDCR_EnPMSN_BIT		(ULL(1) << 36)
 #define MDCR_MPMX_BIT		(ULL(1) << 35)
 #define MDCR_MCCD_BIT		(ULL(1) << 34)
 #define MDCR_SBRBE_SHIFT	U(32)
-#define MDCR_SBRBE_MASK		ULL(0x3)
+#define MDCR_SBRBE(x)		((x) << MDCR_SBRBE_SHIFT)
+#define MDCR_SBRBE_ALL		ULL(0x3)
+#define MDCR_SBRBE_NS		ULL(0x1)
 #define MDCR_NSTB(x)		((x) << 24)
 #define MDCR_NSTB_EL1		ULL(0x3)
+#define MDCR_NSTB_EL3		ULL(0x2)
 #define MDCR_NSTBE_BIT		(ULL(1) << 26)
 #define MDCR_MTPME_BIT		(ULL(1) << 28)
 #define MDCR_TDCC_BIT		(ULL(1) << 27)
@@ -679,6 +686,7 @@
 #define MDCR_SPD32_ENABLE	ULL(0x3)
 #define MDCR_NSPB(x)		((x) << 12)
 #define MDCR_NSPB_EL1		ULL(0x3)
+#define MDCR_NSPB_EL3		ULL(0x2)
 #define MDCR_NSPBE_BIT		(ULL(1) << 11)
 #define MDCR_TDOSA_BIT		(ULL(1) << 10)
 #define MDCR_TDA_BIT		(ULL(1) << 9)
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 8bdc13c..1d0a2e0 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -144,6 +144,8 @@
  * +----------------------------+
  * |	FEAT_FPMR		|
  * +----------------------------+
+ * |	FEAT_MOPS		|
+ * +----------------------------+
  */
 
 __attribute__((always_inline))
@@ -290,7 +292,10 @@
 CREATE_FEATURE_FUNCS(feat_fpmr, id_aa64pfr2_el1, ID_AA64PFR2_EL1_FPMR_SHIFT,
 		     ID_AA64PFR2_EL1_FPMR_MASK, FPMR_IMPLEMENTED,
 		     ENABLE_FEAT_FPMR)
-
+/* FEAT_MOPS */
+CREATE_FEATURE_FUNCS(feat_mops, id_aa64isar2_el1, ID_AA64ISAR2_EL1_MOPS_SHIFT,
+		     ID_AA64ISAR2_EL1_MOPS_MASK, MOPS_IMPLEMENTED,
+		     ENABLE_FEAT_MOPS)
 
 __attribute__((always_inline))
 static inline bool is_feat_sxpie_supported(void)
@@ -353,8 +358,8 @@
 		     ID_AA64MMFR1_EL1_HCX_MASK, 1U, ENABLE_FEAT_HCX)
 
 /* FEAT_RNG_TRAP: Trapping support */
-CREATE_FEATURE_PRESENT(feat_rng_trap, id_aa64pfr1_el1, ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT,
-		      ID_AA64PFR1_EL1_RNDR_TRAP_MASK, RNG_TRAP_IMPLEMENTED)
+CREATE_FEATURE_FUNCS(feat_rng_trap, id_aa64pfr1_el1, ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT,
+		      ID_AA64PFR1_EL1_RNDR_TRAP_MASK, RNG_TRAP_IMPLEMENTED, ENABLE_FEAT_RNG_TRAP)
 
 /* Return the RME version, zero if not supported. */
 CREATE_FEATURE_FUNCS(feat_rme, id_aa64pfr0_el1, ID_AA64PFR0_FEAT_RME_SHIFT,
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 3f3f14d..8b92f19 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -295,6 +295,7 @@
 DEFINE_SYSREG_RW_FUNCS(dbgdtrtx_el0)
 DEFINE_SYSREG_RW_FUNCS(sp_el1)
 DEFINE_SYSREG_RW_FUNCS(sp_el2)
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1)
 
 DEFINE_SYSOP_FUNC(wfi)
 DEFINE_SYSOP_FUNC(wfe)
diff --git a/include/drivers/auth/mbedtls/default_mbedtls_config.h b/include/drivers/auth/mbedtls/default_mbedtls_config.h
index fa5c6f6..23daf24 100644
--- a/include/drivers/auth/mbedtls/default_mbedtls_config.h
+++ b/include/drivers/auth/mbedtls/default_mbedtls_config.h
@@ -152,3 +152,9 @@
  * the warnings to more functions.
  */
 #define MBEDTLS_CHECK_RETURN_WARNING
+
+/*
+ * Use an implementation of SHA-256 with a smaller memory footprint but reduced
+ * speed.
+ */
+#define MBEDTLS_SHA256_SMALLER
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h
index d879f5b..632b82f 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h
@@ -6,6 +6,7 @@
 #ifndef S32CC_CLK_DRV_H
 #define S32CC_CLK_DRV_H
 
+int s32cc_init_core_clocks(void);
 int s32cc_init_early_clks(void);
 
 #endif
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h
index e6adecc..c6e90f0 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h
@@ -5,6 +5,7 @@
 #ifndef S32CC_CLK_UTILS_H
 #define S32CC_CLK_UTILS_H
 
+#include <stdbool.h>
 #include <s32cc-clk-modules.h>
 
 struct s32cc_clk *s32cc_get_clk_from_table(const struct s32cc_clk_array *const *clk_arr,
@@ -18,6 +19,6 @@
 struct s32cc_clk *s32cc_get_arch_clk(unsigned long id);
 int s32cc_get_clk_id(const struct s32cc_clk *clk, unsigned long *id);
 
-void s32cc_clk_register_drv(void);
+int s32cc_clk_register_drv(bool mmap_regs);
 
 #endif /* S32CC_CLK_UTILS_H */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index c40f955..f12a4d6 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -302,7 +302,7 @@
 
 	/*
 	 * Highest power level which takes part in a power management
-	 * operation.
+	 * operation. May be lower while the core is in suspend state.
 	 */
 	unsigned int target_pwrlvl;
 
diff --git a/include/lib/psci/psci_lib.h b/include/lib/psci/psci_lib.h
index c50f8cb..9950a6e 100644
--- a/include/lib/psci/psci_lib.h
+++ b/include/lib/psci/psci_lib.h
@@ -89,10 +89,10 @@
 void psci_register_spd_pm_hook(const spd_pm_ops_t *pm);
 void psci_prepare_next_non_secure_ctx(
 			  entry_point_info_t *next_image_info);
-int psci_stop_other_cores(unsigned int wait_ms,
+int psci_stop_other_cores(unsigned int this_cpu_idx, unsigned int wait_ms,
 			  void (*stop_func)(u_register_t mpidr));
-bool psci_is_last_on_cpu_safe(void);
-bool psci_are_all_cpus_on_safe(void);
+bool psci_is_last_on_cpu_safe(unsigned int this_core);
+bool psci_are_all_cpus_on_safe(unsigned int this_core);
 void psci_pwrdown_cpu(unsigned int power_level);
 void psci_do_manage_extensions(void);
 
diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
index 7b66a5e..bcf9fc9 100644
--- a/include/lib/transfer_list.h
+++ b/include/lib/transfer_list.h
@@ -56,6 +56,7 @@
 	TL_TAG_HOB_BLOCK = 2,
 	TL_TAG_HOB_LIST = 3,
 	TL_TAG_ACPI_TABLE_AGGREGATE = 4,
+	TL_TAG_TPM_EVLOG = 5,
 	TL_TAG_OPTEE_PAGABLE_PART = 0x100,
 	TL_TAG_DT_SPMC_MANIFEST = 0x101,
 	TL_TAG_EXEC_EP_INFO64 = 0x102,
diff --git a/include/plat/arm/board/common/rotpk/rotpk_def.h b/include/plat/arm/board/common/rotpk/rotpk_def.h
index 685c21a..9ad9e4e 100644
--- a/include/plat/arm/board/common/rotpk/rotpk_def.h
+++ b/include/plat/arm/board/common/rotpk/rotpk_def.h
@@ -13,12 +13,9 @@
  */
 
 /*
- * Root of trust key lengths
+ * Length of the header for a hashed DER ROTPK.
  */
-#ifndef ARM_ROTPK_HEADER_LEN
-#define ARM_ROTPK_HEADER_LEN		19
-#endif
-#ifndef ARM_ROTPK_HASH_LEN
-#define ARM_ROTPK_HASH_LEN		32
+#ifndef ARM_ROTPK_HASH_DER_HEADER_LEN
+#define ARM_ROTPK_HASH_DER_HEADER_LEN		19
 #endif
 #endif /* ROTPK_DEF_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 118b537..b43f131 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -299,6 +299,16 @@
 #if (MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT)
 void bl2_plat_mboot_init(void);
 void bl2_plat_mboot_finish(void);
+#if TRANSFER_LIST
+int plat_handoff_mboot(const void *data, uint32_t data_size, void *tl_base);
+#else
+static inline int
+plat_handoff_mboot(__unused const void *data, __unused uint32_t data_size,
+	      __unused void *tl_base)
+{
+	return -1;
+}
+#endif
 #else
 static inline void bl2_plat_mboot_init(void)
 {
diff --git a/include/plat/nuvoton/common/npcm845x_arm_def.h b/include/plat/nuvoton/common/npcm845x_arm_def.h
index df3ad24..9e921b8 100644
--- a/include/plat/nuvoton/common/npcm845x_arm_def.h
+++ b/include/plat/nuvoton/common/npcm845x_arm_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
  *
  * Copyright (C) 2017-2023 Nuvoton Ltd.
  *
@@ -30,10 +30,9 @@
  *****************************************************************************/
 
 /*
- * Root of trust key hash lengths
+ * Length of the header for a hashed DER ROTPK.
  */
-#define ARM_ROTPK_HEADER_LEN		19
-#define ARM_ROTPK_HASH_LEN		32
+#define ARM_ROTPK_HASH_DER_HEADER_LEN		19
 
 /* Special value used to verify platform parameters from BL2 to BL31 */
 #define ARM_BL31_PLAT_PARAM_VAL		ULL(0x0f1e2d3c4b5a6978)
diff --git a/include/services/arm_arch_svc.h b/include/services/arm_arch_svc.h
index 645b388..c2b1f41 100644
--- a/include/services/arm_arch_svc.h
+++ b/include/services/arm_arch_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,8 +13,310 @@
 #define SMCCC_ARCH_WORKAROUND_1		U(0x80008000)
 #define SMCCC_ARCH_WORKAROUND_2		U(0x80007FFF)
 #define SMCCC_ARCH_WORKAROUND_3		U(0x80003FFF)
+#define SMCCC_ARCH_FEATURE_AVAILABILITY		U(0x80000003)
 
 #define SMCCC_GET_SOC_VERSION		U(0)
 #define SMCCC_GET_SOC_REVISION		U(1)
 
+#ifndef __ASSEMBLER__
+#if ARCH_FEATURE_AVAILABILITY
+#include <lib/cassert.h>
+
+#if ENABLE_FEAT_FGT2
+#define SCR_FEAT_FGT2 SCR_FGTEN2_BIT
+#else
+#define SCR_FEAT_FGT2 (0)
+#endif
+
+#if ENABLE_FEAT_FPMR
+#define SCR_FEAT_FPMR SCR_EnFPM_BIT
+#else
+#define SCR_FEAT_FPMR
+#endif
+
+#if ENABLE_FEAT_D128
+#define SCR_FEAT_D128 SCR_D128En_BIT
+#else
+#define SCR_FEAT_D128 (0)
+#endif
+
+#if ENABLE_FEAT_S1PIE
+#define SCR_FEAT_S1PIE SCR_PIEN_BIT
+#else
+#define SCR_FEAT_S1PIE (0)
+#endif
+
+#if ENABLE_FEAT_SCTLR2
+#define SCR_FEAT_SCTLR2 SCR_SCTLR2En_BIT
+#else
+#define SCR_FEAT_SCTLR2 (0)
+#endif
+
+#if ENABLE_FEAT_TCR2
+#define SCR_FEAT_TCR2 SCR_TCR2EN_BIT
+#else
+#define SCR_FEAT_TCR2 (0)
+#endif
+
+#if ENABLE_FEAT_THE
+#define SCR_FEAT_THE SCR_RCWMASKEn_BIT
+#else
+#define SCR_FEAT_THE (0)
+#endif
+
+#if ENABLE_SME_FOR_NS
+#define SCR_FEAT_SME SCR_ENTP2_BIT
+#else
+#define SCR_FEAT_SME (0)
+#endif
+
+#if ENABLE_FEAT_GCS
+#define SCR_FEAT_GCS SCR_GCSEn_BIT
+#else
+#define SCR_FEAT_GCS (0)
+#endif
+
+#if ENABLE_FEAT_HCX
+#define SCR_FEAT_HCX SCR_HXEn_BIT
+#else
+#define SCR_FEAT_HCX (0)
+#endif
+
+#if ENABLE_FEAT_LS64_ACCDATA
+#define SCR_FEAT_LS64_ACCDATA (SCR_ADEn_BIT | SCR_EnAS0_BIT)
+#else
+#define SCR_FEAT_LS64_ACCDATA (0)
+#endif
+
+#if ENABLE_FEAT_AMUv1p1
+#define SCR_FEAT_AMUv1p1 SCR_AMVOFFEN_BIT
+#else
+#define SCR_FEAT_AMUv1p1 (0)
+#endif
+
+#if ENABLE_FEAT_ECV
+#define SCR_FEAT_ECV SCR_ECVEN_BIT
+#else
+#define SCR_FEAT_ECV (0)
+#endif
+
+#if ENABLE_FEAT_FGT
+#define SCR_FEAT_FGT SCR_FGTEN_BIT
+#else
+#define SCR_FEAT_FGT (0)
+#endif
+
+#if ENABLE_FEAT_MTE2
+#define SCR_FEAT_MTE2 SCR_ATA_BIT
+#else
+#define SCR_FEAT_MTE2 (0)
+#endif
+
+#if ENABLE_FEAT_CSV2_2
+#define SCR_FEAT_CSV2_2 SCR_EnSCXT_BIT
+#else
+#define SCR_FEAT_CSV2_2 (0)
+#endif
+
+#if ENABLE_FEAT_RAS
+#define SCR_FEAT_RAS SCR_TERR_BIT
+#else
+#define SCR_FEAT_RAS (0)
+#endif
+
+#ifndef SCR_PLAT_FEATS
+#define SCR_PLAT_FEATS (0)
+#endif
+#ifndef SCR_PLAT_FLIPPED
+#define SCR_PLAT_FLIPPED (0)
+#endif
+#ifndef SCR_PLAT_IGNORED
+#define SCR_PLAT_IGNORED (0)
+#endif
+
+#ifndef CPTR_PLAT_FEATS
+#define CPTR_PLAT_FEATS (0)
+#endif
+#ifndef CPTR_PLAT_FLIPPED
+#define CPTR_PLAT_FLIPPED (0)
+#endif
+
+#ifndef MDCR_PLAT_FEATS
+#define MDCR_PLAT_FEATS (0)
+#endif
+#ifndef MDCR_PLAT_FLIPPED
+#define MDCR_PLAT_FLIPPED (0)
+#endif
+#ifndef MDCR_PLAT_IGNORED
+#define MDCR_PLAT_IGNORED (0)
+#endif
+/*
+ * XYZ_EL3_FEATS - list all bits that are relevant for feature enablement. It's
+ * a constant list based on what features are expected. This relies on the fact
+ * that if the feature is in any way disabled, then the relevant bit will not be
+ * written by context management.
+ *
+ * XYZ_EL3_FLIPPED - bits with an active 0, rather than the usual active 1. The
+ * spec always uses active 1 to mean that the feature will not trap.
+ *
+ * XYZ_EL3_IGNORED - list of all bits that are not relevant for feature
+ * enablement and should not be reported to lower ELs
+ */
+#define SCR_EL3_FEATS (								\
+	SCR_FEAT_FGT2		|						\
+	SCR_FEAT_FPMR		|						\
+	SCR_FEAT_D128		|						\
+	SCR_FEAT_S1PIE		|						\
+	SCR_FEAT_SCTLR2		|						\
+	SCR_FEAT_TCR2		|						\
+	SCR_FEAT_THE		|						\
+	SCR_FEAT_SME		|						\
+	SCR_FEAT_GCS		|						\
+	SCR_FEAT_HCX		|						\
+	SCR_FEAT_LS64_ACCDATA	|						\
+	SCR_FEAT_AMUv1p1	|						\
+	SCR_FEAT_ECV		|						\
+	SCR_FEAT_FGT		|						\
+	SCR_FEAT_MTE2		|						\
+	SCR_FEAT_CSV2_2		|						\
+	SCR_APK_BIT		| /* FEAT_Pauth */				\
+	SCR_FEAT_RAS		|						\
+	SCR_PLAT_FEATS)
+#define SCR_EL3_FLIPPED (							\
+	SCR_FEAT_RAS		|						\
+	SCR_PLAT_FLIPPED)
+#define SCR_EL3_IGNORED (							\
+	SCR_API_BIT		|						\
+	SCR_RW_BIT		|						\
+	SCR_SIF_BIT		|						\
+	SCR_HCE_BIT		|						\
+	SCR_FIQ_BIT		|						\
+	SCR_IRQ_BIT		|						\
+	SCR_NS_BIT		|						\
+	SCR_RES1_BITS		|						\
+	SCR_PLAT_IGNORED)
+CASSERT((SCR_EL3_FEATS & SCR_EL3_IGNORED) == 0, scr_feat_is_ignored);
+CASSERT((SCR_EL3_FLIPPED & SCR_EL3_FEATS) == SCR_EL3_FLIPPED, scr_flipped_not_a_feat);
+
+#if ENABLE_SYS_REG_TRACE_FOR_NS
+#define CPTR_SYS_REG_TRACE (TCPAC_BIT | TTA_BIT)
+#else
+#define CPTR_SYS_REG_TRACE (0)
+#endif
+
+#if ENABLE_FEAT_AMU
+#define CPTR_FEAT_AMU TAM_BIT
+#else
+#define CPTR_FEAT_AMU (0)
+#endif
+
+#if ENABLE_SME_FOR_NS
+#define CPTR_FEAT_SME ESM_BIT
+#else
+#define CPTR_FEAT_SME (0)
+#endif
+
+#if ENABLE_SVE_FOR_NS
+#define CPTR_FEAT_SVE CPTR_EZ_BIT
+#else
+#define CPTR_FEAT_SVE (0)
+#endif
+
+#define CPTR_EL3_FEATS (							\
+	CPTR_SYS_REG_TRACE	|						\
+	CPTR_FEAT_AMU		|						\
+	CPTR_FEAT_SME		|						\
+	TFP_BIT			|						\
+	CPTR_FEAT_SVE		|						\
+	CPTR_PLAT_FEATS)
+#define CPTR_EL3_FLIPPED (							\
+	CPTR_SYS_REG_TRACE	|						\
+	CPTR_FEAT_AMU		|						\
+	TFP_BIT			|						\
+	CPTR_PLAT_FLIPPED)
+CASSERT((CPTR_EL3_FLIPPED & CPTR_EL3_FEATS) == CPTR_EL3_FLIPPED, cptr_flipped_not_a_feat);
+
+/*
+ * Some features enables are expressed with more than 1 bit in order to cater
+ * for multi world enablement. In those cases (BRB, TRB, SPE) only the last bit
+ * is used and reported. This (ab)uses the convenient fact that the last bit
+ * always means "enabled for this world" when context switched correctly.
+ * The per-world values have been adjusted such that this is always true.
+ */
+#if ENABLE_BRBE_FOR_NS
+#define MDCR_FEAT_BRBE MDCR_SBRBE(1UL)
+#else
+#define MDCR_FEAT_BRBE (0)
+#endif
+
+#if ENABLE_FEAT_FGT
+#define MDCR_FEAT_FGT MDCR_TDCC_BIT
+#else
+#define MDCR_FEAT_FGT (0)
+#endif
+
+#if ENABLE_TRBE_FOR_NS
+#define MDCR_FEAT_TRBE MDCR_NSTB(1UL)
+#else
+#define MDCR_FEAT_TRBE (0)
+#endif
+
+#if ENABLE_TRF_FOR_NS
+#define MDCR_FEAT_TRF MDCR_TTRF_BIT
+#else
+#define MDCR_FEAT_TRF (0)
+#endif
+
+#if ENABLE_SPE_FOR_NS
+#define MDCR_FEAT_SPE MDCR_NSPB(1UL)
+#else
+#define MDCR_FEAT_SPE (0)
+#endif
+
+#define MDCR_EL3_FEATS (							\
+	MDCR_FEAT_BRBE		|						\
+	MDCR_FEAT_FGT		|						\
+	MDCR_FEAT_TRBE		|						\
+	MDCR_FEAT_TRF		|						\
+	MDCR_FEAT_SPE		|						\
+	MDCR_TDOSA_BIT		|						\
+	MDCR_TDA_BIT		|						\
+	MDCR_TPM_BIT		| /* FEAT_PMUv3 */				\
+	MDCR_PLAT_FEATS)
+#define MDCR_EL3_FLIPPED (							\
+	MDCR_FEAT_FGT		|						\
+	MDCR_FEAT_TRF		|						\
+	MDCR_TDOSA_BIT		|						\
+	MDCR_TDA_BIT		|						\
+	MDCR_TPM_BIT		|						\
+	MDCR_PLAT_FLIPPED)
+#define MDCR_EL3_IGNORED (							\
+	MDCR_EBWE_BIT		|						\
+	MDCR_EnPMSN_BIT		|						\
+	MDCR_SBRBE(2UL)		|						\
+	MDCR_MTPME_BIT		|						\
+	MDCR_NSTBE_BIT		|						\
+	MDCR_NSTB(2UL)		|						\
+	MDCR_SDD_BIT		|						\
+	MDCR_SPD32(3UL)		|						\
+	MDCR_NSPB(2UL)		|						\
+	MDCR_NSPBE_BIT		|						\
+	MDCR_PLAT_IGNORED)
+CASSERT((MDCR_EL3_FEATS & MDCR_EL3_IGNORED) == 0, mdcr_feat_is_ignored);
+CASSERT((MDCR_EL3_FLIPPED & MDCR_EL3_FEATS) == MDCR_EL3_FLIPPED, mdcr_flipped_not_a_feat);
+
+#define MPAM3_EL3_FEATS		(MPAM3_EL3_TRAPLOWER_BIT)
+#define MPAM3_EL3_FLIPPED	(MPAM3_EL3_TRAPLOWER_BIT)
+#define MPAM3_EL3_IGNORED	(MPAM3_EL3_MPAMEN_BIT)
+CASSERT((MPAM3_EL3_FEATS & MPAM3_EL3_IGNORED) == 0, mpam3_feat_is_ignored);
+CASSERT((MPAM3_EL3_FLIPPED & MPAM3_EL3_FEATS) == MPAM3_EL3_FLIPPED, mpam3_flipped_not_a_feat);
+
+/* The hex representations of these registers' S3 encoding */
+#define SCR_EL3_OPCODE  			U(0x1E1100)
+#define CPTR_EL3_OPCODE 			U(0x1E1140)
+#define MDCR_EL3_OPCODE 			U(0x1E1320)
+#define MPAM3_EL3_OPCODE 			U(0x1EA500)
+
+#endif /* ARCH_FEATURE_AVAILABILITY */
+#endif /* __ASSEMBLER__ */
 #endif /* ARM_ARCH_SVC_H */
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
index 01dbea9..f5a9a2d 100644
--- a/include/services/ffa_svc.h
+++ b/include/services/ffa_svc.h
@@ -173,8 +173,8 @@
 #define FFA_SPM_ID_GET		FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
 #define FFA_NORMAL_WORLD_RESUME	FFA_FID(SMC_32, FFA_FNUM_NORMAL_WORLD_RESUME)
 #define FFA_EL3_INTR_HANDLE	FFA_FID(SMC_32, FFA_FNUM_EL3_INTR_HANDLE)
-#define FFA_MEM_PERM_GET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET)
-#define FFA_MEM_PERM_SET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET)
+#define FFA_MEM_PERM_GET_SMC32	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET)
+#define FFA_MEM_PERM_SET_SMC32	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET)
 #define FFA_CONSOLE_LOG_SMC32 FFA_FID(SMC_32, FFA_FNUM_CONSOLE_LOG)
 
 /* FFA SMC64 FIDs */
@@ -201,6 +201,8 @@
 	FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_REQ2)
 #define FFA_MSG_SEND_DIRECT_RESP2_SMC64	\
 	FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_RESP2)
+#define FFA_MEM_PERM_GET_SMC64	FFA_FID(SMC_64, FFA_FNUM_MEM_PERM_GET)
+#define FFA_MEM_PERM_SET_SMC64	FFA_FID(SMC_64, FFA_FNUM_MEM_PERM_SET)
 
 /*
  * FF-A partition properties values.
@@ -208,6 +210,8 @@
 #define FFA_PARTITION_DIRECT_REQ_RECV	U(1 << 0)
 #define FFA_PARTITION_DIRECT_REQ_SEND	U(1 << 1)
 #define FFA_PARTITION_INDIRECT_MSG	U(1 << 2)
+#define FFA_PARTITION_DIRECT_REQ2_RECV	U(1 << 9)
+#define FFA_PARTITION_DIRECT_REQ2_SEND	U(1 << 10)
 
 /*
  * Reserve a special value for traffic targeted to the Hypervisor or SPM.
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index ca5e047..9b97685 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -49,7 +49,6 @@
 per_world_context_t per_world_context[CPU_DATA_CONTEXT_NUM];
 static bool has_secure_perworld_init;
 
-static void manage_extensions_common(cpu_context_t *ctx);
 static void manage_extensions_nonsecure(cpu_context_t *ctx);
 static void manage_extensions_secure(cpu_context_t *ctx);
 static void manage_extensions_secure_per_world(void);
@@ -236,8 +235,9 @@
 	 * SCR_EL3.APK: Set to one to not trap any PAuth key values at ELs other
 	 *  than EL3
 	 */
-	scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
-
+	if (is_armv8_3_pauth_present()) {
+		scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+	}
 #endif /* CTX_INCLUDE_PAUTH_REGS */
 
 #if HANDLE_EA_EL3_FIRST_NS
@@ -251,7 +251,6 @@
 	 * and RAS ERX registers from EL1 and EL2(from any security state)
 	 * are trapped to EL3.
 	 * Set here to trap only for NS EL1/EL2
-	 *
 	 */
 	scr_el3 |= SCR_TERR_BIT;
 #endif
@@ -447,9 +446,9 @@
 	 * If FEAT_RNG_TRAP is enabled, all reads of the RNDR and RNDRRS
 	 * registers are trapped to EL3.
 	 */
-#if ENABLE_FEAT_RNG_TRAP
-	scr_el3 |= SCR_TRNDR_BIT;
-#endif
+	if (is_feat_rng_trap_supported()) {
+		scr_el3 |= SCR_TRNDR_BIT;
+	}
 
 #if FAULT_INJECTION_SUPPORT
 	/* Enable fault injection from lower ELs */
@@ -466,7 +465,9 @@
 	 * SCR_EL3.APK: Set to one to not trap any PAuth key values at ELs other
 	 *  than EL3
 	 */
-	scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+	if (is_armv8_3_pauth_present()) {
+		scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+	}
 #endif /* CTX_INCLUDE_PAUTH_REGS */
 
 	/*
@@ -567,11 +568,12 @@
 			& ~(MDCR_TDA_BIT | MDCR_TDOSA_BIT)) ;
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3);
 
-	/*
-	 * Configure MDCR_EL3 register as applicable for each world
-	 * (NS/Secure/Realm) context.
-	 */
-	manage_extensions_common(ctx);
+#if IMAGE_BL31
+	/* Enable FEAT_TRF for Non-Secure and prohibit for Secure state. */
+	if (is_feat_trf_supported()) {
+		trf_enable(ctx);
+	}
+#endif /* IMAGE_BL31 */
 
 	/*
 	 * Store the X0-X7 value from the entrypoint into the context
@@ -781,41 +783,6 @@
 }
 
 /*******************************************************************************
- * Enable architecture extensions on first entry to Non-secure world only
- * and disable for secure world.
- *
- * NOTE: Arch features which have been provided with the capability of getting
- * enabled only for non-secure world and being disabled for secure world are
- * grouped here, as the MDCR_EL3 context value remains same across the worlds.
- ******************************************************************************/
-static void manage_extensions_common(cpu_context_t *ctx)
-{
-#if IMAGE_BL31
-	if (is_feat_spe_supported()) {
-		/*
-		 * Enable FEAT_SPE for Non-Secure and prohibit for Secure state.
-		 */
-		spe_enable(ctx);
-	}
-
-	if (is_feat_trbe_supported()) {
-		/*
-		 * Enable FEAT_TRBE for Non-Secure and prohibit for Secure and
-		 * Realm state.
-		 */
-		trbe_enable(ctx);
-	}
-
-	if (is_feat_trf_supported()) {
-		/*
-		 * Enable FEAT_TRF for Non-Secure and prohibit for Secure state.
-		 */
-		trf_enable(ctx);
-	}
-#endif /* IMAGE_BL31 */
-}
-
-/*******************************************************************************
  * Enable architecture extensions on first entry to Non-secure world.
  ******************************************************************************/
 static void manage_extensions_nonsecure(cpu_context_t *ctx)
@@ -837,6 +804,21 @@
 		debugv8p9_extended_bp_wp_enable(ctx);
 	}
 
+	/*
+	 * SPE, TRBE, and BRBE have multi-field enables that affect which world
+	 * they apply to. Despite this, it is useful to ignore these for
+	 * simplicity in determining the feature's per world enablement status.
+	 * This is only possible when context is written per-world. Relied on
+	 * by SMCCC_ARCH_FEATURE_AVAILABILITY
+	 */
+	if (is_feat_spe_supported()) {
+		spe_enable(ctx);
+	}
+
+	if (is_feat_trbe_supported()) {
+		trbe_enable(ctx);
+	}
+
 	if (is_feat_brbe_supported()) {
 		brbe_enable(ctx);
 	}
@@ -901,6 +883,10 @@
 		sme_init_el2_unused();
 	}
 
+	if (is_feat_mops_supported()) {
+		write_hcrx_el2(read_hcrx_el2() | HCRX_EL2_MSCEn_BIT);
+	}
+
 #if ENABLE_PAUTH
 	enable_pauth_el2();
 #endif /* ENABLE_PAUTH */
@@ -930,6 +916,20 @@
 			sme_disable(ctx);
 		}
 	}
+
+	/*
+	 * SPE and TRBE cannot be fully disabled from EL3 registers alone, only
+	 * sysreg access can. In case the EL1 controls leave them active on
+	 * context switch, we want the owning security state to be NS so Secure
+	 * can't be DOSed.
+	 */
+	if (is_feat_spe_supported()) {
+		spe_disable(ctx);
+	}
+
+	if (is_feat_trbe_supported()) {
+		trbe_disable(ctx);
+	}
 #endif /* IMAGE_BL31 */
 }
 
diff --git a/lib/extensions/brbe/brbe.c b/lib/extensions/brbe/brbe.c
index fef6647..f951654 100644
--- a/lib/extensions/brbe/brbe.c
+++ b/lib/extensions/brbe/brbe.c
@@ -22,7 +22,7 @@
 	 * MDCR_EL3.{E3BREW, E3BREC} = 0b00
 	 * Branch recording at EL3 is disabled
 	 */
-	mdcr_el3_val &= ~((MDCR_SBRBE_MASK << MDCR_SBRBE_SHIFT) | MDCR_E3BREW | MDCR_E3BREC);
-	mdcr_el3_val |= (0x1UL << MDCR_SBRBE_SHIFT);
+	mdcr_el3_val &= ~((MDCR_SBRBE(MDCR_SBRBE_ALL)) | MDCR_E3BREW_BIT | MDCR_E3BREC_BIT);
+	mdcr_el3_val |= (MDCR_SBRBE(MDCR_SBRBE_NS));
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
 }
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
index a8d42ab..d7df267 100644
--- a/lib/extensions/spe/spe.c
+++ b/lib/extensions/spe/spe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -42,18 +42,14 @@
 	u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3);
 
 	/*
-	 * MDCR_EL3.NSPB: Clear these bits to disable SPE feature, as it was enabled
-	 * for Non-secure state only. After clearing these bits Secure state owns
-	 * the Profiling Buffer and accesses to Statistical Profiling and Profiling
-	 * Buffer control registers at EL2 and EL1 generate Trap exceptions to EL3
-	 *
-	 * MDCR_EL3.NSPBE: Don't care as it was cleared during spe_enable and setting
-	 * this to 1 does not make sense as NSPBE{1} and NSPB{0b0x} is RESERVED.
+	 * MDCR_EL3.{NSPB,NSPBE} = 0b00, 0b0
+	 *  Disable access of profiling buffer control registers from lower ELs
+	 *  in any security state. Secure state owns the buffer.
 	 *
 	 * MDCR_EL3.EnPMSN (ARM v8.7): Clear the bit to trap access of PMSNEVFR_EL1
 	 * from EL2/EL1 to EL3.
 	 */
-	mdcr_el3_val &= ~(MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT);
+	mdcr_el3_val &= ~(MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_NSPBE_BIT | MDCR_EnPMSN_BIT);
 	write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val);
 }
 
diff --git a/lib/extensions/trbe/trbe.c b/lib/extensions/trbe/trbe.c
index 8775e40..24d88ae 100644
--- a/lib/extensions/trbe/trbe.c
+++ b/lib/extensions/trbe/trbe.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
  */
@@ -35,13 +35,9 @@
 	u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3);
 
 	/*
-	 * MDCR_EL3.NSTBE = 0b0
-	 *  Trace Buffer owning Security state is secure state. If FEAT_RME
-	 *  is not implemented, this field is RES0.
-	 *
-	 * MDCR_EL3.NSTB = 0b00
-	 *  Clear these bits to disable access of trace buffer control registers
-	 *  from lower ELs in any security state.
+	 * MDCR_EL3.{NSTBE,NSTB} = 0b0, 0b00
+	 *  Disable access of trace buffer control registers from lower ELs in
+	 *  any security state. Secure state owns the buffer.
 	 */
 	mdcr_el3_val &= ~(MDCR_NSTB(MDCR_NSTB_EL1));
 	mdcr_el3_val &= ~(MDCR_NSTBE_BIT);
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 5418666..93d71b8 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -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
  */
@@ -16,6 +16,8 @@
 #include <drivers/delay_timer.h>
 #include <lib/el3_runtime/context_mgmt.h>
 #include <lib/extensions/spe.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
 #include <lib/utils.h>
 #include <plat/common/platform.h>
 
@@ -170,9 +172,9 @@
  * Returns 1 (true) if the current CPU is the last ON CPU or 0 (false)
  * otherwise.
  ******************************************************************************/
-static bool psci_is_last_cpu_to_idle_at_pwrlvl(unsigned int end_pwrlvl)
+static bool psci_is_last_cpu_to_idle_at_pwrlvl(unsigned int my_idx, unsigned int end_pwrlvl)
 {
-	unsigned int my_idx, lvl;
+	unsigned int lvl;
 	unsigned int parent_idx = 0;
 	unsigned int cpu_start_idx, ncpus, cpu_idx;
 	plat_local_state_t local_state;
@@ -181,7 +183,6 @@
 		return true;
 	}
 
-	my_idx = plat_my_core_pos();
 	parent_idx = psci_cpu_pd_nodes[my_idx].parent_node;
 	for (lvl = PSCI_CPU_PWR_LVL + U(1); lvl < end_pwrlvl; lvl++) {
 		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
@@ -212,11 +213,9 @@
  * turned OFF and the current CPU is the last running CPU in the system.
  * Returns true, if the current CPU is the last ON CPU or false otherwise.
  ******************************************************************************/
-bool psci_is_last_on_cpu(void)
+bool psci_is_last_on_cpu(unsigned int my_idx)
 {
-	unsigned int cpu_idx, my_idx = plat_my_core_pos();
-
-	for (cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) {
+	for (unsigned int cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) {
 		if (cpu_idx == my_idx) {
 			assert(psci_get_aff_info_state() == AFF_STATE_ON);
 			continue;
@@ -260,13 +259,9 @@
 
 	/*
 	 * Assume that this cpu was suspended and retrieve its target power
-	 * level. If it is invalid then it could only have been turned off
-	 * earlier. PLAT_MAX_PWR_LVL will be the highest power level a
-	 * cpu can be turned off to.
+	 * level. If it wasn't, the cpu is off so this will be PLAT_MAX_PWR_LVL.
 	 */
 	pwrlvl = psci_get_suspend_pwrlvl();
-	if (pwrlvl == PSCI_INVALID_PWR_LVL)
-		pwrlvl = PLAT_MAX_PWR_LVL;
 	assert(pwrlvl < PSCI_INVALID_PWR_LVL);
 	return pwrlvl;
 }
@@ -428,14 +423,14 @@
  * function will be called after a cpu is powered on to find the local state
  * each power domain has emerged from.
  *****************************************************************************/
-void psci_get_target_local_pwr_states(unsigned int end_pwrlvl,
+void psci_get_target_local_pwr_states(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				      psci_power_state_t *target_state)
 {
 	unsigned int parent_idx, lvl;
 	plat_local_state_t *pd_state = target_state->pwr_domain_state;
 
 	pd_state[PSCI_CPU_PWR_LVL] = psci_get_cpu_local_state();
-	parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
 
 	/* Copy the local power state from node to state_info */
 	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
@@ -454,7 +449,7 @@
  * enter. This function will be called after coordination of requested power
  * states has been done for each power level.
  *****************************************************************************/
-void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
+void psci_set_target_local_pwr_states(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				      const psci_power_state_t *target_state)
 {
 	unsigned int parent_idx, lvl;
@@ -468,7 +463,7 @@
 	 */
 	psci_flush_cpu_data(psci_svc_cpu_data.local_state);
 
-	parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
 
 	/* Copy the local_state from state_info */
 	for (lvl = 1U; lvl <= end_pwrlvl; lvl++) {
@@ -500,9 +495,9 @@
  * affinity info state, target power state and requested power state for the
  * current CPU and all its ancestor power domains to RUN.
  *****************************************************************************/
-void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl)
+void psci_set_pwr_domains_to_run(unsigned int cpu_idx, unsigned int end_pwrlvl)
 {
-	unsigned int parent_idx, cpu_idx = plat_my_core_pos(), lvl;
+	unsigned int parent_idx, lvl;
 	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
 
 	/* Reset the local_state to RUN for the non cpu power domains. */
@@ -544,10 +539,10 @@
  * This function will only be invoked with data cache enabled and while
  * powering down a core.
  *****************************************************************************/
-void psci_do_state_coordination(unsigned int end_pwrlvl,
+void psci_do_state_coordination(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				psci_power_state_t *state_info)
 {
-	unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos();
+	unsigned int lvl, parent_idx;
 	unsigned int start_idx;
 	unsigned int ncpus;
 	plat_local_state_t target_state, *req_states;
@@ -620,11 +615,11 @@
  * This function will only be invoked with data cache enabled and while
  * powering down a core.
  *****************************************************************************/
-int psci_validate_state_coordination(unsigned int end_pwrlvl,
+int psci_validate_state_coordination(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				     psci_power_state_t *state_info)
 {
 	int rc = PSCI_E_SUCCESS;
-	unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos();
+	unsigned int lvl, parent_idx;
 	unsigned int start_idx;
 	unsigned int ncpus;
 	plat_local_state_t target_state, *req_states;
@@ -674,7 +669,7 @@
 	 * specified power level.
 	 */
 	lvl = state_info->last_at_pwrlvl;
-	if (!psci_is_last_cpu_to_idle_at_pwrlvl(lvl)) {
+	if (!psci_is_last_cpu_to_idle_at_pwrlvl(cpu_idx, lvl)) {
 		rc = PSCI_E_DENIED;
 	}
 
@@ -1004,7 +999,7 @@
 	 */
 	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
 
-	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
+	psci_get_target_local_pwr_states(cpu_idx, end_pwrlvl, &state_info);
 
 #if ENABLE_PSCI_STAT
 	plat_psci_stat_accounting_stop(&state_info);
@@ -1025,7 +1020,7 @@
 	if (psci_get_aff_info_state() == AFF_STATE_ON_PENDING)
 		psci_cpu_on_finish(cpu_idx, &state_info);
 	else
-		psci_cpu_suspend_finish(cpu_idx, &state_info);
+		psci_cpu_suspend_to_powerdown_finish(cpu_idx, &state_info);
 
 	/*
 	 * Generic management: Now we just need to retrieve the
@@ -1038,16 +1033,10 @@
 	 * Set the requested and target state of this CPU and all the higher
 	 * power domains which are ancestors of this CPU to run.
 	 */
-	psci_set_pwr_domains_to_run(end_pwrlvl);
+	psci_set_pwr_domains_to_run(cpu_idx, end_pwrlvl);
 
 #if ENABLE_PSCI_STAT
-	/*
-	 * Update PSCI stats.
-	 * Caches are off when writing stats data on the power down path.
-	 * Since caches are now enabled, it's necessary to do cache
-	 * maintenance before reading that same data.
-	 */
-	psci_stats_update_pwr_up(end_pwrlvl, &state_info);
+	psci_stats_update_pwr_up(cpu_idx, end_pwrlvl, &state_info);
 #endif
 
 	/*
@@ -1169,6 +1158,17 @@
  ******************************************************************************/
 void psci_pwrdown_cpu(unsigned int power_level)
 {
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+	/*
+	 * Flush cache line so that even if CPU power down happens
+	 * the timestamp update is reflected in memory.
+	 */
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_ENTER_CFLUSH,
+		PMF_CACHE_MAINT);
+#endif
+
 #if HW_ASSISTED_COHERENCY
 	/*
 	 * With hardware-assisted coherency, the CPU drivers only initiate the
@@ -1188,6 +1188,12 @@
 	 */
 	psci_do_pwrdown_cache_maintenance(power_level);
 #endif
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_EXIT_CFLUSH,
+		PMF_NO_CACHE_MAINT);
+#endif
 }
 
 /*******************************************************************************
@@ -1200,15 +1206,11 @@
  * The function returns 'PSCI_E_DENIED' if some cores failed to stop within the
  * given timeout.
  ******************************************************************************/
-int psci_stop_other_cores(unsigned int wait_ms,
+int psci_stop_other_cores(unsigned int this_cpu_idx, unsigned int wait_ms,
 				   void (*stop_func)(u_register_t mpidr))
 {
-	unsigned int idx, this_cpu_idx;
-
-	this_cpu_idx = plat_my_core_pos();
-
 	/* Invoke stop_func for each core */
-	for (idx = 0U; idx < psci_plat_core_count; idx++) {
+	for (unsigned int idx = 0U; idx < psci_plat_core_count; idx++) {
 		/* skip current CPU */
 		if (idx == this_cpu_idx) {
 			continue;
@@ -1222,11 +1224,11 @@
 
 	/* Need to wait for other cores to shutdown */
 	if (wait_ms != 0U) {
-		while ((wait_ms-- != 0U) && (!psci_is_last_on_cpu())) {
+		while ((wait_ms-- != 0U) && (!psci_is_last_on_cpu(this_cpu_idx))) {
 			mdelay(1U);
 		}
 
-		if (!psci_is_last_on_cpu()) {
+		if (!psci_is_last_on_cpu(this_cpu_idx)) {
 			WARN("Failed to stop all cores!\n");
 			psci_print_power_domain_map();
 			return PSCI_E_DENIED;
@@ -1244,16 +1246,15 @@
  * This API has following differences with psci_is_last_on_cpu
  *  1. PSCI states are locked
  ******************************************************************************/
-bool psci_is_last_on_cpu_safe(void)
+bool psci_is_last_on_cpu_safe(unsigned int this_core)
 {
-	unsigned int this_core = plat_my_core_pos();
 	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
 
 	psci_get_parent_pwr_domain_nodes(this_core, PLAT_MAX_PWR_LVL, parent_nodes);
 
 	psci_acquire_pwr_domain_locks(PLAT_MAX_PWR_LVL, parent_nodes);
 
-	if (!psci_is_last_on_cpu()) {
+	if (!psci_is_last_on_cpu(this_core)) {
 		psci_release_pwr_domain_locks(PLAT_MAX_PWR_LVL, parent_nodes);
 		return false;
 	}
@@ -1270,9 +1271,8 @@
  * This API has following differences with psci_are_all_cpus_on
  *  1. PSCI states are locked
  ******************************************************************************/
-bool psci_are_all_cpus_on_safe(void)
+bool psci_are_all_cpus_on_safe(unsigned int this_core)
 {
-	unsigned int this_core = plat_my_core_pos();
 	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
 
 	psci_get_parent_pwr_domain_nodes(this_core, PLAT_MAX_PWR_LVL, parent_nodes);
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index a015531..7ac0e02 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -59,8 +59,8 @@
 	entry_point_info_t ep;
 	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
 	plat_local_state_t cpu_pd_state;
-#if PSCI_OS_INIT_MODE
 	unsigned int cpu_idx = plat_my_core_pos();
+#if PSCI_OS_INIT_MODE
 	plat_local_state_t prev[PLAT_MAX_PWR_LVL];
 #endif
 
@@ -145,7 +145,7 @@
 		plat_psci_stat_accounting_stop(&state_info);
 
 		/* Update PSCI stats */
-		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
+		psci_stats_update_pwr_up(cpu_idx, PSCI_CPU_PWR_LVL, &state_info);
 #endif
 
 		return PSCI_E_SUCCESS;
@@ -167,7 +167,8 @@
 	 * might return if the power down was abandoned for any reason, e.g.
 	 * arrival of an interrupt
 	 */
-	rc = psci_cpu_suspend_start(&ep,
+	rc = psci_cpu_suspend_start(cpu_idx,
+				    &ep,
 				    target_pwrlvl,
 				    &state_info,
 				    is_power_down_state);
@@ -181,9 +182,10 @@
 	int rc;
 	psci_power_state_t state_info;
 	entry_point_info_t ep;
+	unsigned int cpu_idx = plat_my_core_pos();
 
 	/* Check if the current CPU is the last ON CPU in the system */
-	if (!psci_is_last_on_cpu())
+	if (!psci_is_last_on_cpu(cpu_idx))
 		return PSCI_E_DENIED;
 
 	/* Validate the entry point and get the entry_point_info */
@@ -212,7 +214,8 @@
 	 * might return if the power down was abandoned for any reason, e.g.
 	 * arrival of an interrupt
 	 */
-	rc = psci_cpu_suspend_start(&ep,
+	rc = psci_cpu_suspend_start(cpu_idx,
+				    &ep,
 				    PLAT_MAX_PWR_LVL,
 				    &state_info,
 				    PSTATE_TYPE_POWERDOWN);
@@ -399,9 +402,11 @@
 		return PSCI_E_SUCCESS;
 	}
 
+	unsigned int this_core = plat_my_core_pos();
+
 	if (mode == PLAT_COORD) {
 		/* Check if the current CPU is the last ON CPU in the system */
-		if (!psci_is_last_on_cpu_safe()) {
+		if (!psci_is_last_on_cpu_safe(this_core)) {
 			return PSCI_E_DENIED;
 		}
 	}
@@ -411,8 +416,8 @@
 		 * Check if all CPUs in the system are ON or if the current
 		 * CPU is the last ON CPU in the system.
 		 */
-		if (!(psci_are_all_cpus_on_safe() ||
-		      psci_is_last_on_cpu_safe())) {
+		if (!(psci_are_all_cpus_on_safe(this_core) ||
+		      psci_is_last_on_cpu_safe(this_core))) {
 			return PSCI_E_DENIED;
 		}
 	}
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
index f83753f..d40ee3f 100644
--- a/lib/psci/psci_off.c
+++ b/lib/psci/psci_off.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -102,38 +102,21 @@
 	 * it returns the negotiated state info for each power level upto
 	 * the end level specified.
 	 */
-	psci_do_state_coordination(end_pwrlvl, &state_info);
+	psci_do_state_coordination(idx, end_pwrlvl, &state_info);
 
 	/* Update the target state in the power domain nodes */
-	psci_set_target_local_pwr_states(end_pwrlvl, &state_info);
+	psci_set_target_local_pwr_states(idx, end_pwrlvl, &state_info);
 
 #if ENABLE_PSCI_STAT
 	/* Update the last cpu for each level till end_pwrlvl */
-	psci_stats_update_pwr_down(end_pwrlvl, &state_info);
+	psci_stats_update_pwr_down(idx, end_pwrlvl, &state_info);
 #endif
 
-#if ENABLE_RUNTIME_INSTRUMENTATION
-
-	/*
-	 * Flush cache line so that even if CPU power down happens
-	 * the timestamp update is reflected in memory.
-	 */
-	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
-		RT_INSTR_ENTER_CFLUSH,
-		PMF_CACHE_MAINT);
-#endif
-
 	/*
 	 * Arch. management. Initiate power down sequence.
 	 */
 	psci_pwrdown_cpu(psci_find_max_off_lvl(&state_info));
 
-#if ENABLE_RUNTIME_INSTRUMENTATION
-	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
-		RT_INSTR_EXIT_CFLUSH,
-		PMF_NO_CACHE_MAINT);
-#endif
-
 	/*
 	 * Plat. management: Perform platform specific actions to turn this
 	 * cpu off e.g. exit cpu coherency, program the power controller etc.
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index 2eb4a9b..6622755 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -295,19 +295,19 @@
 void psci_restore_req_local_pwr_states(unsigned int cpu_idx,
 				       plat_local_state_t *prev);
 #endif
-void psci_get_target_local_pwr_states(unsigned int end_pwrlvl,
+void psci_get_target_local_pwr_states(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				      psci_power_state_t *target_state);
-void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
+void psci_set_target_local_pwr_states(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				      const psci_power_state_t *target_state);
 int psci_validate_entry_point(entry_point_info_t *ep,
 			uintptr_t entrypoint, u_register_t context_id);
 void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx,
 				      unsigned int end_lvl,
 				      unsigned int *node_index);
-void psci_do_state_coordination(unsigned int end_pwrlvl,
+void psci_do_state_coordination(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				psci_power_state_t *state_info);
 #if PSCI_OS_INIT_MODE
-int psci_validate_state_coordination(unsigned int end_pwrlvl,
+int psci_validate_state_coordination(unsigned int cpu_idx, unsigned int end_pwrlvl,
 				     psci_power_state_t *state_info);
 #endif
 void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
@@ -318,9 +318,9 @@
 			      unsigned int is_power_down_state);
 unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info);
 unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info);
-void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl);
+void psci_set_pwr_domains_to_run(unsigned int cpu_idx, unsigned int end_pwrlvl);
 void psci_print_power_domain_map(void);
-bool psci_is_last_on_cpu(void);
+bool psci_is_last_on_cpu(unsigned int my_idx);
 int psci_spd_migrate_info(u_register_t *mpidr);
 
 /*
@@ -343,12 +343,13 @@
 int psci_do_cpu_off(unsigned int end_pwrlvl);
 
 /* Private exported functions from psci_suspend.c */
-int psci_cpu_suspend_start(const entry_point_info_t *ep,
+int psci_cpu_suspend_start(unsigned int idx,
+			   const entry_point_info_t *ep,
 			   unsigned int end_pwrlvl,
 			   psci_power_state_t *state_info,
 			   unsigned int is_power_down_state);
 
-void psci_cpu_suspend_finish(unsigned int cpu_idx, const psci_power_state_t *state_info);
+void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info);
 
 /* Private exported functions from psci_helpers.S */
 void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level);
@@ -360,9 +361,9 @@
 u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie);
 
 /* Private exported functions from psci_stat.c */
-void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
+void psci_stats_update_pwr_down(unsigned int cpu_idx, unsigned int end_pwrlvl,
 			const psci_power_state_t *state_info);
-void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
+void psci_stats_update_pwr_up(unsigned int cpu_idx, unsigned int end_pwrlvl,
 			const psci_power_state_t *state_info);
 u_register_t psci_stat_residency(u_register_t target_cpu,
 			unsigned int power_state);
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 6bf1ff4..a81ba4a 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -68,8 +68,8 @@
 		/* Set the Affinity Info for the cores as OFF */
 		svc_cpu_data->aff_info_state = AFF_STATE_OFF;
 
-		/* Invalidate the suspend level for the cpu */
-		svc_cpu_data->target_pwrlvl = PSCI_INVALID_PWR_LVL;
+		/* Default to the highest power level when the cpu is not suspending */
+		svc_cpu_data->target_pwrlvl = PLAT_MAX_PWR_LVL;
 
 		/* Set the power state to OFF state */
 		svc_cpu_data->local_state = PLAT_MAX_OFF_STATE;
@@ -202,6 +202,7 @@
 int __init psci_setup(const psci_lib_args_t *lib_args)
 {
 	const unsigned char *topology_tree;
+	unsigned int cpu_idx = plat_my_core_pos();
 
 	assert(VERIFY_PSCI_LIB_ARGS_V1(lib_args));
 
@@ -218,7 +219,7 @@
 	psci_update_pwrlvl_limits();
 
 	/* Populate the mpidr field of cpu node for this CPU */
-	psci_cpu_pd_nodes[plat_my_core_pos()].mpidr =
+	psci_cpu_pd_nodes[cpu_idx].mpidr =
 		read_mpidr() & MPIDR_AFFINITY_MASK;
 
 	psci_init_req_local_pwr_states();
@@ -227,7 +228,7 @@
 	 * Set the requested and target state of this CPU and all the higher
 	 * power domain levels for this CPU to run.
 	 */
-	psci_set_pwr_domains_to_run(PLAT_MAX_PWR_LVL);
+	psci_set_pwr_domains_to_run(cpu_idx, PLAT_MAX_PWR_LVL);
 
 	(void) plat_setup_psci_ops((uintptr_t)lib_args->mailbox_ep,
 				   &psci_plat_pm_ops);
diff --git a/lib/psci/psci_stat.c b/lib/psci/psci_stat.c
index bedb816..1225557 100644
--- a/lib/psci/psci_stat.c
+++ b/lib/psci/psci_stat.c
@@ -73,11 +73,10 @@
  * This function will only be invoked with data cache enabled and while
  * powering down a core.
  ******************************************************************************/
-void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
+void psci_stats_update_pwr_down(unsigned int cpu_idx, unsigned int end_pwrlvl,
 			const psci_power_state_t *state_info)
 {
 	unsigned int lvl, parent_idx;
-	unsigned int cpu_idx = plat_my_core_pos();
 
 	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
 	assert(state_info != NULL);
@@ -106,11 +105,10 @@
  * and NON-CPU power domains.
  * It is called with caches enabled and locks acquired(for NON-CPU domain)
  ******************************************************************************/
-void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
+void psci_stats_update_pwr_up(unsigned int cpu_idx, unsigned int end_pwrlvl,
 			const psci_power_state_t *state_info)
 {
 	unsigned int lvl, parent_idx;
-	unsigned int cpu_idx = plat_my_core_pos();
 	int stat_idx;
 	plat_local_state_t local_state;
 	u_register_t residency;
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index cb12b83..2aadbfd 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,42 +25,18 @@
  * This function does generic and platform specific operations after a wake-up
  * from standby/retention states at multiple power levels.
  ******************************************************************************/
-static void psci_suspend_to_standby_finisher(unsigned int cpu_idx,
-					     unsigned int end_pwrlvl)
+static void psci_cpu_suspend_to_standby_finish(unsigned int cpu_idx,
+					     unsigned int end_pwrlvl,
+					     psci_power_state_t *state_info)
 {
-	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
-	psci_power_state_t state_info;
-
-	/* Get the parent nodes */
-	psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
-
-	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
-
-	/*
-	 * Find out which retention states this CPU has exited from until the
-	 * 'end_pwrlvl'. The exit retention state could be deeper than the entry
-	 * state as a result of state coordination amongst other CPUs post wfi.
-	 */
-	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
-
-#if ENABLE_PSCI_STAT
-	plat_psci_stat_accounting_stop(&state_info);
-	psci_stats_update_pwr_up(end_pwrlvl, &state_info);
-#endif
-
 	/*
 	 * Plat. management: Allow the platform to do operations
 	 * on waking up from retention.
 	 */
-	psci_plat_pm_ops->pwr_domain_suspend_finish(&state_info);
-
-	/*
-	 * Set the requested and target state of this CPU and all the higher
-	 * power domain levels for this CPU to run.
-	 */
-	psci_set_pwr_domains_to_run(end_pwrlvl);
+	psci_plat_pm_ops->pwr_domain_suspend_finish(state_info);
 
-	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+	/* This loses its meaning when not suspending, reset so it's correct for OFF */
+	psci_set_suspend_pwrlvl(PLAT_MAX_PWR_LVL);
 }
 
 /*******************************************************************************
@@ -116,29 +92,12 @@
 	 */
 	cm_init_my_context(ep);
 
-#if ENABLE_RUNTIME_INSTRUMENTATION
-
-	/*
-	 * Flush cache line so that even if CPU power down happens
-	 * the timestamp update is reflected in memory.
-	 */
-	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
-		RT_INSTR_ENTER_CFLUSH,
-		PMF_CACHE_MAINT);
-#endif
-
 	/*
 	 * Arch. management. Initiate power down sequence.
 	 * TODO : Introduce a mechanism to query the cache level to flush
 	 * and the cpu-ops power down to perform from the platform.
 	 */
 	psci_pwrdown_cpu(max_off_lvl);
-
-#if ENABLE_RUNTIME_INSTRUMENTATION
-	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
-		RT_INSTR_EXIT_CFLUSH,
-		PMF_NO_CACHE_MAINT);
-#endif
 }
 
 /*******************************************************************************
@@ -159,14 +118,14 @@
  * the state transition has been done, no further error is expected and it is
  * not possible to undo any of the actions taken beyond that point.
  ******************************************************************************/
-int psci_cpu_suspend_start(const entry_point_info_t *ep,
+int psci_cpu_suspend_start(unsigned int idx,
+			   const entry_point_info_t *ep,
 			   unsigned int end_pwrlvl,
 			   psci_power_state_t *state_info,
 			   unsigned int is_power_down_state)
 {
 	int rc = PSCI_E_SUCCESS;
 	bool skip_wfi = false;
-	unsigned int idx = plat_my_core_pos();
 	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
 
 	/*
@@ -202,7 +161,7 @@
 		 * This function validates the requested state info for
 		 * OS-initiated mode.
 		 */
-		rc = psci_validate_state_coordination(end_pwrlvl, state_info);
+		rc = psci_validate_state_coordination(idx, end_pwrlvl, state_info);
 		if (rc != PSCI_E_SUCCESS) {
 			skip_wfi = true;
 			goto exit;
@@ -214,7 +173,7 @@
 		 * it returns the negotiated state info for each power level upto
 		 * the end level specified.
 		 */
-		psci_do_state_coordination(end_pwrlvl, state_info);
+		psci_do_state_coordination(idx, end_pwrlvl, state_info);
 #if PSCI_OS_INIT_MODE
 	}
 #endif
@@ -230,11 +189,11 @@
 #endif
 
 	/* Update the target state in the power domain nodes */
-	psci_set_target_local_pwr_states(end_pwrlvl, state_info);
+	psci_set_target_local_pwr_states(idx, end_pwrlvl, state_info);
 
 #if ENABLE_PSCI_STAT
 	/* Update the last cpu for each level till end_pwrlvl */
-	psci_stats_update_pwr_down(end_pwrlvl, state_info);
+	psci_stats_update_pwr_down(idx, end_pwrlvl, state_info);
 #endif
 
 	if (is_power_down_state != 0U)
@@ -304,11 +263,32 @@
 	    PMF_NO_CACHE_MAINT);
 #endif
 
+	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
+	/*
+	 * Find out which retention states this CPU has exited from until the
+	 * 'end_pwrlvl'. The exit retention state could be deeper than the entry
+	 * state as a result of state coordination amongst other CPUs post wfi.
+	 */
+	psci_get_target_local_pwr_states(idx, end_pwrlvl, state_info);
+
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_stop(state_info);
+	psci_stats_update_pwr_up(idx, end_pwrlvl, state_info);
+#endif
+
 	/*
 	 * After we wake up from context retaining suspend, call the
 	 * context retaining suspend finisher.
 	 */
+	psci_cpu_suspend_to_standby_finish(idx, end_pwrlvl, state_info);
+
+	/*
+	 * Set the requested and target state of this CPU and all the higher
+	 * power domain levels for this CPU to run.
+	 */
-	psci_suspend_to_standby_finisher(idx, end_pwrlvl);
+	psci_set_pwr_domains_to_run(idx, end_pwrlvl);
+
+	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
 
 	return rc;
 }
@@ -318,7 +298,7 @@
  * are called by the common finisher routine in psci_common.c. The `state_info`
  * is the psci_power_state from which this CPU has woken up from.
  ******************************************************************************/
-void psci_cpu_suspend_finish(unsigned int cpu_idx, const psci_power_state_t *state_info)
+void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info)
 {
 	unsigned int counter_freq;
 	unsigned int max_off_lvl;
@@ -363,8 +343,8 @@
 		psci_spd_pm->svc_suspend_finish(max_off_lvl);
 	}
 
-	/* Invalidate the suspend level for the cpu */
-	psci_set_suspend_pwrlvl(PSCI_INVALID_PWR_LVL);
+	/* This loses its meaning when not suspending, reset so it's correct for OFF */
+	psci_set_suspend_pwrlvl(PLAT_MAX_PWR_LVL);
 
 	PUBLISH_EVENT(psci_suspend_pwrdown_finish);
 }
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index a1db0b8..3c9e136 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -83,6 +83,7 @@
 
 # Enable the features which are mandatory from ARCH version 8.8 and upwards.
 ifeq "8.8" "$(word 1, $(sort 8.8 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+armv8-8-a-feats		:= ENABLE_FEAT_MOPS
 # 8.7 Compliant
 armv8-8-a-feats         += ${armv8-7-a-feats}
 FEAT_LIST               := ${armv8-8-a-feats}
@@ -213,6 +214,14 @@
 ENABLE_FEAT_HCX			?=	0
 
 #----
+# 8.8
+#----
+
+# Flag to enable FEAT_MOPS (Standardization of Memory operations)
+# when INIT_UNUSED_NS_EL2 = 1
+ENABLE_FEAT_MOPS		?=	0
+
+#----
 # 8.9
 #----
 
diff --git a/make_helpers/build_env.mk b/make_helpers/build_env.mk
deleted file mode 100644
index 13acaae..0000000
--- a/make_helpers/build_env.mk
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-# This file contains the logic to identify and include any relevant
-# build environment specific make include files.
-
-ifndef BUILD_ENV_MK
-    BUILD_ENV_MK        :=      $(lastword $(MAKEFILE_LIST))
-
-    # Block possible built-in command definitions that are not fully portable.
-    # This traps occurences that need replacing with our OS portable macros
-    COPY                :=      $$(error "Replace COPY with call to SHELL_COPY or SHELL_COPY_TREE.")
-    CP                  :=      $$(error "Replace CP with call to SHELL_COPY or SHELL_COPY_TREE.")
-    DEL                 :=      $$(error "Replace DEL with call to SHELL_DELETE.")
-    RD                  :=      $$(error "Replace RD with call to SHELL_REMOVE_DIR.")
-    RM                  :=      $$(error "Replace RM with call to SHELL_DELETE.")
-    RMDIR               :=      $$(error "Replace RMDIR with call to SHELL_REMOVE_DIR.")
-
-    ENV_FILE_TO_INCLUDE := unix.mk
-    ifdef OSTYPE
-        ifneq ($(findstring ${OSTYPE}, cygwin),)
-            ENV_FILE_TO_INCLUDE := cygwin.mk
-        else
-            ifneq ($(findstring ${OSTYPE}, MINGW32 mingw msys),)
-                ENV_FILE_TO_INCLUDE := msys.mk
-            endif
-        endif
-    else
-        ifdef MSYSTEM
-            # Although the MINGW MSYS shell sets OSTYPE as msys in its environment,
-            # it does not appear in the GNU make view of environment variables.
-            # We use MSYSTEM as an alternative, as that is seen by make
-            ifneq ($(findstring ${MSYSTEM}, MINGW32 mingw msys),)
-                OSTYPE ?= msys
-                ENV_FILE_TO_INCLUDE := msys.mk
-            endif
-        else
-            ifdef OS
-                ifneq ($(findstring ${OS}, Windows_NT),)
-                    ENV_FILE_TO_INCLUDE := windows.mk
-                endif
-            endif
-        endif
-    endif
-    include $(dir $(lastword $(MAKEFILE_LIST)))${ENV_FILE_TO_INCLUDE}
-    ENV_FILE_TO_INCLUDE :=
-
-    ifndef SHELL_COPY
-        $(error "SHELL_COPY not defined for build environment.")
-    endif
-    ifndef SHELL_COPY_TREE
-        $(error "SHELL_COPY_TREE not defined for build environment.")
-    endif
-    ifndef SHELL_DELETE_ALL
-        $(error "SHELL_DELETE_ALL not defined for build environment.")
-    endif
-    ifndef SHELL_DELETE
-        $(error "SHELL_DELETE not defined for build environment.")
-    endif
-    ifndef SHELL_REMOVE_DIR
-        $(error "SHELL_REMOVE_DIR not defined for build environment.")
-    endif
-
-endif
diff --git a/make_helpers/common.mk b/make_helpers/common.mk
index 848e4e9..a4b69c7 100644
--- a/make_helpers/common.mk
+++ b/make_helpers/common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -14,4 +14,6 @@
 
         s := @$(if $(or $(verbose),$(silent)),: )
         q := $(if $(verbose),,@)
+
+        .exe := $(if $(filter Windows_NT,$(OS)),.exe)
 endif
diff --git a/make_helpers/cygwin.mk b/make_helpers/cygwin.mk
deleted file mode 100644
index 04a963f..0000000
--- a/make_helpers/cygwin.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#
-
-# OS specific definitions for builds in a Cygwin environment.
-# Cygwin allows us to use unix style commands on a windows platform.
-
-ifndef CYGWIN_MK
-    CYGWIN_MK := $(lastword $(MAKEFILE_LIST))
-
-    include ${MAKE_HELPERS_DIRECTORY}unix.mk
-
-    # In cygwin executable files have the Windows .exe extension type.
-    BIN_EXT := .exe
-
-endif
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 8a0975b..4985c0c 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -210,6 +210,9 @@
 # Enable PSCI OS-initiated mode support
 PSCI_OS_INIT_MODE		:= 0
 
+# SMCCC_ARCH_FEATURE_AVAILABILITY support
+ARCH_FEATURE_AVAILABILITY	:= 0
+
 # By default, BL1 acts as the reset handler, not BL31
 RESET_TO_BL31			:= 0
 
diff --git a/make_helpers/msys.mk b/make_helpers/msys.mk
deleted file mode 100644
index 7e60d57..0000000
--- a/make_helpers/msys.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#
-
-# OS specific definitions for builds in a Mingw32 MSYS environment.
-# Mingw32 allows us to use some unix style commands on a windows platform.
-
-ifndef MSYS_MK
-    MSYS_MK := $(lastword $(MAKEFILE_LIST))
-
-    include ${MAKE_HELPERS_DIRECTORY}unix.mk
-
-    # In MSYS executable files have the Windows .exe extension type.
-    BIN_EXT := .exe
-
-endif
-
diff --git a/make_helpers/toolchain.mk b/make_helpers/toolchain.mk
index 2ab577c..3b9d984 100644
--- a/make_helpers/toolchain.mk
+++ b/make_helpers/toolchain.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -18,7 +18,6 @@
 ifndef toolchain-mk
         toolchain-mk := $(lastword $(MAKEFILE_LIST))
 
-        include $(dir $(toolchain-mk))build_env.mk
         include $(dir $(toolchain-mk))utilities.mk
 
         #
@@ -242,28 +241,28 @@
         #
 
         # Arm Compiler for Embedded
-        toolchain-guess-tool-arm-clang = $(shell $(1) --version 2>&1 <$(nul) | grep -o "Tool: armclang")
-        toolchain-guess-tool-arm-link = $(shell $(1) --help 2>&1 <$(nul) | grep -o "Tool: armlink")
-        toolchain-guess-tool-arm-fromelf = $(shell $(1) --help 2>&1 <$(nul) | grep -o "Tool: fromelf")
-        toolchain-guess-tool-arm-ar = $(shell $(1) --version 2>&1 <$(nul) | grep -o "Tool: armar")
+        toolchain-guess-tool-arm-clang = $(shell $(1) --version 2>&1 </dev/null | grep -o "Tool: armclang")
+        toolchain-guess-tool-arm-link = $(shell $(1) --help 2>&1 </dev/null | grep -o "Tool: armlink")
+        toolchain-guess-tool-arm-fromelf = $(shell $(1) --help 2>&1 </dev/null | grep -o "Tool: fromelf")
+        toolchain-guess-tool-arm-ar = $(shell $(1) --version 2>&1 </dev/null | grep -o "Tool: armar")
 
         # LLVM Project
-        toolchain-guess-tool-llvm-clang = $(shell $(1) -v 2>&1 <$(nul) | grep -o "clang version")
-        toolchain-guess-tool-llvm-lld = $(shell $(1) --help 2>&1 <$(nul) | grep -o "OVERVIEW: lld")
-        toolchain-guess-tool-llvm-objcopy = $(shell $(1) --help 2>&1 <$(nul) | grep -o "llvm-objcopy tool")
-        toolchain-guess-tool-llvm-objdump = $(shell $(1) --help 2>&1 <$(nul) | grep -o "llvm object file dumper")
-        toolchain-guess-tool-llvm-ar = $(shell $(1) --help 2>&1 <$(nul) | grep -o "LLVM Archiver")
+        toolchain-guess-tool-llvm-clang = $(shell $(1) -v 2>&1 </dev/null | grep -o "clang version")
+        toolchain-guess-tool-llvm-lld = $(shell $(1) --help 2>&1 </dev/null | grep -o "OVERVIEW: lld")
+        toolchain-guess-tool-llvm-objcopy = $(shell $(1) --help 2>&1 </dev/null | grep -o "llvm-objcopy tool")
+        toolchain-guess-tool-llvm-objdump = $(shell $(1) --help 2>&1 </dev/null | grep -o "llvm object file dumper")
+        toolchain-guess-tool-llvm-ar = $(shell $(1) --help 2>&1 </dev/null | grep -o "LLVM Archiver")
 
         # GNU Compiler Collection & GNU Binary Utilities
-        toolchain-guess-tool-gnu-gcc = $(shell $(1) -v 2>&1 <$(nul) | grep -o "gcc version")
-        toolchain-guess-tool-gnu-ld = $(shell $(1) -v 2>&1 <$(nul) | grep -o "GNU ld")
-        toolchain-guess-tool-gnu-objcopy = $(shell $(1) --version 2>&1 <$(nul) | grep -o "GNU objcopy")
-        toolchain-guess-tool-gnu-objdump = $(shell $(1) --version 2>&1 <$(nul) | grep -o "GNU objdump")
-        toolchain-guess-tool-gnu-ar = $(shell $(1) --version 2>&1 <$(nul) | grep -o "GNU ar")
+        toolchain-guess-tool-gnu-gcc = $(shell $(1) -v 2>&1 </dev/null | grep -o "gcc version")
+        toolchain-guess-tool-gnu-ld = $(shell $(1) -v 2>&1 </dev/null | grep -o "GNU ld")
+        toolchain-guess-tool-gnu-objcopy = $(shell $(1) --version 2>&1 </dev/null | grep -o "GNU objcopy")
+        toolchain-guess-tool-gnu-objdump = $(shell $(1) --version 2>&1 </dev/null | grep -o "GNU objdump")
+        toolchain-guess-tool-gnu-ar = $(shell $(1) --version 2>&1 </dev/null | grep -o "GNU ar")
 
         # Other tools
-        toolchain-guess-tool-generic-dtc = $(shell $(1) --version 2>&1 <$(nul) | grep -o "Version: DTC")
-        toolchain-guess-tool-generic-poetry = $(shell $(1) --version 2>&1 <$(nul))
+        toolchain-guess-tool-generic-dtc = $(shell $(1) --version 2>&1 </dev/null | grep -o "Version: DTC")
+        toolchain-guess-tool-generic-poetry = $(shell $(1) --version 2>&1 </dev/null)
 
         toolchain-guess-tool = $(if $(2),$(firstword $(foreach candidate,$(1),$\
                 $(if $(call toolchain-guess-tool-$(candidate),$(2)),$(candidate)))))
@@ -330,17 +329,17 @@
 
         toolchain-derive-llvm-clang-cpp = $(1)
         toolchain-derive-llvm-clang-as = $(1)
-        toolchain-derive-llvm-clang-ld = $(shell $(1) --print-prog-name ld.lld 2>$(nul))
-        toolchain-derive-llvm-clang-oc = $(shell $(1) --print-prog-name llvm-objcopy 2>$(nul))
-        toolchain-derive-llvm-clang-od = $(shell $(1) --print-prog-name llvm-objdump 2>$(nul))
-        toolchain-derive-llvm-clang-ar = $(shell $(1) --print-prog-name llvm-ar 2>$(nul))
+        toolchain-derive-llvm-clang-ld = $(shell $(1) --print-prog-name ld.lld 2>/dev/null)
+        toolchain-derive-llvm-clang-oc = $(shell $(1) --print-prog-name llvm-objcopy 2>/dev/null)
+        toolchain-derive-llvm-clang-od = $(shell $(1) --print-prog-name llvm-objdump 2>/dev/null)
+        toolchain-derive-llvm-clang-ar = $(shell $(1) --print-prog-name llvm-ar 2>/dev/null)
 
         toolchain-derive-gnu-gcc-cpp = $(1)
         toolchain-derive-gnu-gcc-as = $(1)
         toolchain-derive-gnu-gcc-ld = $(1)
-        toolchain-derive-gnu-gcc-oc = $(shell $(1) --print-prog-name objcopy 2>$(nul))
-        toolchain-derive-gnu-gcc-od = $(shell $(1) --print-prog-name objdump 2>$(nul))
-        toolchain-derive-gnu-gcc-ar = $(shell $(1) --print-prog-name ar 2>$(nul))
+        toolchain-derive-gnu-gcc-oc = $(shell $(1) --print-prog-name objcopy 2>/dev/null)
+        toolchain-derive-gnu-gcc-od = $(shell $(1) --print-prog-name objdump 2>/dev/null)
+        toolchain-derive-gnu-gcc-ar = $(shell $(1) --print-prog-name ar 2>/dev/null)
 
         toolchain-derive = $(if $3,$(call toolchain-derive-$1-$2,$3))
 
diff --git a/make_helpers/unix.mk b/make_helpers/unix.mk
deleted file mode 100644
index fa7722a..0000000
--- a/make_helpers/unix.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-# Trusted Firmware shell command definitions for a Unix style environment.
-
-ifndef UNIX_MK
-    UNIX_MK := $(lastword $(MAKEFILE_LIST))
-
-    DIR_DELIM := /
-    PATH_SEP := :
-
-    # These defines provide Unix style equivalents of the shell commands
-    # required by the Trusted Firmware build environment.
-
-    # ${1} is the file to be copied.
-    # ${2} is the destination file name.
-    define SHELL_COPY
-	$(q)cp -f  "${1}"  "${2}"
-    endef
-
-    # ${1} is the directory to be copied.
-    # ${2} is the destination directory path.
-    define SHELL_COPY_TREE
-	$(q)cp -rf  "${1}"  "${2}"
-    endef
-
-    # ${1} is the file to be deleted.
-    define SHELL_DELETE
-	-$(q)rm -f  "${1}"
-    endef
-
-    # ${1} is a space delimited list of files to be deleted.
-    # Note that we do not quote ${1}, as multiple parameters may be passed.
-    define SHELL_DELETE_ALL
-	-$(q)rm -rf  ${1}
-    endef
-
-    define SHELL_REMOVE_DIR
-	-$(q)rm -rf  "${1}"
-    endef
-
-    nul := /dev/null
-
-    which = $(shell command -v $(call escape-shell,$(1)) 2>$(nul))
-endif
diff --git a/make_helpers/utilities.mk b/make_helpers/utilities.mk
index fcccd24..10645bf 100644
--- a/make_helpers/utilities.mk
+++ b/make_helpers/utilities.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -127,3 +127,17 @@
 #
 
 defined = $(call bool,$(filter-out undefined,$(origin $(1))))
+
+#
+# Determine the path to a program.
+#
+# Parameters:
+#
+#   - $(1): The program to search for.
+#
+# Example usage:
+#
+#     path-to-gcc := $(call which,gcc) # "/usr/bin/gcc"
+#
+
+which = $(shell command -v $(call escape-shell,$(1)) 2>/dev/null)
diff --git a/make_helpers/windows.mk b/make_helpers/windows.mk
deleted file mode 100644
index c24aa08..0000000
--- a/make_helpers/windows.mk
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-# OS specific parts for builds in a Windows_NT environment. The
-# environment variable OS is set to Windows_NT on all modern Windows platforms
-
-# Include generic windows command definitions.
-
-ifndef WINDOWS_MK
-    WINDOWS_MK := $(lastword $(MAKEFILE_LIST))
-
-    DIR_DELIM := $(strip \)
-    BIN_EXT   := .exe
-    PATH_SEP  := ;
-
-    # For some Windows native commands there is a problem with the directory delimiter.
-    # Make uses / (slash) and the commands expect \ (backslash)
-    # We have to provide a means of translating these, so we define local functions.
-
-    # ${1} is the file to be copied.
-    # ${2} is the destination file name.
-    define SHELL_COPY
-	$(eval tmp_from_file:=$(subst /,\,${1}))
-	$(eval tmp_to_file:=$(subst /,\,${2}))
-	copy "${tmp_from_file}" "${tmp_to_file}"
-    endef
-
-    # ${1} is the directory to be copied.
-    # ${2} is the destination directory path.
-    define SHELL_COPY_TREE
-	$(eval tmp_from_dir:=$(subst /,\,${1}))
-	$(eval tmp_to_dir:=$(subst /,\,${2}))
-	xcopy /HIVE "${tmp_from_dir}" "${tmp_to_dir}"
-    endef
-
-    # ${1} is the file to be deleted.
-    define SHELL_DELETE
-	$(eval tmp_del_file:=$(subst /,\,${*}))
-	-@if exist $(tmp_del_file)  del /Q $(tmp_del_file)
-    endef
-
-    # ${1} is a space delimited list of files to be deleted.
-    define SHELL_DELETE_ALL
-	$(eval $(foreach filename,$(wildcard ${1}),$(call DELETE_IF_THERE,${filename})))
-    endef
-
-    # ${1} is the directory to be removed.
-    define SHELL_REMOVE_DIR
-	$(eval tmp_dir:=$(subst /,\,${1}))
-	-@if exist "$(tmp_dir)"  rd /Q /S "$(tmp_dir)"
-    endef
-
-    nul := nul
-
-    which = $(shell where "$(1)" 2>$(nul))
-endif
-
-# Because git is not available from CMD.EXE, we need to avoid
-# the BUILD_STRING generation which uses git.
-# For now we use "development build".
-# This can be overridden from the command line or environment.
-BUILD_STRING ?= development build
-
-MSVC_NMAKE := nmake.exe
diff --git a/package-lock.json b/package-lock.json
index a039bc5..61d05bd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1963,9 +1963,9 @@
       }
     },
     "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
       "dev": true,
       "dependencies": {
         "path-key": "^3.1.0",
diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c
index 6512dbc..05e4c96 100644
--- a/plat/amd/versal2/bl31_setup.c
+++ b/plat/amd/versal2/bl31_setup.c
@@ -127,14 +127,14 @@
 
 	uart_clock = get_uart_clk();
 
+	/* Initialize the platform config for future decision making */
+	config_setup();
+
 	setup_console();
 
 	NOTICE("TF-A running on %s %d.%d\n", board_name_decode(),
 	       platform_version / 10U, platform_version % 10U);
 
-	/* Initialize the platform config for future decision making */
-	config_setup();
-
 	/*
 	 * Do initial security configuration to allow DRAM/device access. On
 	 * Base only DRAM security is programmable (via TrustZone), but
diff --git a/plat/arm/board/a5ds/platform.mk b/plat/arm/board/a5ds/platform.mk
index dd82a10..6d60cbe 100644
--- a/plat/arm/board/a5ds/platform.mk
+++ b/plat/arm/board/a5ds/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -75,9 +75,7 @@
 				${DYN_CFG_SOURCES}				\
 				${A5DS_SECURITY_SOURCES}
 
-# Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
-ifdef UNIX_MK
-
+# Add the FDT_SOURCES and options for Dynamic Config
 FW_CONFIG	:=      ${BUILD_PLAT}/fdts/a5ds_fw_config.dtb
 TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/a5ds_tb_fw_config.dtb
 
@@ -94,7 +92,6 @@
 FDT_SOURCES		+=	plat/arm/board/a5ds/fdts/a5ds_fw_config.dts \
 				plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts \
 					${FVP_HW_CONFIG_DTS}
-endif
 
 NEED_BL32 := yes
 
diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c
index 4a2572f..b1f7b11 100644
--- a/plat/arm/board/common/board_arm_trusted_boot.c
+++ b/plat/arm/board/common/board_arm_trusted_boot.c
@@ -44,11 +44,11 @@
 #pragma weak plat_get_nv_ctr
 #pragma weak plat_set_nv_ctr
 
-extern unsigned char arm_rotpk_header[], arm_rotpk_key[], arm_rotpk_hash_end[],
+extern unsigned char arm_rotpk_hash_der_header[], arm_rotpk_key[], arm_rotpk_hash_end[],
        arm_rotpk_key_end[];
 
 #if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
-static unsigned char rotpk_hash_der[ARM_ROTPK_HEADER_LEN + ARM_ROTPK_HASH_LEN];
+static unsigned char rotpk_hash_der[ARM_ROTPK_HASH_DER_HEADER_LEN + ARM_ROTPK_HASH_LEN];
 #endif
 
 #if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
@@ -68,8 +68,8 @@
 
 	/* Copy the DER header */
 
-	memcpy(rotpk_hash_der, arm_rotpk_header, ARM_ROTPK_HEADER_LEN);
-	dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HEADER_LEN];
+	memcpy(rotpk_hash_der, arm_rotpk_hash_der_header, ARM_ROTPK_HASH_DER_HEADER_LEN);
+	dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HASH_DER_HEADER_LEN];
 
 	words = ARM_ROTPK_HASH_LEN >> 2;
 
@@ -95,8 +95,8 @@
 int arm_get_rotpk_info_dev(void **key_ptr, unsigned int *key_len,
 			unsigned int *flags)
 {
-	*key_ptr = arm_rotpk_header;
-	*key_len = arm_rotpk_hash_end - arm_rotpk_header;
+	*key_ptr = arm_rotpk_hash_der_header;
+	*key_len = arm_rotpk_hash_end - arm_rotpk_hash_der_header;
 	*flags = ROTPK_IS_HASH;
 	return 0;
 }
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
index 365a960..124a44b 100644
--- a/plat/arm/board/common/board_common.mk
+++ b/plat/arm/board/common/board_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -13,63 +13,70 @@
 
 ifneq (${TRUSTED_BOARD_BOOT},0)
 ARM_ROTPK_S = plat/arm/board/common/rotpk/arm_dev_rotpk.S
+ARM_ROTPK = $(BUILD_PLAT)/arm_rotpk.bin
+ARM_ROTPK_IS_HASH := 1
+$(eval $(call add_define_val,ARM_ROTPK,'"$(ARM_ROTPK)"'))
 
 # ROTPK hash location
 ifeq (${ARM_ROTPK_LOCATION}, regs)
 	ARM_ROTPK_LOCATION_ID = ARM_ROTPK_REGS_ID
-else ifeq (${ARM_ROTPK_LOCATION}, devel_rsa)
+else
+# The ROTPK is a development key
+ifeq (${ARM_ROTPK_LOCATION}, devel_rsa)
 	CRYPTO_ALG=rsa
 	ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_RSA_ID
-	ARM_ROTPK_HASH = plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
-$(eval $(call add_define_val,ARM_ROTPK_HASH,'"$(ARM_ROTPK_HASH)"'))
-$(BUILD_PLAT)/bl2/arm_dev_rotpk.o : $(ARM_ROTPK_HASH)
+	ROT_KEY ?= plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
 $(warning Development keys support for FVP is deprecated. Use `regs` \
 option instead)
 else ifeq (${ARM_ROTPK_LOCATION}, devel_ecdsa)
 	CRYPTO_ALG=ec
 	ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_ECDSA_ID
-	ARM_ROTPK_HASH = plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
-$(eval $(call add_define_val,ARM_ROTPK_HASH,'"$(ARM_ROTPK_HASH)"'))
-$(BUILD_PLAT)/bl2/arm_dev_rotpk.o : $(ARM_ROTPK_HASH)
+	ROT_KEY ?= plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
 $(warning Development keys support for FVP is deprecated. Use `regs` \
 option instead)
 else ifeq (${ARM_ROTPK_LOCATION}, devel_full_dev_rsa_key)
 	CRYPTO_ALG=rsa
 	ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_FULL_DEV_RSA_KEY_ID
-	ARM_ROTPK_S = plat/arm/board/common/rotpk/arm_full_dev_rsa_rotpk.S
+	ROT_KEY ?= plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
+	ARM_ROTPK_IS_HASH = 0
 $(warning Development keys support for FVP is deprecated. Use `regs` \
 option instead)
 else ifeq (${ARM_ROTPK_LOCATION}, devel_full_dev_ecdsa_key)
 	CRYPTO_ALG=ec
 	ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_FULL_DEV_ECDSA_KEY_ID
-ifeq (${KEY_SIZE},384)
-	ARM_ROTPK_S = plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p384_rotpk.S
-else
-	ARM_ROTPK_S = plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p256_rotpk.S
-endif
+	ROT_KEY ?= plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
+	ARM_ROTPK_IS_HASH = 0
 $(warning Development keys support for FVP is deprecated. Use `regs` \
 option instead)
 else
 $(error "Unsupported ARM_ROTPK_LOCATION value")
 endif
+$(BUILD_PLAT)/bl1/arm_dev_rotpk.o : $(ARM_ROTPK)
+$(BUILD_PLAT)/bl2/arm_dev_rotpk.o : $(ARM_ROTPK)
+endif
 
 $(eval $(call add_define,ARM_ROTPK_LOCATION_ID))
+$(eval $(call add_define,ARM_ROTPK_IS_HASH))
 
 ifeq (${ENABLE_RME}, 1)
 COT	:=	cca
 endif
 
-# Force generation of the new hash if ROT_KEY is specified
+# Force generation of the ROT public key if ROT_KEY is specified
 ifdef ROT_KEY
-	HASH_PREREQUISITES = $(ROT_KEY) FORCE
+	PK_PREREQUISITES = $(ROT_KEY) FORCE
 endif
 
-$(ARM_ROTPK_HASH) : $(HASH_PREREQUISITES)
+$(ARM_ROTPK) : $(PK_PREREQUISITES)
 ifndef ROT_KEY
-	$(error Cannot generate hash: no ROT_KEY defined)
+	$(error Cannot generate public key: no ROT_KEY defined)
 endif
+ifeq ($(ARM_ROTPK_IS_HASH), 1)
 	${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in $< -pubout -outform DER | \
-	${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@
+	${OPENSSL_BIN_PATH}/openssl dgst -${HASH_ALG} -binary -out $@
+else
+	${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in $< -pubout -outform DER -out $@
+endif
 
 # Certificate NV-Counters. Use values corresponding to tied off values in
 # ARM development platforms
@@ -85,50 +92,73 @@
 BL2_SOURCES		+=	plat/arm/board/common/board_arm_trusted_boot.c \
 				${ARM_ROTPK_S}
 
+ifeq ($(CRYPTO_ALG), ec)
+ifeq ($(KEY_SIZE), 384)
+ARM_PROT_KEY		:=	plat/arm/board/common/protpk/arm_protprivk_ecdsa_secp384r1.pem
+ARM_SWD_ROT_KEY		:=	plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa_secp384r1.pem
+else
+ARM_PROT_KEY		:=	plat/arm/board/common/protpk/arm_protprivk_ecdsa.pem
+ARM_SWD_ROT_KEY		:=	plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa.pem
+endif
+else
+ARM_PROT_KEY		:=	plat/arm/board/common/protpk/arm_protprivk_rsa.pem
+ARM_SWD_ROT_KEY		:=	plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem
+endif
+
 # Allows platform code to provide implementation variants depending on the
 # selected chain of trust.
 $(eval $(call add_define,ARM_COT_${COT}))
 
 ifeq (${COT},dualroot)
 # Platform Root of Trust key files.
-ARM_PROT_KEY		:=	plat/arm/board/common/protpk/arm_protprivk_rsa.pem
-ARM_PROTPK_HASH		:=	plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
+ARM_PROTPK			:=	$(BUILD_PLAT)/arm_protpk.bin
 
 # Provide the private key to cert_create tool. It needs it to sign the images.
 PROT_KEY		:=	${ARM_PROT_KEY}
 
-$(eval $(call add_define_val,ARM_PROTPK_HASH,'"$(ARM_PROTPK_HASH)"'))
+$(eval $(call add_define_val,ARM_PROTPK,'"$(ARM_PROTPK)"'))
 
 BL1_SOURCES		+=	plat/arm/board/common/protpk/arm_dev_protpk.S
 BL2_SOURCES		+=	plat/arm/board/common/protpk/arm_dev_protpk.S
 
-$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
-$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
+$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK)
+$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK)
 endif
 
 ifeq (${COT},cca)
 # Platform and Secure World Root of Trust key files.
-ARM_PROT_KEY		:=	plat/arm/board/common/protpk/arm_protprivk_rsa.pem
-ARM_PROTPK_HASH		:=	plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
-ARM_SWD_ROT_KEY		:=	plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem
-ARM_SWD_ROTPK_HASH	:=	plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
+ARM_PROTPK			:=	$(BUILD_PLAT)/arm_protpk.bin
+ARM_SWD_ROTPK		:=	$(BUILD_PLAT)/arm_swd_rotpk.bin
 
 # Provide the private keys to cert_create tool. It needs them to sign the images.
 PROT_KEY		:=	${ARM_PROT_KEY}
 SWD_ROT_KEY		:=	${ARM_SWD_ROT_KEY}
 
-$(eval $(call add_define_val,ARM_PROTPK_HASH,'"$(ARM_PROTPK_HASH)"'))
-$(eval $(call add_define_val,ARM_SWD_ROTPK_HASH,'"$(ARM_SWD_ROTPK_HASH)"'))
+$(eval $(call add_define_val,ARM_PROTPK,'"$(ARM_PROTPK)"'))
+$(eval $(call add_define_val,ARM_SWD_ROTPK,'"$(ARM_SWD_ROTPK)"'))
 
 BL1_SOURCES		+=	plat/arm/board/common/protpk/arm_dev_protpk.S \
 				plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
 BL2_SOURCES		+=	plat/arm/board/common/protpk/arm_dev_protpk.S \
 				plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
 
+$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK)
+$(BUILD_PLAT)/bl1/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK)
+$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK)
+$(BUILD_PLAT)/bl2/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK)
+endif
+
-$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
-$(BUILD_PLAT)/bl1/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK_HASH)
-$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
-$(BUILD_PLAT)/bl2/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK_HASH)
+$(ARM_PROTPK): $(ARM_PROT_KEY)
+ifndef ARM_PROT_KEY
+	$(error Cannot generate hash: no PROT_KEY defined)
 endif
+	${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in ${ARM_PROT_KEY} -pubout -outform DER | \
+	${OPENSSL_BIN_PATH}/openssl dgst -${HASH_ALG} -binary -out $@
 
+$(ARM_SWD_ROTPK): $(ARM_SWD_ROT_KEY)
+ifndef ARM_SWD_ROT_KEY
+	$(error Cannot generate hash: no SWD_KEY defined)
+endif
+	${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in ${ARM_SWD_ROT_KEY} -pubout -outform DER | \
+	${OPENSSL_BIN_PATH}/openssl dgst -${HASH_ALG} -binary -out $@
 endif
diff --git a/plat/arm/board/common/protpk/README b/plat/arm/board/common/protpk/README
index 3aca180..15a0a9a 100644
--- a/plat/arm/board/common/protpk/README
+++ b/plat/arm/board/common/protpk/README
@@ -6,9 +6,12 @@
 
   openssl genrsa 2048 > arm_protprivk_rsa.pem
 
-* arm_protpk_rsa_sha256.bin is the SHA-256 hash of the DER-encoded public key
-  associated with the above private key. It has been generated using the openssl
-  command line tool:
+* arm_protprivk_ecdsa.pem is a P-256 ECSA private key in PEM format. It has been
+  generated using the openssl command line tool:
+
+  openssl ecparam -name prime256v1 -genkey -outform PEM -noout -out arm_protprivk_ecdsa.pem
+
+* arm_protprivk_ecdsa_secp384r1.pem is a P-384 ECSA private key in PEM format. It has been
+  generated using the openssl command line tool:
 
-  openssl rsa -in arm_protprivk_rsa.pem -pubout -outform DER | \
-    openssl dgst -sha256 -binary > arm_protpk_rsa_sha256.bin
+  openssl ecparam -name secp384r1 -genkey -outform PEM -noout -out arm_protprivk_ecdsa_secp384r1.pem
\ No newline at end of file
diff --git a/plat/arm/board/common/protpk/arm_dev_protpk.S b/plat/arm/board/common/protpk/arm_dev_protpk.S
index 2688cbb..79b8c36 100644
--- a/plat/arm/board/common/protpk/arm_dev_protpk.S
+++ b/plat/arm/board/common/protpk/arm_dev_protpk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,10 +9,31 @@
 
 	.section .rodata.arm_protpk_hash, "a"
 
+/*
+* The protpk header is dependent only on the algorithm used to
+* generate the hash.
+* ASN1_HASH_ALG is the last byte used to encode the OID for
+* the hash algorithm into the header,
+* this byte distinguishes between SHA256, SHA384 and SHA512.
+*/
+.equ HASH_ASN1_LEN, ARM_ROTPK_HASH_LEN
+#if ARM_ROTPK_HASH_LEN == 48
+	.equ ASN1_HASH_ALG, 0x02
+	.equ TOTAL_ASN1_LEN, 0x41
+#elif ARM_ROTPK_HASH_LEN == 64
+	.equ ASN1_HASH_ALG, 0x03
+	.equ TOTAL_ASN1_LEN, 0x51
+#elif ARM_ROTPK_HASH_LEN == 32
+	.equ ASN1_HASH_ALG, 0x01
+	.equ TOTAL_ASN1_LEN, 0x31
+#else
+	.error "Invalid PROTPK hash length."
+#endif
+
 arm_protpk_hash:
 	/* DER header. */
-	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
-	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	.byte 0x30, TOTAL_ASN1_LEN, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, ASN1_HASH_ALG, 0x05, 0x00, 0x04, HASH_ASN1_LEN
 	/* Key hash. */
-	.incbin ARM_PROTPK_HASH
+	.incbin ARM_PROTPK
 arm_protpk_hash_end:
diff --git a/plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin b/plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
deleted file mode 100644
index 587da66..0000000
--- a/plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
+++ /dev/null
@@ -1 +0,0 @@
-œó6{W*…`Ÿtíve×·§è£	€¾PžÆK{9
\ No newline at end of file
diff --git a/plat/arm/board/common/protpk/arm_protprivk_ecdsa.pem b/plat/arm/board/common/protpk/arm_protprivk_ecdsa.pem
new file mode 100644
index 0000000..5888e10
--- /dev/null
+++ b/plat/arm/board/common/protpk/arm_protprivk_ecdsa.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEILviumKhnibRT6+73/WOURk8lCxu/AHRQVcbCn/nGAr8oAoGCCqGSM49
+AwEHoUQDQgAE2HPZeAd+P8kZKHcCMfNUE+MlZSKJV360gYYC1JEdogyYztJ/QbKj
+26CZijUU/He2b9kkCOpZoJp3UuMRlsQE4Q==
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/common/protpk/arm_protprivk_ecdsa_secp384r1.pem b/plat/arm/board/common/protpk/arm_protprivk_ecdsa_secp384r1.pem
new file mode 100644
index 0000000..d9db645
--- /dev/null
+++ b/plat/arm/board/common/protpk/arm_protprivk_ecdsa_secp384r1.pem
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCn+L3kRlvrZKnemt8aDOH+ujwuhpdwAM2ZxacxudJPy5qrWCjXGIh1
+gOAMHlGESySgBwYFK4EEACKhZANiAASM5exqdUZi0msFLGi42bIMW7FPqWsJ8YmL
+scDkI6BUYRoP0V4XZWB7NOjP6y/tm5Uwid9q25QTlhNKUo5qki1YH3T6unHuylWN
+63KRHQLOaXCXZqhMhT0wccg0gG3hs+0=
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/common/rotpk/arm_dev_rotpk.S b/plat/arm/board/common/rotpk/arm_dev_rotpk.S
index 22ae9d3..f4a1875 100644
--- a/plat/arm/board/common/rotpk/arm_dev_rotpk.S
+++ b/plat/arm/board/common/rotpk/arm_dev_rotpk.S
@@ -6,20 +6,64 @@
 
 #include <plat/arm/board/common/rotpk/rotpk_def.h>
 
-	.global arm_rotpk_header
+#if ARM_ROTPK_IS_HASH == 1
+	.global arm_rotpk_hash_der_header
+	.global arm_rotpk_hash_end
 	.section .rodata.arm_rotpk_hash, "a"
 
-arm_rotpk_header:
-	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
-	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
-arm_rotpk_header_len:
+	#ifndef ARM_ROTPK_HASH_LEN
+	.error "ROTPK hash not defined."
+	#endif
 
-#ifdef ARM_ROTPK_HASH
-	.global arm_rotpk_hash_end
-	.incbin ARM_ROTPK_HASH
+	/*
+	* The rotpk header is dependent only on the algorithm used to
+	* generate the hash.
+	* ASN1_HASH_ALG is the last byte used to encode the OID for
+	* the hash algorithm into the header,
+	* this byte distinguishes between SHA256, SHA384 and SHA512.
+	*/
+	.equ HASH_ASN1_LEN, ARM_ROTPK_HASH_LEN
+	#if ARM_ROTPK_HASH_LEN == 48
+		.equ ASN1_HASH_ALG, 0x02
+		.equ TOTAL_ASN1_LEN, 0x41
+	#elif ARM_ROTPK_HASH_LEN == 64
+		.equ ASN1_HASH_ALG, 0x03
+		.equ TOTAL_ASN1_LEN, 0x51
+	#elif ARM_ROTPK_HASH_LEN == 32
+		.equ ASN1_HASH_ALG, 0x01
+		.equ TOTAL_ASN1_LEN, 0x31
+	#else
+		.error "Invalid ROTPK hash length."
+	#endif
+
+arm_rotpk_hash_der_header:
+	.byte 0x30, TOTAL_ASN1_LEN, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, ASN1_HASH_ALG, 0x05, 0x00, 0x04, HASH_ASN1_LEN
+arm_rotpk_hash_der_header_len:
+
+#ifdef ARM_ROTPK
+	.incbin ARM_ROTPK
 arm_rotpk_hash_end:
 #endif
 
-.if ARM_ROTPK_HEADER_LEN != arm_rotpk_header_len - arm_rotpk_header
-.error "Invalid ROTPK header length."
-.endif
+	.if ARM_ROTPK_HASH_DER_HEADER_LEN != arm_rotpk_hash_der_header_len - arm_rotpk_hash_der_header
+		.error "Invalid ROTPK header length."
+	.endif
+
+#else
+	/*
+	* The rotpk is an unhashed public key in DER format.
+	* We do not need a header in this case.
+	*/
+	.global arm_rotpk_key
+	.section .rodata.arm_rotpk_key, "a"
+
+arm_rotpk_key:
+	#ifdef ARM_ROTPK
+		.global arm_rotpk_key_end
+		.incbin ARM_ROTPK
+arm_rotpk_key_end:
+	#else
+		.error "ROTPK not found."
+	#endif
+#endif
\ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p256_rotpk.S b/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p256_rotpk.S
deleted file mode 100644
index 690bdbc..0000000
--- a/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p256_rotpk.S
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-	.global arm_rotpk_key
-	.global arm_rotpk_key_end
-
-	.section .rodata.arm_rotpk_key, "a"
-
-/* Derived from arm_rotprivk_ecdsa.pem private key file. */
-arm_rotpk_key:
-	.byte 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D
-	.byte 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01
-	.byte 0x07, 0x03, 0x42, 0x00, 0x04, 0x9B, 0xE6, 0x48, 0xBD, 0x34, 0x38
-	.byte 0xE1, 0xA2, 0xA4, 0xF3, 0x70, 0xE1, 0x54, 0xBB, 0x2F, 0xB0, 0x5A
-	.byte 0x4A, 0x0C, 0xFF, 0xC2, 0x87, 0xDB, 0xC0, 0xFB, 0x81, 0xE9, 0xF9
-	.byte 0xF9, 0x95, 0x7D, 0x7E, 0xA0, 0x0C, 0x7F, 0x0A, 0xD4, 0xE0, 0x62
-	.byte 0x4A, 0x94, 0x5F, 0xEC, 0x52, 0x7D, 0x44, 0x63, 0xC8, 0x9F, 0x61
-	.byte 0xFA, 0xC6, 0xCB, 0x7E, 0x6B, 0x53, 0xAD, 0x2C, 0xC5, 0x94, 0x0D
-	.byte 0x1A, 0x86, 0x91
-arm_rotpk_key_end:
diff --git a/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p384_rotpk.S b/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p384_rotpk.S
deleted file mode 100644
index eaf2de4..0000000
--- a/plat/arm/board/common/rotpk/arm_full_dev_ecdsa_p384_rotpk.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-	.global arm_rotpk_key
-	.global arm_rotpk_key_end
-
-	.section .rodata.arm_rotpk_key, "a"
-
-/* Derived from arm_rotprivk_ecdsa_secp384r1.pem private key file. */
-arm_rotpk_key:
-	.byte 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D
-	.byte 0x02, 0x01, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62
-	.byte 0x00, 0x04, 0xB8, 0xB0, 0xC7, 0xC4, 0x57, 0x19, 0xB7, 0x5A, 0x06
-	.byte 0x36, 0xC5, 0xD8, 0x3C, 0x4E, 0xC3, 0xB5, 0xE1, 0x15, 0x60, 0x0E
-	.byte 0x63, 0xD8, 0xAF, 0x22, 0x2C, 0x6D, 0x79, 0x29, 0xDF, 0x46, 0xA9
-	.byte 0x30, 0x12, 0x16, 0x2D, 0x4F, 0x0F, 0x96, 0x6B, 0x1F, 0x87, 0x06
-	.byte 0xDB, 0x8F, 0xD7, 0x08, 0x46, 0xE4, 0x4C, 0x22, 0xF3, 0xDE, 0xCE
-	.byte 0x0F, 0x72, 0x27, 0x00, 0xAA, 0xD8, 0xC3, 0x79, 0x80, 0x5E, 0xF1
-	.byte 0x35, 0x1B, 0x33, 0xB6, 0x31, 0xC4, 0x59, 0xD4, 0xE9, 0x65, 0x91
-	.byte 0x22, 0x58, 0x2F, 0x87, 0xF1, 0x6C, 0x27, 0xBE, 0x99, 0x6F, 0x5F
-	.byte 0x6C, 0x14, 0xC5, 0x37, 0x0C, 0x73, 0xB4, 0xE4, 0x8A, 0x63
-arm_rotpk_key_end:
diff --git a/plat/arm/board/common/rotpk/arm_full_dev_rsa_rotpk.S b/plat/arm/board/common/rotpk/arm_full_dev_rsa_rotpk.S
deleted file mode 100644
index 4532e53..0000000
--- a/plat/arm/board/common/rotpk/arm_full_dev_rsa_rotpk.S
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-	.global arm_rotpk_key
-	.global arm_rotpk_key_end
-
-	.section .rodata.arm_rotpk_key, "a"
-
-arm_rotpk_key:
-	.byte 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48
-	.byte 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01
-	.byte 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00
-	.byte 0xCB, 0x2C, 0x60, 0xD5, 0x8D, 0x63, 0xD4, 0x07, 0x79, 0x7E, 0xC7
-	.byte 0x16, 0x96, 0xBD, 0x4D, 0x24, 0x4E, 0xAC, 0x86, 0xE6, 0xB7, 0x71
-	.byte 0xE3, 0xC5, 0x54, 0x0B, 0xE7, 0x14, 0x1C, 0xBD, 0x29, 0x1A, 0xC1
-	.byte 0x3F, 0x7A, 0xB6, 0x02, 0xAA, 0xAB, 0x36, 0xC4, 0xD9, 0x36, 0x69
-	.byte 0x6C, 0xE2, 0x65, 0xC3, 0x9B, 0xB1, 0xBF, 0x3D, 0xA8, 0x56, 0x26
-	.byte 0xCB, 0xFD, 0x04, 0x01, 0xBA, 0xAC, 0x3E, 0x54, 0x32, 0xCA, 0x79
-	.byte 0x5E, 0xBB, 0xB2, 0x05, 0xEA, 0x06, 0x58, 0xF2, 0x74, 0xBA, 0xE1
-	.byte 0xF4, 0x87, 0xC0, 0x19, 0x0A, 0x1F, 0x66, 0x07, 0x77, 0x84, 0x83
-	.byte 0xA1, 0x1C, 0xEF, 0xFF, 0x28, 0x59, 0xE7, 0xC3, 0x68, 0x7D, 0x26
-	.byte 0x20, 0x43, 0xEB, 0x56, 0x63, 0xF3, 0x39, 0x31, 0xD8, 0x2B, 0x51
-	.byte 0xA9, 0xBC, 0x4F, 0xD0, 0xF6, 0xDE, 0x95, 0xDC, 0x5F, 0x5B, 0xC1
-	.byte 0xED, 0x90, 0x6F, 0xEC, 0x28, 0x91, 0x7E, 0x17, 0xED, 0x78, 0x90
-	.byte 0xF4, 0x60, 0xA7, 0xC4, 0xC7, 0x4F, 0x50, 0xED, 0x5D, 0x13, 0x3A
-	.byte 0x21, 0x2B, 0x70, 0xC5, 0x61, 0x7B, 0x08, 0x21, 0x65, 0x3A, 0xCD
-	.byte 0x82, 0x56, 0x8C, 0x7A, 0x47, 0xAC, 0x89, 0xE8, 0xA5, 0x48, 0x48
-	.byte 0x31, 0xD9, 0x1D, 0x46, 0xE5, 0x85, 0x86, 0x98, 0xA0, 0xE5, 0xC0
-	.byte 0xA6, 0x6A, 0xBD, 0x07, 0xE4, 0x92, 0x57, 0x61, 0x07, 0x8F, 0x7D
-	.byte 0x5A, 0x4D, 0xCA, 0xAE, 0x36, 0xB9, 0x56, 0x04, 0x10, 0xF2, 0x6C
-	.byte 0xBE, 0xF6, 0x3B, 0x6C, 0x80, 0x3E, 0xBE, 0x0E, 0xA3, 0x4D, 0xC7
-	.byte 0xD4, 0x7E, 0xA7, 0x49, 0xD4, 0xF2, 0xD2, 0xBC, 0xCF, 0x30, 0xA8
-	.byte 0xE7, 0x74, 0x8F, 0x64, 0xDF, 0xBC, 0x5C, 0x47, 0x68, 0xCC, 0x40
-	.byte 0x4C, 0xF8, 0x83, 0xCC, 0xCB, 0x40, 0x35, 0x04, 0x60, 0xCA, 0xB3
-	.byte 0xA4, 0x17, 0x9F, 0x03, 0xCA, 0x1D, 0x5A, 0xFA, 0xD1, 0xAF, 0x21
-	.byte 0x57, 0x10, 0xD3, 0x02, 0x03, 0x01, 0x00, 0x01
-arm_rotpk_key_end:
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
deleted file mode 100644
index 2547877..0000000
--- a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
+++ /dev/null
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
deleted file mode 100644
index c5e123a..0000000
--- a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
+++ /dev/null
@@ -1 +0,0 @@
-.@¿nù»˜1q	=ýÑÌiJ˜ë‹ ° †Nl
\ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_rsa.der b/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
deleted file mode 100644
index 661f899..0000000
--- a/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
+++ /dev/null
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin b/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
deleted file mode 100644
index 7653f7e..0000000
--- a/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
+++ /dev/null
@@ -1 +0,0 @@
-°ó‚	—Ø:7zrGì2sé’2âIYö^‹JJFØ"šÚ
\ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_rsa_3k.pem b/plat/arm/board/common/rotpk/arm_rotprivk_rsa_3k.pem
new file mode 100644
index 0000000..842979d
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_rsa_3k.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCi82DxdQ1Z88RT
+DBoK8nBZ3SF4YSnOSV3KXODZHtEJq/D1HihLpCITsB1GkR17qGX5XzjcIvrS7tGC
+1Y/ELC+wL1DNoNlLsgwfZdQ3+MGGlkymnK37/b5Q1bvkuthAHg415skvdzX+6tpM
+y3bbGn55oW+hjynGo9lhixZiOA22sKhHFM6TBgpyNyXt/EpxGHcL4HM59LSWgB3I
+UX6l0Fb5MLb3XRzOkPcf6tQwnupDRS8rcRKHlkq8m0kIZ619zDkj4DZVW7VSU3hj
+vnzMMTEqbJ9uBnGFLdTqw2O822jOtKJ8pDqcN1xEe60a0CN0abN5uNzr9WPgLw5d
+ZjWqTx2kFVbjIr5nAiY6KTUoas/radidv/r5BY4wXvbi/SVNHip4oLoKCgu6T+Un
+pIc5DG0osXKO/xtT5gsQUZ/AXEztCsEeuwkueEZ8c1AG+ceoOul/zH4y0YrFGzxV
+apwwRuXZQtjU0lXpFlD1Yy83QzkrxWgEfE5mUm402TRF92oLsY8CAwEAAQKCAYA5
+QBwLyW3G8FPGP8a4mOQrVntncW/AN9uZeRdQgTi9VqkiXZWXudN1Klemzt5Wb1xg
+iHmQMkQArwJyHrlTmZippH4VuNEPfL8wmtS8U4wezpigowSnt8dRXD6XBqRqpoSk
+oHCH2jDg3r+S4ptgMIdGEZeIYiWx0ihSUo0rNflvedKtopxPYHx0E3cijZTT9l4B
+ELs7HgQCqoGMO0GtXSzpgRmPgCnaU2lXz+f8KyEwQFLpxuDVPVMFv+Mhblewjnrn
+IpDUAocRPI1n0cOrObHHnnpVzkKpz4usxBfsvc+9Qg37hS/1ccbOWKPjA/LS9dOC
+w29J6pa3Az9AGQ6OdZlhbaOH7hMj4gmreC/4omtgV+IhOL65TeMeBwIY0Vb4gtCQ
+yHhu2eT99MeL+G/Zw+00RRqzKl898tnYTvBkFG1llIFyT9LRqPY8lRHAQzzgNTRq
+ZpwTAijCRxmBAIDdBkXQai/En2PP3LMuORZ9+2zYu5uIJeZnBoHKONtDlpOpKpkC
+gcEA2HkeVlfmFgiBen4QMRKCseB9II9s+xiPjk8VpWT2TRmsVPEmKRrIKkXER2YO
+yYG97vBocECQXOHB0dNNUTMtbnFvY9B0FAswcUwtWPdjafrqmPe6iIZkynTaFqCG
+nY52P4EYZsSF3YthXkkzZuwzaQ/zyVA5W2HXp/XL8SKj9uPA3dEMP114Of9jNlmH
++gfpNY49tiXomR1DX/k6nmyJyeG9eUVBGlmxERK72g/7OynYLK8o/7T3m8SUW5lq
+R5hZAoHBAMC0ZI36iq2m18xtEx84nrlipbRRRahIeb2bXziPBL3yEbomotwrabDl
+GExl3PpfAEUlNnqseZ3GS2EpESsEbOBnLuWmviF528pX/H/pw87AVjuseUZQOjzI
+GzuJu+Of0DNlt7FJsaWrOJeNqT0t1w0JiII3uEekmIC59740lyUJ2sVZlDq6Gf7i
+etV+7oqGn+aAmXgug0wszezMaYH8ZNjLgrxkxIsLSONQ8tUX3CYXglkqty0/JRVA
+ZCluTQ/cJwKBwHzESlz/qoi2fFIqiJCQF64IMnZq1ChhPpSKNnKun1tO2cnXd+Qn
+IIlkzr1MMGeqFNu7yqYwQESYhgq23BBaC+xlCwufoNfQnyod+uEVLUJvMXnbBrMb
+qsoZ0X1LJmt3KeZuNK8+w90uMX+Td0HyD6uVWzCDwZtO6GpRPCuOiKyLFqWCkKmQ
+6POcpAU2Uy4kEyEgC6eJb+eYOzX8wvF+o2gtaPSVmvFiErFBd+42Wdn+wy72Ag5n
+snMgOVYWNXBweQKBwQCcsBEzAIzSNd8x8V6i/D7TLkreG1cwRf33FeaO7ntElxei
+7Ndvfj0qAJ2JQSo0yhpGHsP1a1hX2WxhTCsRdz+wFzYitTnTrmnwVSqSN1lnOyzi
+yJKzgXhZA7xg5NVJeCCqKgL6vJkdw+L4F8+MV0GM8Dt25ieI2WTHBm9S0SA0lZa0
+8Ol99uQ8Q5rtDZCYQm6x1c7z0Z4gyi2GZY9EihzVymQ7GxRUmpBhhOhuLEBtGKB8
+MCdROw7EAN9wcKdoRfECgcB5zqNzKu2kbpa0oeHLLDpcOK1w9e7khN3/j3dTrpRw
+em8+HoCF54PoyfkPWANTHfg+Bs2gktgvUsxfLy0/DDBIRUBQXo6AyztfB34D5/3L
+QIPyPjSgQKxOCnUCcDAkvVRY+6J7W6J/pW385ZhzikCUrRSKrbc3UYEu3UZwypSC
+mJGKLUzhDhPYvIginpIugE9Pv3WXfKas3HRrk7UdqjIMpJxIRF5CULsEaZua6tje
+1oA5miNwoiXHcxPoo2qMtz8=
+-----END PRIVATE KEY-----
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_rsa_4k.pem b/plat/arm/board/common/rotpk/arm_rotprivk_rsa_4k.pem
new file mode 100644
index 0000000..2309ee6
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_rsa_4k.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDGeG6dmMX7DHdx
+LJ5vi3HpqSLVfyiGzYmjN14bcOORf1efCXy+0KfZ4M/N1rw/fVzIH6LP6iKm8rrH
+HQleKMb2rklbu8Azchr9fAJCbbbhENjhbp+lnh5W+bMWlhz4ePoSft/VNDssK/30
+tedSX7AEqs8nXOcqIjcOTnkB1UocNSAd98WP+m7oeqcwrJZGFj2HKHPkZiveX4c6
+5pN7xsdeuJ00FbOau7R3tX+0hInbTCxuA9UfPR9O+TrElMETPBCwvYUDo8SO0Oj9
+Vn3VsMYLuYfOQuHY65pgepBytgu6MTL8mKGxMTZ3HeaBfD2cDzf1tOe3PoN2eeBA
+eGHt/L9R7z0/84kfWDJg8zG9eSfCofXJy3HNlYAWo7fIdRaidNc75vU3DWRYrCE2
+OLwR+3pIRUoP+Pa1Xhaal/mXH9MHKNvK2aBz2QPgjaujMNlh9yLLtBjnBAcO9IXh
+ktS2pnEYwf+Rh2Nepy2sJa4Q88ZD7Uz8MZl7z/zNUjNpehDIe7oM8NXMt/i1DWqe
+XZoLfTdb7C77hgNfporBxkeqduhGGcu+RUgdAOMEJvFA4022iiZIJDkWeaiFZWI4
+iy9bmFd+VOXabCIAjb0Nl6F5TAROJ/mH9UjyT8hKlXYhnRu912+yEaFAlqiXk2rz
+kYbGGzj9zUMzClM52wJ7Btj50dz0eQIDAQABAoICAB62uHePEuRc84cCHqqoa8J7
+ODbN7NmfqTMm+FtKxwzXJhoof7OP2snu7nmuR4eTwO3/Z1TBqQco/RqfNbnqmY/H
+PPcDQSU0/VRJApiBHhIKZ2XLls0sgQl4ruxJ4sXZAuol1EHMSXP2guCB3gBzamvu
+ewxeZi+xB9Ag+Lz94vAmkIfStjIn0U4M3R69Nqw1+OOXsQehgBxzsBu/XweCpYvV
+Cg7rZNYHQlBcOB0ZfbQAP8fus+aXsOapzxxo4NA3NWYEjjcX+u0XC1dZMTQGnT9n
+QMr8srK9EzDnBr+ZyIrR3lAU1sDzGrioWemj7mzeNgzCKDHFbNbC2Z9ggdcwi/K+
+SX3ckR8phNkhGyIWImt5ChY19d/yh53A/FwFEJU4R/HiM0GFj8bxWMRr01R1TJV6
+UUb6c4L/T95URqe05bTAWz/BUUWirGs8F03NUp/8PvXquUJiKs3eEMHeyHDIt2Rj
+mB0bi+nr0qe4C7Y5yU9+Giw9RnV7slBkQvohA7mHXRlneenQx+Lh1v2fNk+Z+eVF
+Y7HBdTiNeavW8ZReoVgicqA8w2KZgbiDAhhJ2pzefpREjVAnY2endbMX4faqfEMF
+y6StIsg4rplrxojVIYftQ+nenSV0H+5I6+YsIk4XTirGYuBhccoko0ApRJx9VdX2
++UJU49UPHK2fTdqqouc5AoIBAQDmEqfyXQdf+5njZ3zx9cJFKRXB8SiFIDNZeSDL
+b8ph7py1YfinM163Xyb2/5oTB19tcNcfAaPoFOHJ8FDzXmSW3aUHKrB+sh8Q+aOH
+/3u6y2+dBEBNGPbtSxmMswVYK2z0K6NzzeZSZnqus0J61RPuG8EnO25PdMx9xOg/
+cPWTrxYNUYIBqSdhjm8K5BaTrkOf49Wur/0MZlcULVoatFzc3H/L3qyePvptKAwT
+V68bZeM2mXWhC3X953kxX5haClWZPJhf9sLESIeoOleaMi5yBvX6r7JKiFJy3Fwk
+dV7lPWr9fEkVtVoveHklCW8Ra6JbMizV7i1S5fmUcaUmgbbTAoIBAQDc1hTMI98o
+7hDEqh1cHtPmh1u9rLgJEMYLirUn/u4QDV6SUpT1Bpu55usLn+NFDyKfpEh1IU4r
+4CjfrjP15e2WLs+IOU+LvbDqbps7mEnq/TFWwr1YcjUVpur4SphJkqFHU/ztV6RC
+FbTA8656kb34YrILDnjgM7G1TKvWRHxzqdDCasPnlv7ch2/vtwv5zcVfTSNjixFb
+b8FCPy8WI6/LIFjKmSliLaeRb0NaUAWwMQ2qMEuP+rsGaq4Lr/6zf/UjSUcTgKzQ
+GSVm5cdJqjcqULFQzFZaOoG7Dht+ZJXumwc0G+k1eTuDAnYRs5CkEggtrnK9WfGm
+nBvGOAdeBvADAoIBAAPayCmNWXRIONnQgA1luq2B9LVdHvqsAXA8UUpXQyLE5qc7
+TvkuKSYVWAfHXIN5GiYxP8lrM53Ny8KgXhrVuAW3DO7DzlUxEsgsBotewmnswp/0
+1Eb2Zhyvp2vuC+bgQ2EL4h8skfFLej63DiQUsdLJcEECA+Uc5dgtll6Ju/OPeWUb
+unvgo6JEyqN6Es7CmqtxG8FjfW/Zvxe9cscDwpKItzNpNacpEvUFOL6SN4LUACyI
+AaqDEKUCXctv+JN5nNmGZF8nOTgkpvEwmQsiUBjk+PYMP4Z0Jj16Z6jMtpxMnSBG
+FstgUHR/JjhyogO+s+enPY0QAn5jD/1msgelILUCggEBAMV5emeBvFBxcfUq2c5C
+kuIWMGdQR9FzemVfx9bYFDGugt79kc359s8qOwzOEQD0I9X1pgV3ntuFO4ep0zUU
+QnyFp3b9KLChE87O0WldKNxFRRV8Vqz8k5OlC4Cz07IWuLl71TS3pl6h4lyYi3F3
+WhT+zI8uhdCW6VZiFVcpLtCPDeqMZlp1n7m8MtB9MuxSoSgzZm3hMcg+CucecRCv
+IMfXSQ8CHwt4H9vhTq032Z5QfxOs1CUP5KY8Rx6UZoJE7gR7xl8eNWpw0g1NdAPf
+fi0Ms0K5No7Aurl2SAeiEqCnaK2kN8plel4QmVwC4liU91NCJ8BC6eA+wGdkOtJO
+CdkCggEAG6v3cc6mw/kA3l+z21NzAXFUnYy7Q9xxl6noNBdNtT+vBQJ2jbEISSqi
+RM48KKtky2pgFWB980XUS1ZI8SiZ9GveM9bCSgpN+zupSdKNBaxT7+AKO/MPKMeO
+hukkWqtNCwFs6opByhLMRMC2UAKRSvTZBlrCUyIBY2EB6IzsqqQGdoAHOw2fDWay
+7C79JxtEl/XH10Et7zeWEI2uz6JK4TmSd2ZZu6m/X1UU6BHZJTHpItZlTnp14QYc
+hpHcRHU5d5i+ARQ+kUUynfEyAabY6sBIn3lxXqa9FplR0vqbtxyZPtQh1ZP11drD
+ihQEUR+haaYi8LFFpxe3Lja8D5eclg==
+-----END PRIVATE KEY-----
diff --git a/plat/arm/board/common/swd_rotpk/README b/plat/arm/board/common/swd_rotpk/README
index b628a5f..18fea4c 100644
--- a/plat/arm/board/common/swd_rotpk/README
+++ b/plat/arm/board/common/swd_rotpk/README
@@ -6,9 +6,12 @@
 
   openssl genrsa 2048 > arm_swd_rotprivk_rsa.pem
 
-* swd_rotpk_rsa_sha256.bin is the SHA-256 hash of the DER-encoded public key
-  associated with the above private key. It has been generated using the openssl
-  command line tool:
+* arm_swd_rotprivk_ecdsa.pem is a P-256 ECSA private key in PEM format. It has been
+  generated using the openssl command line tool:
+
+  openssl ecparam -name prime256v1 -genkey -outform PEM -noout -out arm_swd_rotprivk_ecdsa.pem
+
+* arm_swd_rotprivk_ecdsa_secp384r1.pem is a P-384 ECSA private key in PEM format. It has been
+  generated using the openssl command line tool:
 
-  openssl rsa -in arm_swd_rotprivk_rsa.pem -pubout -outform DER | \
-    openssl dgst -sha256 -binary > arm_swd_rotpk_rsa_sha256.bin
+  openssl ecparam -name secp384r1 -genkey -outform PEM -noout -out arm_swd_rotprivk_ecdsa_secp384r1.pem
diff --git a/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S b/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
index ae4f9d2..2056bbe 100644
--- a/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
+++ b/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,10 +9,31 @@
 
 	.section .rodata.arm_swd_rotpk_hash, "a"
 
+/*
+* The swd_roptpk header is dependent only on the algorithm used to
+* generate the hash.
+* ASN1_HASH_ALG is the last byte used to encode the OID for
+* the hash algorithm into the header,
+* this byte distinguishes between SHA256, SHA384 and SHA512.
+*/
+.equ HASH_ASN1_LEN, ARM_ROTPK_HASH_LEN
+#if ARM_ROTPK_HASH_LEN == 48
+	.equ ASN1_HASH_ALG, 0x02
+	.equ TOTAL_ASN1_LEN, 0x41
+#elif ARM_ROTPK_HASH_LEN == 64
+	.equ ASN1_HASH_ALG, 0x03
+	.equ TOTAL_ASN1_LEN, 0x51
+#elif ARM_ROTPK_HASH_LEN == 32
+	.equ ASN1_HASH_ALG, 0x01
+	.equ TOTAL_ASN1_LEN, 0x31
+#else
+	.error "Invalid SWD_ROTPK hash length."
+#endif
+
 arm_swd_rotpk_hash:
 	/* DER header. */
-	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
-	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	.byte 0x30, TOTAL_ASN1_LEN, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, ASN1_HASH_ALG, 0x05, 0x00, 0x04, HASH_ASN1_LEN
 	/* Key hash. */
-	.incbin ARM_SWD_ROTPK_HASH
+	.incbin ARM_SWD_ROTPK
 arm_swd_rotpk_hash_end:
diff --git a/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin b/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
deleted file mode 100644
index b2f3e60..0000000
--- a/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
+++ /dev/null
@@ -1 +0,0 @@
-0¾âÃ’æœÈË“(ì¨0ŠwIӁÕéã¡gk
\ No newline at end of file
diff --git a/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa.pem b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa.pem
new file mode 100644
index 0000000..be40565
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIFmIjAPUmyqDfKXT+kKRMvyFzQfaZekczIzSPfLeQUGyoAoGCCqGSM49
+AwEHoUQDQgAEtZB8OrBV7hPl+lBrc5ypKetwGsUi+SpTK8OoMw0GwA17rGDYdBTV
+JK2ttZNtCsGzlDrXeHu6bcTmrleMdW9NdQ==
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa_secp384r1.pem b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa_secp384r1.pem
new file mode 100644
index 0000000..14ad7f7
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_ecdsa_secp384r1.pem
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDC348NhWsLI30vzJnWofKae6t3S6YIb5rdLEJSUyI9XwKj8FyJO8N3G
+DNgvVBwk4NigBwYFK4EEACKhZANiAARodLWP/EGH7/SrImvwDJr1zACOrh8acVH/
+eymfvZW2af4DPRMPyUC5Ftzv6NwGz6yPzBbAg9+qDgLgO7cqwXOwVON+hAU+ECEZ
+3AIQ7zLDfnXcfNz8dv1kwkwhfDJeQCs=
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts b/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts
new file mode 100644
index 0000000..df6810f
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_stmm_manifest.dts
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+#include <platform_def.h>
+
+/ {
+#define MODE_SEL0	(0x1)
+#define MODE_SEL1	(0x2)
+
+#define SECURE_RO 0x1
+#define SECURE_RW 0x3
+#define SECURE_EXECUTE_RO 0x5
+#define SECURE_EXECUTE_RW 0x7
+#define NON_SECURE_RO 0x9
+#define NON_SECURE_RW 0xB
+#define NON_SECURE_EXECUTE_RO 0xD
+#define NON_SECURE_EXECUTE_RW 0xF
+	/*
+	 * FF-A compatible Secure Partition Manager parses the
+	 * config file and fetch the following booting arguments to
+	 * pass on to the StandAloneMM(StMM) Secure Partition.
+	 */
+	compatible = "arm,ffa-manifest-1.0";
+
+	description = "FVP Base StandaloneMm";
+	ffa-version = <0x00010002>; /* 31:16 - Major, 15:0 - Minor */
+	uuid = <0xdcae8d37 0x46446bf0 0xab401483 0xa3873c93>;
+	id = <0x8001>;
+	execution-ctx-count = <PLATFORM_CORE_COUNT>;
+	exception-level = <MODE_SEL0>; /* SEL0*/
+	execution-state = <0>; /* AArch64*/
+	load-address = <0x0 0xff200000>;
+	image-size = <0x0 0x00300000>;
+	xlat-granule = <0>; /* 4KiB */
+	boot-order = <0>;
+	messaging-method = <0x603>; /* Direct req/resp/req2/resp2 supported. */
+	gp-register-num = <0>;
+
+	device-regions {
+		compatible = "arm,ffa-manifest-device-regions";
+
+		/**
+		 * System registers, rtc, uart and etc regions for access from S-EL0.
+		 */
+		io_fpga {
+			base-address = <0x0 0x1C000000>;
+			pages-count = <0x3000>;
+			attributes = <SECURE_RW>;
+		};
+
+		system_reg_el0 {
+			base-address = <0x0 0x1C010000>;
+			pages-count = <0x10>;
+			attributes = <SECURE_RW>;
+		};
+
+		/**
+		 * ARM CSS SoC Peripherals area.
+		 * Similar to SOC_CSS_MAP_DEVICE.
+		 */
+		soc_components {
+			base-address = <0x0 0x20000000>;
+			pages-count = <0xc200>;
+			attributes = <SECURE_RO>;
+		};
+
+		/**
+		 * NOR0 Flash region, used for Firmware Image Update.
+		 */
+		nor_flash0 {
+			base-address = <0x0 0x08000000>;
+			pages-count = <0x4000>;
+			attributes = <SECURE_RW>;
+		};
+
+		/**
+		 * NOR1 Flash region, used for Secure booting.
+		 */
+		nor_flash1 {
+			base-address = <0x0 0x0c000000>;
+			pages-count = <0x4000>;
+			attributes = <SECURE_RW>;
+		};
+	};
+
+	memory-regions {
+		compatible = "arm,ffa-manifest-memory-regions";
+
+		/*
+		 * SPM Payload memory. Mapped as code region for S-EL0
+		 * Similar to ARM_SP_IMAGE_MMAP.
+		 */
+		stmm_region {
+			description = "image";
+			base-address = <0x0 0xff200000>;
+			pages-count = <0x300>;
+			/* StMM will remap the regions during runtime */
+			attributes = <SECURE_EXECUTE_RO>;
+		};
+
+		/*
+		 * Memory shared between EL3 and S-EL0.
+		 * Similar to ARM_SPM_BUF_EL0_MMAP.
+		 */
+		rx-tx-buffers {
+			description = "shared-buff";
+			base-address = <0x0 0xff500000>;
+			pages-count = <0x100>;
+			attributes = <SECURE_RW>;
+		};
+
+		/*
+		 * Memory shared between Normal world and S-EL0.
+		 * Similar to ARM_SP_IMAGE_NS_BUF_MMAP.
+		 */
+		ns_comm_buffer {
+			/*
+			 * Description is needed for StMM to identify
+			 * ns-communication buffer.
+			 */
+			description = "ns-comm";
+			base-address = <0x0 0xff600000>;
+			pages-count = <0x10>;
+			attributes = <NON_SECURE_RW>;
+		};
+
+		/*
+		 * Heap used by SP to allocate memory for DMA.
+		 */
+		heap {
+			/*
+			 * Description is needed for StMM to identify
+			 * heap buffer.
+			 */
+			description = "heap";
+			base-address = <0x0 0xFF610000>;
+			pages-count = <0x7F0>;
+			attributes = <SECURE_RW>;
+		};
+	};
+};
diff --git a/plat/arm/board/fvp/fvp_security.c b/plat/arm/board/fvp/fvp_security.c
index 573d92e..5b97034 100644
--- a/plat/arm/board/fvp/fvp_security.c
+++ b/plat/arm/board/fvp/fvp_security.c
@@ -24,7 +24,7 @@
 
 	const arm_tzc_regions_info_t fvp_tzc_regions[] = {
 		ARM_TZC_REGIONS_DEF,
-#if !SPM_MM && !ENABLE_RME
+#if !SPM_MM && !ENABLE_RME && !(SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
 		{FVP_DRAM3_BASE, FVP_DRAM3_END,
 		 ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},
 		{FVP_DRAM4_BASE, FVP_DRAM4_END,
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index e0c9725..df4be8f 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -170,6 +170,8 @@
 # elif SPMC_AT_EL3
 #  define PLAT_ARM_MMAP_ENTRIES		13
 #  define MAX_XLAT_TABLES		11
+#  define PLAT_SP_IMAGE_MMAP_REGIONS	30
+#  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
 # else
 #  define PLAT_ARM_MMAP_ENTRIES		9
 #  if USE_DEBUGFS
@@ -220,7 +222,8 @@
  * In case of PSA Crypto API, few algorithms like ECDSA needs bigger BL1 RW
  * area.
  */
-#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA || PSA_CRYPTO
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA || PSA_CRYPTO || \
+FVP_TRUSTED_SRAM_SIZE == 512
 #define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xC000)
 #else
 #define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xB000)
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 08fbfee..8793840 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/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
 #
@@ -22,7 +22,12 @@
 # only; enable redistributor frames of all CPU cores by default.
 FVP_GICR_REGION_PROTECTION	:= 0
 
+ifeq (${HW_ASSISTED_COHERENCY}, 0)
 FVP_DT_PREFIX			:= fvp-base-gicv3-psci
+else
+FVP_DT_PREFIX			:= fvp-base-gicv3-psci-dynamiq
+endif
+# fdts is wrong otherwise
 
 # Size (in kilobytes) of the Trusted SRAM region to  utilize when building for
 # the FVP platform. This option defaults to 256.
@@ -58,6 +63,7 @@
       ENABLE_TRBE_FOR_NS	:= 2
       ENABLE_FEAT_D128		:= 2
       ENABLE_FEAT_FPMR		:= 2
+      ENABLE_FEAT_MOPS		:= 2
 endif
 
 ENABLE_SYS_REG_TRACE_FOR_NS	:= 2
@@ -338,7 +344,6 @@
 endif
 
 # Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
-ifdef UNIX_MK
 FVP_HW_CONFIG_DTS	:=	fdts/${FVP_DT_PREFIX}.dts
 
 FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
@@ -390,7 +395,6 @@
 
 # Add the HW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config,${FVP_HW_CONFIG}))
-endif
 
 ifeq (${TRANSFER_LIST}, 1)
 include lib/transfer_list/transfer_list.mk
diff --git a/plat/arm/board/juno/juno_trusted_boot.c b/plat/arm/board/juno/juno_trusted_boot.c
index c730406..2ead454 100644
--- a/plat/arm/board/juno/juno_trusted_boot.c
+++ b/plat/arm/board/juno/juno_trusted_boot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,9 +14,9 @@
 
 #if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
 
-static unsigned char rotpk_hash_der[ARM_ROTPK_HEADER_LEN + ARM_ROTPK_HASH_LEN];
+static unsigned char rotpk_hash_der[ARM_ROTPK_HASH_DER_HEADER_LEN + ARM_ROTPK_HASH_LEN];
 
-extern unsigned char arm_rotpk_header[];
+extern unsigned char arm_rotpk_hash_der_header[];
 
 /*
  * Return the ROTPK hash stored in the registers of Juno board.
@@ -33,8 +33,8 @@
 	assert(flags != NULL);
 
 	/* Copy the DER header */
-	memcpy(rotpk_hash_der, arm_rotpk_header, ARM_ROTPK_HEADER_LEN);
-	dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HEADER_LEN];
+	memcpy(rotpk_hash_der, arm_rotpk_hash_der_header, ARM_ROTPK_HASH_DER_HEADER_LEN);
+	dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HASH_DER_HEADER_LEN];
 
 
 	/*
diff --git a/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
index bce8834..39a86b1 100644
--- a/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
@@ -152,6 +152,9 @@
 	nrd_plat_info.config_id = plat_arm_nrd_get_config_id();
 	nrd_plat_info.multi_chip_mode = plat_arm_nrd_get_multi_chip_mode();
 
+	/* Initialize generic timer */
+	generic_delay_timer_init();
+
 	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
 }
 
@@ -216,7 +219,6 @@
 
 void nrd_bl31_common_platform_setup(void)
 {
-	generic_delay_timer_init();
 
 	arm_bl31_platform_setup();
 
diff --git a/plat/arm/board/tc/include/platform_def.h b/plat/arm/board/tc/include/platform_def.h
index 5a22628..71f7bb3 100644
--- a/plat/arm/board/tc/include/platform_def.h
+++ b/plat/arm/board/tc/include/platform_def.h
@@ -259,7 +259,7 @@
 #define PLAT_ARM_DRAM2_SIZE             ULL(0x180000000)
 #elif TARGET_PLATFORM >= 3
 
-#if TC_FPGA_ANDROID_IMG_IN_RAM
+#if TC_FPGA_FS_IMG_IN_RAM
 /* 10GB reserved for system+userdata+vendor images */
 #define SYSTEM_IMAGE_SIZE		0xC0000000	/* 3GB */
 #define USERDATA_IMAGE_SIZE		0x140000000	/* 5GB */
@@ -273,8 +273,8 @@
 #define PLAT_ARM_DRAM2_SIZE		ULL(0x380000000) - ANDROID_FS_SIZE
 #else
 #define PLAT_ARM_DRAM2_BASE             ULL(0x880000000)
-#define PLAT_ARM_DRAM2_SIZE             ULL(0x380000000)
-#endif /* TC_FPGA_ANDROID_IMG_IN_RAM */
+#define PLAT_ARM_DRAM2_SIZE             ULL(0x180000000)
+#endif /* TC_FPGA_FS_IMG_IN_RAM */
 
 #endif /* TARGET_VERSION >= 3 */
 
@@ -443,18 +443,22 @@
 #undef PLAT_ARM_BOOT_UART_CLK_IN_HZ
 #undef PLAT_ARM_RUN_UART_CLK_IN_HZ
 
+#undef  ARM_CONSOLE_BAUDRATE
+#define ARM_CONSOLE_BAUDRATE		38400
+
+#if TARGET_PLATFORM <= 2
+#define TC_UARTCLK			5000000
+#elif TARGET_PLATFORM == 3
+#define TC_UARTCLK			3750000
+#elif TARGET_PLATFORM == 4
+#define TC_UARTCLK			4000000
+#endif /* TARGET_PLATFORM <=2 */
+
+
 #if TARGET_FLAVOUR_FVP
 #define PLAT_ARM_BOOT_UART_BASE		TC_UART1
-#define TC_UARTCLK			7372800
 #else /* TARGET_FLAVOUR_FPGA */
 #define PLAT_ARM_BOOT_UART_BASE		TC_UART0
-#if TARGET_PLATFORM <= 2
-#define TC_UARTCLK			5000000
-#elif TARGET_PLATFORM >= 3
-#define TC_UARTCLK			3750000
-#endif /* TARGET_PLATFORM >= 3 */
-#undef  ARM_CONSOLE_BAUDRATE
-#define ARM_CONSOLE_BAUDRATE		38400
 #endif /* TARGET_FLAVOUR_FPGA */
 
 #define PLAT_ARM_RUN_UART_BASE		TC_UART0
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 759c85d..1ec7c44 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -77,8 +77,8 @@
         $(error TARGET_FLAVOUR must be fvp or fpga)
 endif
 
-# Support for loading Android Image to DRAM
-TC_FPGA_ANDROID_IMG_IN_RAM := 0
+# Support for loading FS Image to DRAM
+TC_FPGA_FS_IMG_IN_RAM := 0
 
 # Support Loading of FIP image to DRAM
 TC_FPGA_FIP_IMG_IN_RAM := 0
@@ -92,7 +92,7 @@
 	TC_RESOLUTION_$(call uppercase,${TC_RESOLUTION}) \
 	TC_DPU_USE_SCMI_CLK \
 	TC_SCMI_PD_CTRL_EN \
-	TC_FPGA_ANDROID_IMG_IN_RAM \
+	TC_FPGA_FS_IMG_IN_RAM \
 	TC_FPGA_FIP_IMG_IN_RAM \
 	TC_DPU_USE_SIMPLE_PANEL \
 ))
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 07b3b62..17dc0ed 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -52,17 +52,10 @@
 #pragma weak bl2_plat_arch_setup
 #pragma weak bl2_plat_sec_mem_layout
 
-#if ENABLE_RME
 #define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
 					bl2_tzram_layout.total_base,	\
 					bl2_tzram_layout.total_size,	\
-					MT_MEMORY | MT_RW | MT_ROOT)
-#else
-#define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
-					bl2_tzram_layout.total_base,	\
-					bl2_tzram_layout.total_size,	\
-					MT_MEMORY | MT_RW | MT_SECURE)
-#endif /* ENABLE_RME */
+					MT_MEMORY | MT_RW | EL3_PAS)
 
 #pragma weak arm_bl2_plat_handle_post_image_load
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 2fd993c..580ef5f 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -363,7 +363,7 @@
 endif
 
 # Pointer Authentication sources
-ifeq (${ENABLE_PAUTH}, 1)
+ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3))
 PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
 endif
 
@@ -382,12 +382,14 @@
 ifneq ($(filter 1,${MEASURED_BOOT} ${TRUSTED_BOARD_BOOT} ${DRTM_SUPPORT}),)
     PLAT_INCLUDES		+=	-Iplat/arm/common	\
 					-Iinclude/drivers/auth/mbedtls
-    # Specify mbed TLS configuration file
-    ifeq (${PSA_CRYPTO},1)
-      MBEDTLS_CONFIG_FILE	?=	"<plat_arm_psa_mbedtls_config.h>"
+    ifeq (${HASH_ALG}, sha512)
+      ARM_ROTPK_HASH_LEN	:=	64
+    else ifeq (${HASH_ALG}, sha384)
+      ARM_ROTPK_HASH_LEN	:=	48
     else
-      MBEDTLS_CONFIG_FILE	?=	"<plat_arm_mbedtls_config.h>"
+      ARM_ROTPK_HASH_LEN	:=	32
     endif
+    $(eval $(call add_define,ARM_ROTPK_HASH_LEN))
 endif
 
 ifneq (${TRUSTED_BOARD_BOOT},0)
diff --git a/plat/arm/common/arm_ni.c b/plat/arm/common/arm_ni.c
index b3ad8b3..9c105f7 100644
--- a/plat/arm/common/arm_ni.c
+++ b/plat/arm/common/arm_ni.c
@@ -144,19 +144,33 @@
 
 	for (uint32_t i = 0U; i < vd_count; i++) {
 		vd_addr = global_cfg + mmio_read_32(global_cfg + NI_CHILD_POINTER(i));
+
+		VERBOSE("Voltage domain %u at 0x%lx node info: 0x%x\n",
+			i, vd_addr, mmio_read_32(vd_addr));
+
 		pd_count = mmio_read_32(vd_addr + NI_CHILD_NODE_COUNT);
 
 		for (uint32_t j = 0U; j < pd_count; j++) {
 			pd_addr = global_cfg + mmio_read_32(vd_addr + NI_CHILD_POINTER(j));
 			cd_count = mmio_read_32(pd_addr + NI_CHILD_NODE_COUNT);
 
+			VERBOSE("Power domain %u at 0x%lx node info: 0x%x\n",
+				j, pd_addr, mmio_read_32(pd_addr));
+
 			for (uint32_t k = 0U; k < cd_count; k++) {
 				cd_addr = global_cfg + mmio_read_32(pd_addr + NI_CHILD_POINTER(k));
 				comp_count = mmio_read_32(cd_addr + NI_CHILD_NODE_COUNT);
 
+				VERBOSE("Clock domain %u at 0x%lx node info: 0x%x\n",
+					k, cd_addr, mmio_read_32(cd_addr));
+
 				for (uint32_t l = 0U; l < comp_count; l++) {
 					comp_addr = global_cfg +
 						mmio_read_32(cd_addr + NI_CHILD_POINTER(l));
+
+					VERBOSE("Component %u at 0x%lx node info: 0x%x\n",
+						l, comp_addr, mmio_read_32(comp_addr));
+
 					ni_setup_component(comp_addr);
 				}
 			}
diff --git a/plat/arm/common/plat_arm_mbedtls_config.h b/plat/arm/common/plat_arm_mbedtls_config.h
deleted file mode 100644
index c2db595..0000000
--- a/plat/arm/common/plat_arm_mbedtls_config.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2024, Arm Ltd. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PLAT_ARM_MBEDTLS_CONFIG_H
-#define PLAT_ARM_MBEDTLS_CONFIG_H
-
-#include <default_mbedtls_config.h>
-
-/**
- * On Arm platforms, the ROTPK is always hashed using the SHA-256
- * algorithm.
- * TODO: Update to hash the ROTPK with the selected HASH_ALG to avoid
- * the need for explicitly enabling the SHA-256 configuration in mbedTLS.
- */
-#define MBEDTLS_SHA256_C
-
-/*
- * Use an implementation of SHA-256 with a smaller memory footprint
- * but reduced speed.
- */
-#define MBEDTLS_SHA256_SMALLER
-
-#endif /* PLAT_ARM_MBEDTLS_CONFIG_H */
diff --git a/plat/arm/common/plat_arm_psa_mbedtls_config.h b/plat/arm/common/plat_arm_psa_mbedtls_config.h
deleted file mode 100644
index b7a4bf1..0000000
--- a/plat/arm/common/plat_arm_psa_mbedtls_config.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2024, Arm Ltd. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PLAT_ARM_PSA_MBEDTLS_CONFIG_H
-#define PLAT_ARM_PSA_MBEDTLS_CONFIG_H
-
-#include "plat_arm_mbedtls_config.h"
-
-#define MBEDTLS_PSA_CRYPTO_C
-#define MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS
-
-/*
- * Using PSA crypto API requires an RNG right now. If we don't define the macro
- * below then we get build errors.
- *
- * This is a functionality gap in mbedTLS. The technical limitation is that
- * psa_crypto_init() is all-or-nothing, and fixing that would require separate
- * initialization of the keystore, the RNG, etc.
- *
- * By defining MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG, we pretend using an external
- * RNG. As a result, the PSA crypto init code does nothing when it comes to
- * initializing the RNG, as we are supposed to take care of that ourselves.
- */
-#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
-
-/*
- * Override heap size for PSA Crypto when RSA key size > 2048.
- */
-#if TF_MBEDTLS_USE_RSA && TF_MBEDTLS_KEY_SIZE > 2048
-#undef TF_MBEDTLS_HEAP_SIZE
-#define TF_MBEDTLS_HEAP_SIZE        U(12 * 1024)
-#endif
-
-#endif /* PLAT_ARM_PSA_MBEDTLS_CONFIG_H */
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
index a603f2b..dbb6f81 100644
--- a/plat/common/plat_bl_common.c
+++ b/plat/common/plat_bl_common.c
@@ -9,6 +9,7 @@
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <lib/transfer_list.h>
 #include <lib/xlat_tables/xlat_tables_compat.h>
 #include <plat/common/platform.h>
 #include <services/arm_arch_svc.h>
@@ -129,3 +130,13 @@
 	/* Create the page tables to reflect the above mappings */
 	init_xlat_tables();
 }
+
+#if ((MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT) && TRANSFER_LIST)
+int plat_handoff_mboot(const void *data, uint32_t data_size, void *tl_base)
+{
+	if (!transfer_list_add(tl_base, TL_TAG_TPM_EVLOG, data_size, data))
+		return -1;
+
+	return 0;
+}
+#endif
diff --git a/plat/intel/soc/agilex5/bl31_plat_setup.c b/plat/intel/soc/agilex5/bl31_plat_setup.c
index c090117..ab03928 100644
--- a/plat/intel/soc/agilex5/bl31_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl31_plat_setup.c
@@ -196,6 +196,9 @@
 	NOTICE("BL31: CPU ID = %x\n", cpuid);
 	INFO("BL31: Invalidate Data cache\n");
 	invalidate_dcache_all();
+
+	/* Invalidate for NS EL2 and EL1 */
+	invalidate_cache_low_el();
 }
 
 /* Get non-secure image entrypoint for BL33. Zephyr and Linux */
diff --git a/plat/intel/soc/agilex5/soc/agilex5_cache.S b/plat/intel/soc/agilex5/soc/agilex5_cache.S
index 52ed5d3..f8c6a2d 100644
--- a/plat/intel/soc/agilex5/soc/agilex5_cache.S
+++ b/plat/intel/soc/agilex5/soc/agilex5_cache.S
@@ -15,14 +15,16 @@
 	 * --------------------------------------------------------
 	 */
 func invalidate_cache_low_el
-	mrs	x0,SCR_EL3
-	orr	x1,x0,#SCR_NS_BIT
+	mrs	x0, SCR_EL3
+	orr	x1, x0, #SCR_NS_BIT
 	msr	SCR_EL3, x1
 	isb
 	tlbi	ALLE2
 	dsb	sy
 	tlbi	ALLE1
 	dsb	sy
+	msr	SCR_EL3, x0
+	isb
 endfunc invalidate_cache_low_el
 
 .pushsection .text.asm_dcache_level, "ax"
diff --git a/plat/mediatek/build_helpers/mtk_build_helpers.mk b/plat/mediatek/build_helpers/mtk_build_helpers.mk
index 0cb2014..a095ba9 100644
--- a/plat/mediatek/build_helpers/mtk_build_helpers.mk
+++ b/plat/mediatek/build_helpers/mtk_build_helpers.mk
@@ -71,8 +71,9 @@
         $(eval SOURCES    := $(2))
         $(eval OBJS_TEMP  := $(addprefix $(BUILD_DIR)/$(MODULE)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
         $(eval MODULE_OBJS += $(OBJS_TEMP))
+        $(eval BL         := $(call uppercase,$(3)))
 
-$(eval $(call MAKE_OBJS,$(BUILD_DIR)/$(MODULE),$(SOURCES),${3}))
+$(eval $(call MAKE_OBJS,$(BUILD_DIR)/$(MODULE),$(SOURCES),${3},$(BL)))
 
 libraries: $(OBJS_TEMP)
 endef
diff --git a/plat/mediatek/drivers/apusys/apusys.c b/plat/mediatek/drivers/apusys/apusys.c
index dfe1dcf..87e8960 100644
--- a/plat/mediatek/drivers/apusys/apusys.c
+++ b/plat/mediatek/drivers/apusys/apusys.c
@@ -30,10 +30,10 @@
 
 	switch (request_ops) {
 	case MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_ON:
-		ret = apusys_kernel_apusys_pwr_top_on();
+		ret = apusys_kernel_apusys_rv_pwr_ctrl(APU_PWR_ON);
 		break;
 	case MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_OFF:
-		ret = apusys_kernel_apusys_pwr_top_off();
+		ret = apusys_kernel_apusys_rv_pwr_ctrl(APU_PWR_OFF);
 		break;
 	case MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_REVISER:
 		ret = apusys_kernel_apusys_rv_setup_reviser();
@@ -68,6 +68,27 @@
 	case MTK_APUSYS_KERNEL_OP_APUSYS_RV_CG_UNGATING:
 		ret = apusys_kernel_apusys_rv_cg_ungating();
 		break;
+	case MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_APUMMU:
+		ret = apusys_kernel_apusys_rv_setup_apummu();
+		break;
+#ifdef CONFIG_MTK_APUSYS_LOGTOP_SUPPORT
+	case MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_DUMP:
+		ret = apusys_kernel_apusys_logtop_reg_dump((uint32_t)x2, smccc_ret);
+		break;
+	case MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_WRITE:
+		ret = apusys_kernel_apusys_logtop_reg_write((uint32_t)x2, (uint32_t)x3,
+							    smccc_ret);
+		break;
+	case MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_W1C:
+		ret = apusys_kernel_apusys_logtop_reg_w1c((uint32_t)x2, smccc_ret);
+		break;
+#endif
+	case MTK_APUSYS_KERNEL_OP_APUSYS_COLD_BOOT_CLR_MBOX_DUMMY:
+		ret = apusys_rv_cold_boot_clr_mbox_dummy();
+		break;
+	case MTK_APUSYS_KERNEL_OP_APUSYS_SETUP_CE_BIN:
+		ret = apusys_rv_setup_ce_bin();
+		break;
 	default:
 		ERROR(MODULE_TAG "%s unknown request_ops = %x\n", MODULE_TAG, request_ops);
 		break;
diff --git a/plat/mediatek/drivers/apusys/apusys.h b/plat/mediatek/drivers/apusys/apusys.h
index ed4e195..709379e 100644
--- a/plat/mediatek/drivers/apusys/apusys.h
+++ b/plat/mediatek/drivers/apusys/apusys.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,19 +10,25 @@
 #define MODULE_TAG "[APUSYS]"
 
 enum MTK_APUSYS_KERNEL_OP {
-	MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_ON,		/*  0 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_OFF,	/*  1 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_REVISER,	/*  2 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_RESET_MP,	/*  3 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_BOOT,	/*  4 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_START_MP,	/*  5 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_STOP_MP,		/*  6 */
-	MTK_APUSYS_KERNEL_OP_DEVAPC_INIT_RCX,		/*  7 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_SEC_MEM,	/*  8 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_DISABLE_WDT_ISR,	/*  9 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CLEAR_WDT_ISR,	/* 10 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CG_GATING,	/* 11 */
-	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CG_UNGATING,	/* 12 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_ON,			/*  0 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_PWR_TOP_OFF,		/*  1 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_REVISER,		/*  2 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_RESET_MP,		/*  3 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_BOOT,		/*  4 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_START_MP,		/*  5 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_STOP_MP,			/*  6 */
+	MTK_APUSYS_KERNEL_OP_DEVAPC_INIT_RCX,			/*  7 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_SEC_MEM,		/*  8 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_DISABLE_WDT_ISR,		/*  9 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CLEAR_WDT_ISR,		/* 10 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CG_GATING,		/* 11 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_CG_UNGATING,		/* 12 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_RV_SETUP_APUMMU,		/* 13 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_DUMP,		/* 14 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_WRITE,		/* 15 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_LOGTOP_REG_W1C,		/* 16 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_COLD_BOOT_CLR_MBOX_DUMMY,	/* 17 */
+	MTK_APUSYS_KERNEL_OP_APUSYS_SETUP_CE_BIN,		/* 18 */
 	MTK_APUSYS_KERNEL_OP_NUM,
 };
 
diff --git a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.c b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.c
index cb57668..a9eebb5 100644
--- a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.c
+++ b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.c
@@ -1,9 +1,11 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <errno.h>
+
 /* TF-A system header */
 #include <common/debug.h>
 #include <drivers/delay_timer.h>
@@ -14,7 +16,19 @@
 #include "apusys.h"
 #include "apusys_rv.h"
 #include "apusys_rv_mbox_mpu.h"
-#include "emi_mpu.h"
+#include "apusys_rv_pwr_ctrl.h"
+#include "apusys_rv_sec_info.h"
+#ifdef CONFIG_MTK_APUSYS_SEC_CTRL
+#include "apusys_security_ctrl_perm.h"
+#endif
+#include "apusys_security_ctrl_plat.h"
+#include <drivers/apusys_rv_public.h>
+#include <mtk_mmap_pool.h>
+#include <mtk_sip_svc.h>
+
+#ifdef CONFIG_MTK_APUSYS_RV_APUMMU_SUPPORT
+#include "apusys_ammu.h"
+#endif
 
 static spinlock_t apusys_rv_lock;
 
@@ -94,6 +108,8 @@
 		      (PREDEFINE_CACHE << PREDEF_2G_OFS) | (PREDEFINE_CACHE << PREDEF_3G_OFS) |
 		      (PREDEFINE_CACHE << PREDEF_4G_OFS));
 
+	apusys_infra_dcm_setup();
+
 	spin_unlock(&apusys_rv_lock);
 	return 0;
 }
@@ -104,28 +120,67 @@
 	mmio_write_32(MD32_RUNSTALL, MD32_RUN);
 	spin_unlock(&apusys_rv_lock);
 
+	return 0;
+}
+
+static int hw_sema2_release(uint32_t timeout)
+{
+#ifdef CONFIG_MTK_APUSYS_RV_COREDUMP_WA_SUPPORT
+	int ret;
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_USER, 0, timeout, 0);
+	if (ret) {
+		ERROR("%s: HW semaphore release timeout\n", __func__);
+	}
+
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+static int hw_sema2_acquire(uint32_t timeout)
+{
+#ifdef CONFIG_MTK_APUSYS_RV_COREDUMP_WA_SUPPORT
+	int ret;
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_USER, 1, timeout, 0);
+	if (ret) {
+		ERROR("%s: HW semaphore acquire timeout\n", __func__);
+	}
+
+	return ret;
+#else
 	return 0;
+#endif
 }
 
 int apusys_kernel_apusys_rv_stop_mp(void)
 {
+	int ret;
+
+	ret = hw_sema2_acquire(HW_SEM_TIMEOUT);
+	if (ret)
+		return ret;
+
 	spin_lock(&apusys_rv_lock);
 	mmio_write_32(MD32_RUNSTALL, MD32_STALL);
 	spin_unlock(&apusys_rv_lock);
 
-	return 0;
+	ret = hw_sema2_release(HW_SEM_TIMEOUT);
+
+	return ret;
 }
 
 int apusys_kernel_apusys_rv_setup_sec_mem(void)
 {
-	int ret;
+	int ret = 0;
 
 	spin_lock(&apusys_rv_lock);
 
-	ret = set_apu_emi_mpu_region();
-	if (ret != 0) {
+	ret = apusys_plat_setup_sec_mem();
+	if (ret != 0)
 		ERROR(MODULE_TAG "%s: set emimpu protection failed\n", __func__);
-	}
 
 	spin_unlock(&apusys_rv_lock);
 	return ret;
@@ -133,37 +188,312 @@
 
 int apusys_kernel_apusys_rv_disable_wdt_isr(void)
 {
+	int ret;
+
+	ret = hw_sema2_acquire(0);
+	if (ret)
+		return ret;
+
 	spin_lock(&apusys_rv_lock);
 	mmio_clrbits_32(WDT_CTRL0, WDT_EN);
 	spin_unlock(&apusys_rv_lock);
 
-	return 0;
+	ret = hw_sema2_release(0);
+
+	return ret;
 }
 
 int apusys_kernel_apusys_rv_clear_wdt_isr(void)
 {
+	int ret;
+
+	ret = hw_sema2_acquire(HW_SEM_TIMEOUT);
+	if (ret)
+		return ret;
+
 	spin_lock(&apusys_rv_lock);
 	mmio_clrbits_32(UP_INT_EN2, DBG_APB_EN);
 	mmio_write_32(WDT_INT, WDT_INT_W1C);
 	spin_unlock(&apusys_rv_lock);
 
-	return 0;
+	ret = hw_sema2_release(HW_SEM_TIMEOUT);
+
+	return ret;
 }
 
 int apusys_kernel_apusys_rv_cg_gating(void)
 {
+	int ret;
+
+	ret = hw_sema2_acquire(HW_SEM_TIMEOUT);
+	if (ret)
+		return ret;
+
 	spin_lock(&apusys_rv_lock);
 	mmio_write_32(MD32_CLK_CTRL, MD32_CLK_DIS);
 	spin_unlock(&apusys_rv_lock);
 
-	return 0;
+	ret = hw_sema2_release(HW_SEM_TIMEOUT);
+
+	return ret;
 }
 
 int apusys_kernel_apusys_rv_cg_ungating(void)
 {
+	int ret;
+
+	ret = hw_sema2_acquire(HW_SEM_TIMEOUT);
+	if (ret)
+		return ret;
+
 	spin_lock(&apusys_rv_lock);
 	mmio_write_32(MD32_CLK_CTRL, MD32_CLK_EN);
 	spin_unlock(&apusys_rv_lock);
+
+	ret = hw_sema2_release(HW_SEM_TIMEOUT);
+
+	return ret;
+}
+
+int apusys_kernel_apusys_rv_setup_apummu(void)
+{
+	spin_lock(&apusys_rv_lock);
+
+#ifdef CONFIG_MTK_APUSYS_SEC_CTRL
+	sec_set_rv_dns();
+#endif
+
+#ifdef CONFIG_MTK_APUSYS_RV_APUMMU_SUPPORT
+	uint32_t apummu_tcm_sz_select = 0;
+
+	if (APU_MD32_TCM_SZ <= 0x20000)
+		apummu_tcm_sz_select = APUMMU_PAGE_LEN_128KB;
+	else if (APU_MD32_TCM_SZ <= 0x40000)
+		apummu_tcm_sz_select = APUMMU_PAGE_LEN_256KB;
+	else if (APU_MD32_TCM_SZ <= 0x80000)
+		apummu_tcm_sz_select = APUMMU_PAGE_LEN_512KB;
+	else if (APU_MD32_TCM_SZ <= 0x100000)
+		apummu_tcm_sz_select = APUMMU_PAGE_LEN_1MB;
+	else {
+		ERROR("%s: APU_MD32_TCM_SZ = 0x%x > 1MB", __func__, APU_MD32_TCM_SZ);
+		spin_unlock(&apusys_rv_lock);
+		return -EINVAL;
+	}
+
+	INFO("%s: apummu_tcm_sz_select = %u\n", __func__, apummu_tcm_sz_select);
+	rv_boot(APU_SEC_FW_IOVA, 0, APUMMU_PAGE_LEN_1MB,
+		APU_MD32_TCM, apummu_tcm_sz_select);
+#endif
+
+	spin_unlock(&apusys_rv_lock);
+	return 0;
+}
+
+int apusys_kernel_apusys_rv_pwr_ctrl(enum APU_PWR_OP op)
+{
+	return apusys_rv_pwr_ctrl(op);
+}
+
+#ifdef CONFIG_MTK_APUSYS_LOGTOP_SUPPORT
+int apusys_kernel_apusys_logtop_reg_dump(uint32_t op, struct smccc_res *smccc_ret)
+{
+	int ret = 0;
+	uint8_t smc_op;
+	uint32_t reg_addr[MAX_SMC_OP_NUM];
+	uint32_t i;
+
+	if (op == 0) {
+		ERROR("%s empty op = 0x%08x\n", MODULE_TAG, op);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_SMC_OP_NUM; i++) {
+		smc_op = (op >> (LOGTOP_OP_SHIFT * i)) & LOGTOP_OP_MASK;
+		switch (smc_op) {
+		case SMC_OP_APU_LOG_BUF_NULL:
+			reg_addr[i] = 0x0;
+			break;
+		case SMC_OP_APU_LOG_BUF_T_SIZE:
+			reg_addr[i] = APU_LOG_BUF_T_SIZE;
+			break;
+		case SMC_OP_APU_LOG_BUF_W_PTR:
+			reg_addr[i] = APU_LOG_BUF_W_PTR;
+			break;
+		case SMC_OP_APU_LOG_BUF_R_PTR:
+			reg_addr[i] = APU_LOG_BUF_R_PTR;
+			break;
+		case SMC_OP_APU_LOG_BUF_CON:
+			reg_addr[i] = APU_LOGTOP_CON;
+			break;
+		default:
+			ERROR("%s unknown op = 0x%08x\n", MODULE_TAG, smc_op);
+			return -EINVAL;
+		}
+	}
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_LOGGER_USER, 1, 0, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < MAX_SMC_OP_NUM; i++) {
+		if (reg_addr[i] == 0)
+			continue;
+
+		switch (i) {
+		case 0:
+			smccc_ret->a1 = mmio_read_32(reg_addr[i]);
+			break;
+		case 1:
+			smccc_ret->a2 = mmio_read_32(reg_addr[i]);
+			break;
+		case 2:
+			smccc_ret->a3 = mmio_read_32(reg_addr[i]);
+			break;
+		}
+	}
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_LOGGER_USER, 0, 0, 0);
+	if (ret)
+		ERROR("%s(%d): sem release timeout\n", __func__, op);
+
+	return ret;
+}
+
+static int apusys_kernel_apusys_logtop_reg_rw(uint32_t op, uint32_t write_val,
+					      bool w1c, struct smccc_res *smccc_ret)
+{
+	int ret = 0;
+	uint32_t reg_addr = 0, reg_val = 0;
+
+	switch (op) {
+	case SMC_OP_APU_LOG_BUF_R_PTR:
+		reg_addr = APU_LOG_BUF_R_PTR;
+		break;
+	case SMC_OP_APU_LOG_BUF_CON:
+		reg_addr = APU_LOGTOP_CON;
+		break;
+	default:
+		ERROR("%s unknown or not support op = %x\n", MODULE_TAG, op);
+		return -EINVAL;
+	}
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_LOGGER_USER, 1, 0, 0);
+	if (ret)
+		return ret;
+
+	if (w1c) {
+		reg_val = mmio_read_32(reg_addr);
+		mmio_write_32(reg_addr, reg_val);
+		smccc_ret->a1 = reg_val;
+	} else {
+		mmio_write_32(reg_addr, write_val);
+	}
+
+	ret = apu_hw_sema_ctl(HW_SEMA2, HW_SEMA_LOGGER_USER, 0, 0, 0);
+	if (ret)
+		ERROR("%s(%d): sem release timeout\n", __func__, op);
+
+	return ret;
+}
+
+int apusys_kernel_apusys_logtop_reg_write(uint32_t op, uint32_t write_val,
+					  struct smccc_res *smccc_ret)
+{
+	return apusys_kernel_apusys_logtop_reg_rw(op, write_val, false, smccc_ret);
+}
+
+int apusys_kernel_apusys_logtop_reg_w1c(uint32_t op, struct smccc_res *smccc_ret)
+{
+	return apusys_kernel_apusys_logtop_reg_rw(op, 0, true, smccc_ret);
+}
+
+#endif /* CONFIG_MTK_APUSYS_LOGTOP_SUPPORT */
+
+int apusys_rv_cold_boot_clr_mbox_dummy(void)
+{
+#ifdef SUPPORT_APU_CLEAR_MBOX_DUMMY
+	mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, 0);
+#else
+	WARN("Not support clear mbox dummy on this platform\n");
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT
+int apusys_rv_iommu_hw_sem_trylock(void)
+{
+	return rv_iommu_hw_sem_trylock();
+}
+
+int apusys_rv_iommu_hw_sem_unlock(void)
+{
+	return rv_iommu_hw_sem_unlock();
+}
+#endif /* CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT */
+
+int apusys_rv_setup_ce_bin(void)
+{
+#ifdef CONFIG_MTK_APUSYS_CE_SUPPORT
+	uintptr_t apusys_rv_sec_buf_pa;
+	struct apusys_secure_info_t *apusys_secure_info;
+	struct ce_main_hdr_t *ce_main_hdr;
+	struct ce_sub_hdr_t *ce_sub_hdr;
+	unsigned int cnt, i, reg_val;
+	uint64_t ce_sub_hdr_bin;
+	int ret;
+
+	apusys_rv_sec_buf_pa = APU_RESERVE_MEMORY;
+	/* create mapping */
+	ret = mmap_add_dynamic_region(apusys_rv_sec_buf_pa, apusys_rv_sec_buf_pa,
+				      round_up(APU_RESERVE_SIZE, PAGE_SIZE),
+				      MT_MEMORY | MT_RW | MT_NS);
+	if (ret) {
+		ERROR("%s: mmap_add_dynamic_region() fail, ret=0x%x\n", __func__, ret);
+		return ret;
+	}
+
+	apusys_secure_info = (struct apusys_secure_info_t *)
+				(apusys_rv_sec_buf_pa + APU_SEC_INFO_OFFSET);
+
+	ce_main_hdr = (struct ce_main_hdr_t *)(apusys_rv_sec_buf_pa +
+		apusys_secure_info->ce_bin_ofs);
+	ce_sub_hdr = (struct ce_sub_hdr_t *)((uintptr_t)ce_main_hdr + ce_main_hdr->hdr_size);
+
+	if (ce_main_hdr->magic != CE_MAIN_MAGIC) {
+		ERROR("%s: invalid header\n", __func__);
+		return -EINVAL;
+	}
+
+	cnt = 0;
+
+	while (ce_sub_hdr->magic == CE_SUB_MAGIC && cnt < ce_main_hdr->bin_count) {
+		VERBOSE("%s: job (%d), magic (0x%x)\n", __func__,
+			ce_sub_hdr->ce_enum, ce_sub_hdr->magic);
+
+		ce_sub_hdr_bin = (uint64_t)ce_sub_hdr + ce_sub_hdr->bin_offset;
+
+		for (i = 0; i < ce_sub_hdr->bin_size; i += sizeof(uint32_t)) {
+			reg_val = *(uint32_t *)(ce_sub_hdr_bin + i);
+			mmio_write_32(ce_sub_hdr->mem_st + i, reg_val);
+		}
+
+		if (ce_sub_hdr->hw_entry) {
+			mmio_clrsetbits_32(ce_sub_hdr->hw_entry,
+					   ce_sub_hdr->hw_entry_mask << ce_sub_hdr->hw_entry_bit,
+					   (ce_sub_hdr->hw_entry_val & ce_sub_hdr->hw_entry_mask)
+					   << ce_sub_hdr->hw_entry_bit);
+		}
+
+		ce_sub_hdr = (struct ce_sub_hdr_t *)(ce_sub_hdr_bin + ce_sub_hdr->bin_size);
+		cnt++;
+	}
+
+	mmap_remove_dynamic_region(apusys_rv_sec_buf_pa,
+				   round_up(APU_RESERVE_SIZE, PAGE_SIZE));
 
+	INFO("%s: setup CE binary done\n", __func__);
+#else
+	WARN("Not support CE on this platform\n");
+#endif
 	return 0;
 }
diff --git a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.h b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.h
index 8a43890..506fcee 100644
--- a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.h
+++ b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -88,24 +88,35 @@
 #define WDT_INT_W1C			(1)
 #define WDT_EN				BIT(31)
 
-/* APU MBOX */
-#define MBOX_FUNC_CFG			(0xb0)
-#define MBOX_DOMAIN_CFG			(0xe0)
-#define MBOX_CTRL_LOCK			BIT(0)
-#define MBOX_NO_MPU_SHIFT		(16)
-#define MBOX_RX_NS_SHIFT		(16)
-#define MBOX_RX_DOMAIN_SHIFT		(17)
-#define MBOX_TX_NS_SHIFT		(24)
-#define MBOX_TX_DOMAIN_SHIFT		(25)
-#define MBOX_SIZE			(0x100)
-#define MBOX_NUM			(8)
+enum APU_PWR_OP {
+	APU_PWR_OFF = 0,
+	APU_PWR_ON  = 1,
+};
 
-#define APU_MBOX(i)		(((i) < MBOX_NUM) ? (APU_MBOX0 + MBOX_SIZE * (i)) : \
-						  (APU_MBOX1 + MBOX_SIZE * ((i) - MBOX_NUM)))
-#define APU_MBOX_FUNC_CFG(i)	(APU_MBOX(i) + MBOX_FUNC_CFG)
-#define APU_MBOX_DOMAIN_CFG(i)	(APU_MBOX(i) + MBOX_DOMAIN_CFG)
+/* APU_LOGTOP */
+#define APU_LOGTOP_CON			(APU_LOGTOP + 0x0)
+#define APU_LOG_BUF_T_SIZE		(APU_LOGTOP + 0x78)
+#define APU_LOG_BUF_W_PTR		(APU_LOGTOP + 0x80)
+#define APU_LOG_BUF_R_PTR		(APU_LOGTOP + 0x84)
+#define HW_SEMA2			(APU_ARE_REG_BASE + 0x0E08)
+#define HW_SEMA_USER			(0x2)
+#define HW_SEMA_LOGGER_USER		(0x3)
+#define MAX_SMC_OP_NUM			(0x3)
+#define LOGTOP_OP_MASK			(0xFF)
+#define LOGTOP_OP_SHIFT			(8)
+enum {
+	SMC_OP_APU_LOG_BUF_NULL = 0,
+	SMC_OP_APU_LOG_BUF_T_SIZE,
+	SMC_OP_APU_LOG_BUF_W_PTR,
+	SMC_OP_APU_LOG_BUF_R_PTR,
+	SMC_OP_APU_LOG_BUF_CON,
+	SMC_OP_APU_LOG_BUF_NUM
+};
+
+struct smccc_res;
 
 void apusys_rv_mbox_mpu_init(void);
+int apusys_infra_dcm_setup(void);
 int apusys_kernel_apusys_rv_setup_reviser(void);
 int apusys_kernel_apusys_rv_reset_mp(void);
 int apusys_kernel_apusys_rv_setup_boot(void);
@@ -116,5 +127,13 @@
 int apusys_kernel_apusys_rv_clear_wdt_isr(void);
 int apusys_kernel_apusys_rv_cg_gating(void);
 int apusys_kernel_apusys_rv_cg_ungating(void);
+int apusys_kernel_apusys_rv_setup_apummu(void);
+int apusys_kernel_apusys_rv_pwr_ctrl(enum APU_PWR_OP op);
+int apusys_kernel_apusys_logtop_reg_dump(uint32_t op, struct smccc_res *smccc_ret);
+int apusys_kernel_apusys_logtop_reg_write(uint32_t op, uint32_t write_val,
+					  struct smccc_res *smccc_ret);
+int apusys_kernel_apusys_logtop_reg_w1c(uint32_t op, struct smccc_res *smccc_ret);
+int apusys_rv_cold_boot_clr_mbox_dummy(void);
+int apusys_rv_setup_ce_bin(void);
 
 #endif /* APUSYS_RV_H */
diff --git a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_sec_info.h b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_sec_info.h
new file mode 100644
index 0000000..581ed0a
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_sec_info.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_RV_SECURE_INFO_H
+#define APUSYS_RV_SECURE_INFO_H
+
+#define CE_MAIN_MAGIC		(0xCEC0DE88)
+#define CE_SUB_MAGIC		(0xCEC0DE00)
+
+struct apusys_secure_info_t {
+	unsigned int total_sz;
+	unsigned int up_code_buf_ofs;
+	unsigned int up_code_buf_sz;
+
+	unsigned int up_fw_ofs;
+	unsigned int up_fw_sz;
+	unsigned int up_xfile_ofs;
+	unsigned int up_xfile_sz;
+	unsigned int mdla_fw_boot_ofs;
+	unsigned int mdla_fw_boot_sz;
+	unsigned int mdla_fw_main_ofs;
+	unsigned int mdla_fw_main_sz;
+	unsigned int mdla_xfile_ofs;
+	unsigned int mdla_xfile_sz;
+	unsigned int mvpu_fw_ofs;
+	unsigned int mvpu_fw_sz;
+	unsigned int mvpu_xfile_ofs;
+	unsigned int mvpu_xfile_sz;
+	unsigned int mvpu_sec_fw_ofs;
+	unsigned int mvpu_sec_fw_sz;
+	unsigned int mvpu_sec_xfile_ofs;
+	unsigned int mvpu_sec_xfile_sz;
+
+	unsigned int up_coredump_ofs;
+	unsigned int up_coredump_sz;
+	unsigned int mdla_coredump_ofs;
+	unsigned int mdla_coredump_sz;
+	unsigned int mvpu_coredump_ofs;
+	unsigned int mvpu_coredump_sz;
+	unsigned int mvpu_sec_coredump_ofs;
+	unsigned int mvpu_sec_coredump_sz;
+
+	unsigned int ce_bin_ofs;
+	unsigned int ce_bin_sz;
+};
+
+struct ce_main_hdr_t {
+	unsigned int magic;         /* magic number*/
+	unsigned int hdr_size;      /* header size */
+	unsigned int img_size;      /* img size */
+	unsigned int bin_count;     /* bin count */
+};
+
+struct ce_sub_hdr_t {
+	unsigned int magic;         /* magic number */
+	unsigned int bin_offset;    /* binary offset */
+	unsigned int bin_size;      /* binary size */
+	unsigned int ce_enum;       /* ce enum */
+	char job_name[8];           /* job name */
+	unsigned int mem_st;        /* ce enum */
+	unsigned int hw_entry;      /* hw entry */
+	unsigned int hw_entry_bit;  /* hw entry bit */
+	unsigned int hw_entry_mask; /* hw entry mask */
+	unsigned int hw_entry_val;  /* hw entry val*/
+	unsigned int user_info;     /* user_info */
+};
+
+#endif /* APUSYS_RV_SECURE_INFO_H */
diff --git a/plat/mediatek/drivers/apusys/devapc/apusys_dapc_v1.h b/plat/mediatek/drivers/apusys/devapc/apusys_dapc_v1.h
index 1b77942..a15daa2 100644
--- a/plat/mediatek/drivers/apusys/devapc/apusys_dapc_v1.h
+++ b/plat/mediatek/drivers/apusys/devapc/apusys_dapc_v1.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,8 +13,15 @@
  * STRUCTURE DEFINITION
  ******************************************************************************/
 enum apusys_apc_err_status {
-	APUSYS_APC_OK		= 0x0,
-	APUSYS_APC_ERR_GENERIC	= 0x1,
+	APUSYS_APC_OK				= 0x0,
+	APUSYS_APC_ERR_GENERIC			= 0x1000,
+	APUSYS_APC_ERR_INVALID_CMD		= 0x1001,
+	APUSYS_APC_ERR_SLAVE_TYPE_NOT_SUPPORTED	= 0x1002,
+	APUSYS_APC_ERR_SLAVE_IDX_NOT_SUPPORTED	= 0x1003,
+	APUSYS_APC_ERR_DOMAIN_NOT_SUPPORTED	= 0x1004,
+	APUSYS_APC_ERR_PERMISSION_NOT_SUPPORTED	= 0x1005,
+	APUSYS_APC_ERR_OUT_OF_BOUNDARY		= 0x1006,
+	APUSYS_APC_ERR_REQ_TYPE_NOT_SUPPORTED	= 0x1007,
 };
 
 enum apusys_apc_perm_type {
@@ -155,4 +162,110 @@
 			   FORBIDDEN,     NO_PROTECTION, FORBIDDEN, FORBIDDEN, \
 			   FORBIDDEN,     FORBIDDEN,     FORBIDDEN, FORBIDDEN, \
 			   FORBIDDEN,     FORBIDDEN,     FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_D11_NO_PROTECT_D3_D5_D8_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   SEC_RW_ONLY,   FORBIDDEN,   FORBIDDEN, NO_PROTECTION, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D3_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   SEC_RW_NS_R, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   FORBIDDEN, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN, SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN, FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   SEC_RW_NS_R, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D3_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D3_D5_SEC_RW_D0_D4_D11_NO_PROTECT(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   NO_PROTECTION, SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, NO_PROTECTION, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D5_SEC_RW_D0_NO_PROTECT(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   SEC_RW_ONLY, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D3_D5_SEC_RW_D0_D11_NO_PROTECT(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, NO_PROTECTION, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D5_D8_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   SEC_RW_ONLY,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_D3_D5_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   SEC_RW_ONLY, FORBIDDEN,   FORBIDDEN, SEC_RW_ONLY, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_D8_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   SEC_RW_NS_R, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   SEC_RW_ONLY, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D5_D8_SEC_RW(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, \
+			   SEC_RW_ONLY, FORBIDDEN,   FORBIDDEN, FORBIDDEN, \
+			   FORBIDDEN,   FORBIDDEN,   FORBIDDEN, FORBIDDEN)
+
+#define SLAVE_FORBID_EXCEPT_D0_D5_D7_D14_NO_PROTECT(domain) \
+	APUSYS_APC_AO_ATTR(domain, \
+			   NO_PROTECTION, FORBIDDEN,     FORBIDDEN,     FORBIDDEN, \
+			   FORBIDDEN,     NO_PROTECTION, FORBIDDEN,     NO_PROTECTION, \
+			   FORBIDDEN,     FORBIDDEN,     FORBIDDEN,     FORBIDDEN, \
+			   FORBIDDEN,     FORBIDDEN,     NO_PROTECTION, FORBIDDEN)
+
 #endif /* APUSYS_DAPC_V1_H */
diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_power.c b/plat/mediatek/drivers/apusys/mt8188/apusys_power.c
index 0a2781b..746c81f 100644
--- a/plat/mediatek/drivers/apusys/mt8188/apusys_power.c
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_power.c
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <errno.h>
 #include <inttypes.h>
 
 /* TF-A system header */
@@ -18,6 +19,7 @@
 #include "apusys.h"
 #include "apusys_power.h"
 #include "apusys_rv.h"
+#include "apusys_rv_pwr_ctrl.h"
 #include <mtk_mmap_pool.h>
 
 static spinlock_t apu_lock;
@@ -118,7 +120,7 @@
 	mmio_write_32(APU_MBOX0_BASE + PWR_FLOW_SYNC_REG, (cfg & 0x1));
 }
 
-int apusys_kernel_apusys_pwr_top_on(void)
+static int apusys_kernel_apusys_pwr_top_on(void)
 {
 	int ret;
 
@@ -184,7 +186,7 @@
 	udelay(100);
 }
 
-int apusys_kernel_apusys_pwr_top_off(void)
+static int apusys_kernel_apusys_pwr_top_off(void)
 {
 	int ret;
 
@@ -221,6 +223,19 @@
 	return ret;
 }
 
+int apusys_rv_pwr_ctrl(enum APU_PWR_OP op)
+{
+	if (op != APU_PWR_OFF && op != APU_PWR_ON) {
+		ERROR(MODULE_TAG "%s unknown request_ops = %d\n", __func__, op);
+		return -EINVAL;
+	}
+
+	if (op == APU_PWR_ON)
+		return apusys_kernel_apusys_pwr_top_on();
+
+	return apusys_kernel_apusys_pwr_top_off();
+}
+
 static void get_pll_pcw(const uint32_t clk_rate, uint32_t *r1, uint32_t *r2)
 {
 	unsigned int fvco = clk_rate;
@@ -481,3 +496,10 @@
 
 	return ret;
 }
+
+int apusys_infra_dcm_setup(void)
+{
+	WARN(MODULE_TAG "%s not support\n", __func__);
+
+	return -EOPNOTSUPP;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_power.h b/plat/mediatek/drivers/apusys/mt8188/apusys_power.h
index 460cc50..e1ce4a4 100644
--- a/plat/mediatek/drivers/apusys/mt8188/apusys_power.h
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_power.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -242,7 +242,5 @@
 #define CG_CLR					(0xffffffff)
 
 int apusys_power_init(void);
-int apusys_kernel_apusys_pwr_top_on(void);
-int apusys_kernel_apusys_pwr_top_off(void);
 
 #endif /* APUSYS_POWER_H */
diff --git a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_mbox_mpu.h b/plat/mediatek/drivers/apusys/mt8188/apusys_rv_mbox_mpu.h
similarity index 95%
rename from plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_mbox_mpu.h
rename to plat/mediatek/drivers/apusys/mt8188/apusys_rv_mbox_mpu.h
index 0ee4878..dbdf274 100644
--- a/plat/mediatek/drivers/apusys/apusys_rv/2.0/apusys_rv_mbox_mpu.h
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_rv_mbox_mpu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_rv_pwr_ctrl.h b/plat/mediatek/drivers/apusys/mt8188/apusys_rv_pwr_ctrl.h
new file mode 100644
index 0000000..329eadf
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_rv_pwr_ctrl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_RV_PWR_CTL_H
+#define APUSYS_RV_PWR_CTL_H
+
+#include "apusys_rv.h"
+
+/* APU MBOX */
+#define MBOX_FUNC_CFG			(0xb0)
+#define MBOX_DOMAIN_CFG			(0xe0)
+#define MBOX_CTRL_LOCK			BIT(0)
+#define MBOX_NO_MPU_SHIFT		(16)
+#define MBOX_RX_NS_SHIFT		(16)
+#define MBOX_RX_DOMAIN_SHIFT		(17)
+#define MBOX_TX_NS_SHIFT		(24)
+#define MBOX_TX_DOMAIN_SHIFT		(25)
+#define MBOX_SIZE			(0x100)
+#define MBOX_NUM			(8)
+
+#define APU_MBOX(i)		(((i) < MBOX_NUM) ? (APU_MBOX0 + MBOX_SIZE * (i)) : \
+						  (APU_MBOX1 + MBOX_SIZE * ((i) - MBOX_NUM)))
+#define APU_MBOX_FUNC_CFG(i)	(APU_MBOX(i) + MBOX_FUNC_CFG)
+#define APU_MBOX_DOMAIN_CFG(i)	(APU_MBOX(i) + MBOX_DOMAIN_CFG)
+
+#define HW_SEM_TIMEOUT		(0)
+
+int apusys_rv_pwr_ctrl(enum APU_PWR_OP op);
+
+#endif /* APUSYS_RV_PWR_CTL_H */
diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.c b/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.c
index 86bebe5..8517db0 100644
--- a/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.c
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,8 @@
 #include <common/debug.h>
 #include <lib/mmio.h>
 
+#include "emi_mpu.h"
+
 /* Vendor header */
 #include "apusys_security_ctrl_plat.h"
 
@@ -41,3 +43,8 @@
 {
 	apusys_domain_remap_init();
 }
+
+int apusys_plat_setup_sec_mem(void)
+{
+	return set_apu_emi_mpu_region();
+}
diff --git a/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.h b/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.h
index f9181ae..f1b0a41 100644
--- a/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.h
+++ b/plat/mediatek/drivers/apusys/mt8188/apusys_security_ctrl_plat.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,5 +34,6 @@
 #define D15_REMAP_DOMAIN	(15)
 
 void apusys_security_ctrl_init(void);
+int apusys_plat_setup_sec_mem(void);
 
 #endif /* APUSYS_SECURITY_CTRL_PLAT_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.c b/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.c
new file mode 100644
index 0000000..fa1cd2c
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <errno.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "apusys_ammu.h"
+#include <apusys_security_ctrl_perm.h>
+#include <mtk_mmap_pool.h>
+
+static void apummu_set_segment_offset0(uint32_t vsid_idx, uint8_t seg_idx, uint32_t input_adr,
+				       uint8_t res_bits, uint8_t page_sel, uint8_t page_len)
+{
+	mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_0),
+		      APUMMU_BUILD_SEGMENT_OFFSET0(input_adr, res_bits, page_sel, page_len));
+}
+
+static void apummu_set_segment_offset1(uint32_t vsid_idx, uint8_t seg_idx, uint32_t output_adr,
+				       uint8_t res0, uint8_t iommu_en, uint8_t res1)
+{
+	mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_1),
+		      APUMMU_BUILD_SEGMENT_OFFSET1(output_adr, res0, iommu_en, res1));
+}
+
+static void apummu_set_segment_offset2(uint32_t vsid_idx, uint8_t seg_idx, uint8_t resv,
+				       uint8_t domain, uint8_t acp_en, uint8_t aw_clr,
+				       uint8_t aw_invalid, uint8_t ar_exclu, uint8_t ar_sepcu,
+				       uint8_t aw_cache_allocate, uint8_t aw_slc_en,
+				       uint8_t aw_slb_en, uint8_t ar_cache_allocate,
+				       uint8_t ar_slc_en, uint8_t ar_slb_en, uint8_t ro,
+				       uint8_t ns)
+{
+	mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_2),
+		      APUMMU_BUILD_SEGMENT_OFFSET2(resv, domain, acp_en, aw_clr, aw_invalid,
+						   ar_exclu, ar_sepcu, aw_cache_allocate,
+						   aw_slc_en, aw_slb_en, ar_cache_allocate,
+						   ar_slc_en, ar_slb_en, ro, ns));
+}
+
+static void apummu_vsid_segment_enable_init(uint8_t vsid_idx)
+{
+	mmio_write_32(APUMMU_VSID_SEGMENT_ENABLE(vsid_idx), 0);
+}
+
+static void apummu_set_single_segment(uint8_t vsid_idx, uint8_t seg_idx)
+{
+	mmio_setbits_32(APUMMU_VSID_SEGMENT_ENABLE(vsid_idx), BIT(seg_idx));
+}
+
+static int apummu_enable_vsid(uint32_t vsid_idx)
+{
+	if (vsid_idx > (APUMMU_VSID_ACTIVE - 1) &&
+	    vsid_idx < (APUMMU_RSV_VSID_IDX_END - APUMMU_VSID_RSV + 1)) {
+		ERROR("invalid vsid index %d\n", vsid_idx);
+		return -1;
+	}
+
+	mmio_write_32(APUMMU_VSID_ENABLE_BASE(vsid_idx), BIT(vsid_idx & APUMMU_VSID_EN_MASK));
+	mmio_write_32(APUMMU_VSID_VALID_BASE(vsid_idx), BIT(vsid_idx & APUMMU_VSID_EN_MASK));
+
+	return 0;
+}
+
+static void apummu_enable(void)
+{
+	mmio_setbits_32(APUMMU_CMU_TOP_BASE, 0x1);
+}
+
+static void apummu_vsid_sram_config(void)
+{
+	uint32_t idx;
+	uint32_t base = (APUMMU_VSID_SRAM_TOTAL - APUMMU_VSID_RSV);
+
+	for (idx = 0; idx < APUMMU_VSID_RSV; idx++) {
+		mmio_write_32(APUMMU_VSID(APUMMU_RSV_VSID_IDX_START + idx),
+			      APUMMU_VSID_DESC(base + idx));
+		apummu_vsid_segment_enable_init(base + idx);
+	}
+}
+
+static void apummu_bind_vsid(uint32_t tcu_base, uint32_t vsid_idx, uint8_t cor_id,
+			     uint8_t hw_thread, uint8_t cor_valid, uint8_t vsid_valid)
+{
+	mmio_write_32((tcu_base + hw_thread * VSID_THREAD_SZ),
+		      (((cor_id & VSID_CORID_MASK) << VSID_CORID_OFF) |
+		       ((vsid_idx & VSID_IDX_MASK) << VSID_IDX_OFF) |
+		       ((cor_valid & VSID_VALID_MASK) << VSID_COR_VALID_OFF) |
+		       ((vsid_valid & VSID_VALID_MASK) << VSID_VALID_OFF)));
+}
+
+static int apummu_rv_bind_vsid(uint8_t hw_thread)
+{
+	uint8_t cor_id = 0, cor_valid = 0, vsid_valid = 1;
+
+	if (hw_thread > APUMMU_HW_THREAD_MAX) {
+		ERROR("%s: the hw thread id (%d) is not valid for rv/logger\n", __func__,
+		       hw_thread);
+		return -EINVAL;
+	}
+
+	apummu_bind_vsid(APUMMU_RCX_UPRV_TCU_BASE, APUMMU_UPRV_RSV_VSID, cor_id, hw_thread,
+			 cor_valid, vsid_valid);
+
+	return 0;
+}
+
+static int apummu_apmcu_bind_vsid(uint8_t hw_thread)
+{
+	uint8_t cor_id = 0, cor_valid = 0, vsid_valid = 1;
+
+	if (hw_thread > APUMMU_HW_THREAD_MAX) {
+		ERROR("%s: the hw thread id (%d) is not valid for apmcu\n", __func__, hw_thread);
+		return -EINVAL;
+	}
+
+	apummu_bind_vsid(APUMMU_RCX_EXTM_TCU_BASE, APUMMU_APMCU_RSV_VSID, cor_id, hw_thread,
+			 cor_valid, vsid_valid);
+
+	return 0;
+}
+
+static int apummu_add_map(uint32_t vsid_idx, uint8_t seg_idx, uint64_t input_adr,
+			  uint64_t output_adr, uint8_t page_sel, uint8_t page_len,
+			  uint8_t domain, uint8_t ns)
+{
+	uint8_t smmu_sid;
+	bool smmu_sec_id;
+
+	if (seg_idx > APUMMU_SEG_MAX) {
+		ERROR("seg_idx is illegal (0x%x)\n", seg_idx);
+		return -EINVAL;
+	}
+
+	smmu_sec_id = false;
+	if (ns == 0)
+		smmu_sid = SMMU_NORMAL_1_4G_SID;
+	else
+		smmu_sid = (output_adr > 0xFFFFFFFF) ? SMMU_NORMAL_4_16G_SID
+						     : SMMU_NORMAL_1_4G_SID;
+
+	/* fill segment */
+	apummu_set_segment_offset0(vsid_idx, seg_idx, (input_adr >> APUMMU_ADDR_SHIFT), 0,
+				   page_sel, page_len);
+	apummu_set_segment_offset1(vsid_idx, seg_idx, (output_adr >> APUMMU_ADDR_SHIFT),
+				   smmu_sid, 0, smmu_sec_id);
+	apummu_set_segment_offset2(vsid_idx, seg_idx, 0, domain,
+				   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ns);
+	apummu_set_single_segment(vsid_idx, seg_idx);
+
+	return 0;
+}
+
+static int apummu_get_dns(enum apusys_dev_type engine_type, enum apusys_sec_level sec_level,
+			  uint8_t *domain, uint8_t *ns)
+{
+	int ret = 0;
+
+	if (engine_type != APUSYS_DEVICE_NUM) {
+		ret = sec_get_dns(engine_type, sec_level, domain, ns);
+		if (ret)
+			ERROR("engine:%d, sec: %d\n", engine_type, sec_level);
+	} else {
+		*domain = 7;
+		*ns = 1;
+	}
+
+	return ret;
+}
+
+static void apummu_init(void)
+{
+	apummu_vsid_sram_config();
+	mmio_write_32((APU_VCORE_CONFIG_BASE + APUMMU_SSID_SID_WIDTH_CTRL),
+		      CSR_SMMU_AXMMUSID_WIDTH);
+	apummu_enable();
+}
+
+static void virtual_engine_thread(void)
+{
+	mmio_write_32((APUMMU_RCX_EXTM_TCU_BASE + APUMMU_INT_D2T_TBL0_OFS), APUMMU_THD_ID_TEE);
+}
+
+static int apummu_add_apmcu_map(uint32_t seg0_input, uint32_t seg0_output,
+				enum apummu_page_size page_size)
+{
+	int i, ret;
+	uint8_t domain, ns, seg;
+
+	ret = apummu_get_dns(APUSYS_DEVICE_NUM, SEC_LEVEL_SECURE, &domain, &ns);
+	if (ret) {
+		return ret;
+	}
+
+	seg = 0;
+	ret = apummu_add_map(APUMMU_APMCU_RSV_DESC_IDX, seg, seg0_input, seg0_output, 0,
+			     page_size, domain, ns);
+	seg += 1;
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 4; i++) {
+		ret = apummu_add_map(APUMMU_APMCU_RSV_DESC_IDX, seg,
+				     APUSYS_TCM + (i * APUMMU_1M_SIZE),
+				     APUSYS_TCM + (i * APUMMU_1M_SIZE),
+				     0, APUMMU_PAGE_LEN_1MB, domain, ns);
+		seg += 1;
+		if (ret)
+			return ret;
+	}
+
+	ret = apummu_enable_vsid(APUMMU_APMCU_RSV_VSID);
+
+	return ret;
+}
+
+static int apummu_add_rv_boot_map(uint32_t seg0_output, uint32_t seg1_output, uint32_t seg2_output)
+{
+	int ret;
+	uint8_t domain, ns;
+
+	ret = apummu_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_SECURE, &domain, &ns);
+	if (ret) {
+		ERROR("sec get dns fail %d\n", ret);
+		return ret;
+	}
+
+	/* must be in order */
+	ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 0, 0, seg0_output, 0,
+			      APUMMU_PAGE_LEN_1MB, domain, ns);
+	ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 1, 0, seg1_output, 0,
+			      APUMMU_PAGE_LEN_512MB, domain, ns);
+
+	ret |= apummu_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_NORMAL, &domain, &ns);
+	if (ret) {
+		return ret;
+	}
+
+	ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 2,
+			      0, seg2_output, 0, APUMMU_PAGE_LEN_4GB,
+			      domain, ns);
+	if (ret) {
+		ERROR("sec add map fail %d\n", ret);
+		return ret;
+	}
+
+	ret = apummu_enable_vsid(APUMMU_UPRV_RSV_VSID);
+
+	return ret;
+}
+
+int rv_boot(uint32_t uP_seg_output, uint8_t uP_hw_thread,
+	    enum apummu_page_size logger_page_size,
+	    uint32_t XPU_seg_output, enum apummu_page_size XPU_page_size)
+{
+	int ret = 0;
+
+	apummu_init();
+
+	ret = apummu_add_rv_boot_map(uP_seg_output, 0, 0);
+	if (ret) {
+		return ret;
+	}
+
+	ret = apummu_rv_bind_vsid(uP_hw_thread);
+	if (ret)
+		return ret;
+
+	ret = apummu_rv_bind_vsid(uP_hw_thread + 1);
+	if (ret)
+		return ret;
+
+	virtual_engine_thread();
+
+	ret = apummu_add_apmcu_map(XPU_seg_output, XPU_seg_output,
+				   XPU_page_size);
+	if (ret)
+		return ret;
+
+	ret = apummu_apmcu_bind_vsid(APUMMU_THD_ID_TEE);
+
+	return ret;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.h b/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.h
new file mode 100644
index 0000000..61defc9
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_ammu.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_AMMU_H
+#define APUSYS_AMMU_H
+
+#include <platform_def.h>
+
+/* CMU */
+#define APUMMU_CMU_TOP_BASE		(APU_CMU_TOP)
+#define APUMMU_CMU_TOP_TOPOLOGY		(APUMMU_CMU_TOP_BASE + 0x04)
+#define APUMMU_VSID_ENABLE_OFFSET	(0x50)
+#define APUMMU_VSID_VALID_OFFSET	(0xb0)
+
+#define VSID_OFFSET(vsid_idx)		(((vsid_idx) >> 5) * 0x4)
+
+#define APUMMU_VSID_ENABLE_BASE(vsid_idx) \
+	(APUMMU_CMU_TOP_BASE + VSID_OFFSET(vsid_idx) + APUMMU_VSID_ENABLE_OFFSET)
+#define APUMMU_VSID_VALID_BASE(vsid_idx) \
+	(APUMMU_CMU_TOP_BASE + VSID_OFFSET(vsid_idx) + APUMMU_VSID_VALID_OFFSET)
+
+/* VSID SRAM */
+#define APUMMU_VSID_BASE		(APUMMU_CMU_TOP_BASE + 0x1000)
+#define APUMMU_VSID_DESC_BASE		(APUMMU_VSID_BASE + 0x400)
+#define APUMMU_VSID_SRAM_SZIE		(0x5C00)
+#define APUMMU_VSID_TBL_SZIE		(0xF4)
+
+#define APUMMU_VSID(vsid_idx)		(APUMMU_VSID_BASE + (vsid_idx) * 4)
+#define APUMMU_VSID_DESC(vsid_idx) \
+	(APUMMU_VSID_DESC_BASE + (vsid_idx) * APUMMU_VSID_TBL_SZIE)
+
+/* TCU RCX */
+#define APU_VCORE_CONFIG_BASE		(APU_RCX_VCORE_CONFIG)
+#define APUMMU_RCX_EXTM_TCU_BASE	(APU_RCX_EXTM_TCU)
+#define APUMMU_RCX_UPRV_TCU_BASE	(APU_RCX_UPRV_TCU)
+
+#define APUMMU_SSID_SID_WIDTH_CTRL	(0xCC0)
+#define CSR_SMMU_AXMMUSID_WIDTH		BIT(7)
+#define APUMMU_1M_SIZE			(0x100000)
+
+#define SMMU_NORMAL_0_1G_SID		(0x8)
+#define SMMU_NORMAL_1_4G_SID		(0x9)
+#define SMMU_NORMAL_4_16G_SID		(0xA)
+
+enum apummu_page_size {
+	APUMMU_PAGE_LEN_128KB = 0,
+	APUMMU_PAGE_LEN_256KB,
+	APUMMU_PAGE_LEN_512KB,
+	APUMMU_PAGE_LEN_1MB,
+	APUMMU_PAGE_LEN_128MB,
+	APUMMU_PAGE_LEN_256MB,
+	APUMMU_PAGE_LEN_512MB,
+	APUMMU_PAGE_LEN_4GB,
+};
+
+#define APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, seg_offset) \
+	(APUMMU_VSID_DESC(vsid_idx) + (seg_idx) * 0xC + (seg_offset) * 0x04 + 0x4)
+
+#define APUMMU_VSID_SEGMENT_ENABLE(vsid_idx)	(APUMMU_VSID_DESC(vsid_idx))
+
+#define APUMMU_VSID_SRAM_TOTAL		(APUMMU_VSID_SRAM_SZIE / APUMMU_VSID_TBL_SZIE)
+#define APUMMU_RSV_VSID_DESC_IDX_END	(APUMMU_VSID_SRAM_TOTAL - 1)
+#define APUMMU_UPRV_RSV_DESC_IDX	(APUMMU_RSV_VSID_DESC_IDX_END)		/* 53 */
+#define APUMMU_LOGGER_RSV_DESC_IDX	(APUMMU_RSV_VSID_DESC_IDX_END - 1)
+#define APUMMU_APMCU_RSV_DESC_IDX	(APUMMU_RSV_VSID_DESC_IDX_END - 2)
+#define APUMMU_GPU_RSV_DESC_IDX		(APUMMU_RSV_VSID_DESC_IDX_END - 3)
+
+#define APUMMU_SEG_OFFSET_0		(0)
+#define APUMMU_SEG_OFFSET_1		(1)
+#define APUMMU_SEG_OFFSET_2		(2)
+#define APUMMU_VSID_EN_MASK		(0x1f)
+
+#define APUMMU_HW_THREAD_MAX		(7)
+#define APUMMU_SEG_MAX			(9)
+#define APUMMU_ADDR_SHIFT		(12)
+
+#define VSID_THREAD_SZ			(0x4)
+#define VSID_CORID_MASK			(0x7f)
+#define VSID_CORID_OFF			(11)
+#define VSID_IDX_MASK			(0xff)
+#define VSID_IDX_OFF			(3)
+#define VSID_VALID_MASK			(0x1)
+#define VSID_COR_VALID_OFF		(1)
+#define VSID_VALID_OFF			(0)
+
+#define APUMMU_VSID_ACTIVE		(32)
+#define APUMMU_VSID_RSV			(4)
+#define APUMMU_VSID_UNUSED		(12)
+#define APUMMU_VSID_USE_MAX		(APUMMU_VSID_ACTIVE + APUMMU_VSID_RSV)
+
+#if ((APUMMU_VSID_RSV + APUMMU_VSID_ACTIVE + APUMMU_VSID_UNUSED + 1) > APUMMU_VSID_SRAM_TOTAL)
+#error APUMMU VSID Overflow
+#endif
+
+#define APUMMU_RSV_VSID_IDX_END		(254)
+#define APUMMU_RSV_VSID_IDX_START	(APUMMU_RSV_VSID_IDX_END - APUMMU_VSID_RSV + 1)
+
+#if ((APUMMU_RSV_VSID_IDX_END - APUMMU_RSV_VSID_IDX_START) > APUMMU_VSID_RSV)
+#error APUMMU VSID RSV Overflow
+#endif
+
+/* Reserve */
+#define APUMMU_UPRV_RSV_VSID		(APUMMU_RSV_VSID_IDX_END)
+#define APUMMU_LOGGER_RSV_VSID		(APUMMU_RSV_VSID_IDX_END - 1)
+#define APUMMU_APMCU_RSV_VSID		(APUMMU_RSV_VSID_IDX_END - 2)
+#define APUMMU_GPU_RSV_VSID		(APUMMU_RSV_VSID_IDX_END - 3)
+
+/* VSID bit mask */
+#define APUMMU_VSID_MAX_MASK_WORD	((APUMMU_VSID_USE_MAX + 32 - 1) / 32)
+
+/* VSID fields */
+#define READ_VSID_FIELD(vids, sg, offset, shift, mask) \
+	((mmio_read_32(APUMMU_VSID_SEGMENT_BASE(vsid, seg, offset)) >> sift) & mask)
+#define READ_VSID_FIELD_OFFESET0(vids, sg, shift, mask) \
+	READ_VSID_FIELD(vids, sg, 0, shift, mask)
+#define READ_VSID_FIELD_OFFESET1(vids, sg, shift, mask) \
+	READ_VSID_FIELD(vids, sg, 1, shift, mask)
+#define READ_VSID_FIELD_OFFESET2(vids, sg, shift, mask) \
+	READ_VSID_FIELD(vids, sg, 2, shift, mask)
+
+/* Get segment offset 0 data - 0x00 */
+#define APUMMU_SEGMENT_GET_INPUT(vsid, seg) \
+	READ_VSID_FIELD_OFFESET0(vsid, seg, 10, 0x3FFFFF)
+#define APUMMU_SEGMENT_GET_OFFSET0_RSRV(vsid, seg) \
+	READ_VSID_FIELD_OFFESET0(vsid, seg, 6, 0xF)
+#define APUMMU_SEGMENT_GET_PAGELEN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET0(vsid, seg, 0, 0x7)
+#define APUMMU_SEGMENT_GET_PAGESEL(vsid, seg) \
+	READ_VSID_FIELD_OFFESET0(vsid, seg, 3, 0x7)
+
+/* Get segment offset 1 data - 0x04 */
+#define APUMMU_SEGMENT_GET_IOMMU_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET1(vsid, seg, 1, 0x1)
+#define APUMMU_SEGMENT_GET_OFFSET1_RSRV0(vsid, seg) \
+	READ_VSID_FIELD_OFFESET1(vsid, seg, 2, 0xFF)
+#define APUMMU_SEGMENT_GET_OFFSET1_RSRV1(vsid, seg) \
+	READ_VSID_FIELD_OFFESET1(vsid, seg, 0, 0x1)
+#define APUMMU_SEGMENT_GET_OUTPUT(vsid, seg) \
+	READ_VSID_FIELD_OFFESET1(vsid, seg, 10, 0x3FFFFF)
+
+/* Get segment offset 2 data - 0x08 */
+#define APUMMU_SEGMENT_GET_ACP_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 12, 0x1)
+#define APUMMU_SEGMENT_GET_AR_CACHE_ALLOC(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 4, 0x1)
+#define APUMMU_SEGMENT_GET_AR_EXCLU(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 9, 0x1)
+#define APUMMU_SEGMENT_GET_AR_SEPCU(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 8, 0x1)
+#define APUMMU_SEGMENT_GET_AR_SLB_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 2, 0x1)
+#define APUMMU_SEGMENT_GET_AR_SLC_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 3, 0x1)
+#define APUMMU_SEGMENT_GET_AW_CACHE_ALLOC(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 7, 0x1)
+#define APUMMU_SEGMENT_GET_AW_CLR(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 11, 0x1)
+#define APUMMU_SEGMENT_GET_AW_INVALID(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 10, 0x1)
+#define APUMMU_SEGMENT_GET_AW_SLB_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 5, 0x1)
+#define APUMMU_SEGMENT_GET_AW_SLC_EN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 6, 0x1)
+#define APUMMU_SEGMENT_GET_DOMAIN(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 13, 0xF)
+#define APUMMU_SEGMENT_GET_NS(vsid, seg) \
+	READ_VSID_FIELD_OFFESET2(vsid, seg, 0, 0x1)
+
+/* Build segment data */
+/* Build segment offset 0 (0x00) data */
+#define APUMMU_VSID_SEGMENT_00_INPUT(input_adr)		(((input_adr) & 0x3fffff) << 10)
+#define APUMMU_VSID_SEGMENT_00_PAGESEL(page_sel)	(((page_sel) & 0x7) << 3)
+#define APUMMU_VSID_SEGMENT_00_PAGELEN(page_len)	(((page_len) & 0x7) << 0)
+#define APUMMU_VSID_SEGMENT_00_RESV(resv)		(((resv) & 0xf) << 6)
+
+#define APUMMU_BUILD_SEGMENT_OFFSET0(input_adr, resv, page_sel, page_len) \
+				(APUMMU_VSID_SEGMENT_00_INPUT(input_adr) | \
+				 APUMMU_VSID_SEGMENT_00_RESV(resv) | \
+				 APUMMU_VSID_SEGMENT_00_PAGESEL(page_sel) | \
+				 APUMMU_VSID_SEGMENT_00_PAGELEN(page_len))
+
+/* Build segment offset 1 (0x04) data */
+#define APUMMU_VSID_SEGMENT_04_IOMMU_EN(iommu_en)	(((iommu_en) & 0x1) << 1)
+#define APUMMU_VSID_SEGMENT_04_OUTPUT(output_adr)	(((output_adr) & 0x3fffff) << 10)
+#define APUMMU_VSID_SEGMENT_04_RESV0(resv0)		(((resv0) & 0xff) << 2)
+#define APUMMU_VSID_SEGMENT_04_RESV1(resv1)		(((resv1) & 0x1) << 0)
+
+#define APUMMU_BUILD_SEGMENT_OFFSET1(output_adr, resv0, iommu_en, resv1) \
+				(APUMMU_VSID_SEGMENT_04_OUTPUT(output_adr) | \
+				 APUMMU_VSID_SEGMENT_04_RESV0(resv0) | \
+				 APUMMU_VSID_SEGMENT_04_IOMMU_EN(iommu_en) | \
+				 APUMMU_VSID_SEGMENT_04_RESV1(resv1))
+
+/* Build segment offset 2 (0x08) data */
+#define APUMMU_VSID_SEGMENT_08_DOMAIN_MASK	(0xf)
+#define APUMMU_VSID_SEGMENT_08_DOMAIN_SHIFT	(13)
+#define APUMMU_VSID_SEGMENT_08_RESV_MASK	(0x7fff)
+#define APUMMU_VSID_SEGMENT_08_RESV_SHIFT	(17)
+
+#define APUMMU_VSID_SEGMENT_08_DOMAIN(domain) \
+	(((domain) & APUMMU_VSID_SEGMENT_08_DOMAIN_MASK) << APUMMU_VSID_SEGMENT_08_DOMAIN_SHIFT)
+#define APUMMU_VSID_SEGMENT_08_RESV(resv) \
+	(((resv) & APUMMU_VSID_SEGMENT_08_RESV_MASK) << APUMMU_VSID_SEGMENT_08_RESV_SHIFT)
+
+#define APUMMU_VSID_SEGMENT_08_ACP_EN(acp_en)		(((acp_en) & 0x1) << 12)
+#define APUMMU_VSID_SEGMENT_08_AR_EXCLU(ar_exclu)	(((ar_exclu) & 0x1) << 9)
+#define APUMMU_VSID_SEGMENT_08_AR_SEPCU(ar_sepcu)	(((ar_sepcu) & 0x1) << 8)
+#define APUMMU_VSID_SEGMENT_08_AR_SLB_EN(ar_slb_en)	(((ar_slb_en) & 0x1) << 2)
+#define APUMMU_VSID_SEGMENT_08_AR_SLC_EN(ar_slc_en)	(((ar_slc_en) & 0x1) << 3)
+#define APUMMU_VSID_SEGMENT_08_AW_CLR(aw_clr)		(((aw_clr) & 0x1) << 11)
+#define APUMMU_VSID_SEGMENT_08_AW_INVALID(aw_invalid)	(((aw_invalid) & 0x1) << 10)
+#define APUMMU_VSID_SEGMENT_08_AW_SLB_EN(aw_slb_en)	(((aw_slb_en) & 0x1) << 5)
+#define APUMMU_VSID_SEGMENT_08_AW_SLC_EN(aw_slc_en)	(((aw_slc_en) & 0x1) << 6)
+#define APUMMU_VSID_SEGMENT_08_NS(ns)			(((ns) & 0x1) << 0)
+#define APUMMU_VSID_SEGMENT_08_RO(ro)			(((ro) & 0x1) << 1)
+
+#define APUMMU_VSID_SEGMENT_08_AR_CACHE_ALLOCATE(ar_cache_allocate) \
+	(((ar_cache_allocate) & 0x1) << 4)
+#define APUMMU_VSID_SEGMENT_08_AW_CACHE_ALLOCATE(aw_cache_allocate) \
+	(((aw_cache_allocate) & 0x1) << 7)
+
+#define APUMMU_BUILD_SEGMENT_OFFSET2(resv, domain, acp_en, aw_clr, \
+		aw_invalid, ar_exclu, ar_sepcu, \
+		aw_cache_allocate, aw_slc_en, aw_slb_en, ar_cache_allocate, \
+		ar_slc_en, ar_slb_en, ro, ns) \
+		((APUMMU_VSID_SEGMENT_08_RESV(resv)) |\
+		 (APUMMU_VSID_SEGMENT_08_DOMAIN(domain)) |\
+		 (APUMMU_VSID_SEGMENT_08_ACP_EN(acp_en)) |\
+		 (APUMMU_VSID_SEGMENT_08_AW_CLR(aw_clr)) |\
+		 (APUMMU_VSID_SEGMENT_08_AW_INVALID(aw_invalid)) |\
+		 (APUMMU_VSID_SEGMENT_08_AR_EXCLU(ar_exclu)) |\
+		 (APUMMU_VSID_SEGMENT_08_AR_SEPCU(ar_sepcu)) |\
+		 (APUMMU_VSID_SEGMENT_08_AW_CACHE_ALLOCATE(aw_cache_allocate)) |\
+		 (APUMMU_VSID_SEGMENT_08_AW_SLC_EN(aw_slc_en)) |\
+		 (APUMMU_VSID_SEGMENT_08_AW_SLB_EN(aw_slb_en)) |\
+		 (APUMMU_VSID_SEGMENT_08_AR_CACHE_ALLOCATE(ar_cache_allocate)) |\
+		 (APUMMU_VSID_SEGMENT_08_AR_SLC_EN(ar_slc_en)) |\
+		 (APUMMU_VSID_SEGMENT_08_AR_SLB_EN(ar_slb_en)) |\
+		 (APUMMU_VSID_SEGMENT_08_RO(ro)) | (APUMMU_VSID_SEGMENT_08_NS(ns)))
+
+/* Build segment offset 3 (0x0c) data */
+#define APUMMU_VSID_SEGMENT_0C_RESV(rsv)		(((rsv) & 0x7fffffff) << 0)
+#define APUMMU_VSID_SEGMENT_0C_SEG_VALID(seg_valid)	(((seg_valid) & 0x1U) << 31)
+#define APUMMU_BUILD_SEGMENT_OFFSET3(seg_valid, rsv) \
+	((uint32_t)APUMMU_VSID_SEGMENT_0C_SEG_VALID(seg_valid) | \
+	 APUMMU_VSID_SEGMENT_0C_RESV(rsv))
+
+#define APUMMU_INT_D2T_TBL0_OFS	(0x40)
+
+#define APUSYS_TCM		(0x4d100000)
+
+enum {
+	APUMMU_THD_ID_APMCU_NORMAL = 0,
+	APUMMU_THD_ID_TEE,
+};
+
+int rv_boot(uint32_t uP_seg_output, uint8_t uP_hw_thread,
+	    enum apummu_page_size logger_page_size, uint32_t XPU_seg_output,
+	    enum apummu_page_size XPU_page_size);
+
+#endif
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.c b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.c
new file mode 100644
index 0000000..09e35f1
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+#include <apusys_devapc.h>
+#include <apusys_devapc_def.h>
+#include <mtk_mmap_pool.h>
+
+/* AO CONTROL DEVAPC - apu_rcx_ao_infra_dapc_con */
+static const struct apc_dom_16 APUSYS_CTRL_DAPC_AO[] = {
+	/* ctrl index = 0 */
+	SLAVE_RCX_BULK0("apu_ao_ctl_o-0"),
+	SLAVE_MD32_APB("apu_ao_ctl_o-1"),
+	SLAVE_ACP_TCU_SSC("apu_ao_ctl_o-2"),
+	SLAVE_PTP_THM("apu_ao_ctl_o-3"),
+	SLAVE_VCORE("apu_ao_ctl_o-4"),
+	SLAVE_IOMMU0_BANK0("apu_ao_ctl_o-5"),
+	SLAVE_IOMMU0_BANK1("apu_ao_ctl_o-6"),
+	SLAVE_IOMMU0_BANK2("apu_ao_ctl_o-7"),
+	SLAVE_IOMMU0_BANK3("apu_ao_ctl_o-8"),
+	SLAVE_IOMMU0_BANK4("apu_ao_ctl_o-9"),
+
+	/* ctrl index = 10 */
+	SLAVE_IOMMU1_BANK0("apu_ao_ctl_o-10"),
+	SLAVE_IOMMU1_BANK1("apu_ao_ctl_o-11"),
+	SLAVE_IOMMU1_BANK2("apu_ao_ctl_o-12"),
+	SLAVE_IOMMU1_BANK3("apu_ao_ctl_o-13"),
+	SLAVE_IOMMU1_BANK4("apu_ao_ctl_o-14"),
+	SLAVE_S0_SSC("apu_ao_ctl_o-15"),
+	SLAVE_N0_SSC("apu_ao_ctl_o-16"),
+	SLAVE_S1_SSC("apu_ao_ctl_o-17"),
+	SLAVE_N1_SSC("apu_ao_ctl_o-18"),
+	SLAVE_ACP_SSC("apu_ao_ctl_o-19"),
+
+	/* ctrl index = 20 */
+	SLAVE_WDEC("apu_ao_ctl_o-20"),
+	SLAVE_SMMU_IP_REG("apu_ao_ctl_o-21"),
+	SLAVE_SMMU_NSEC("apu_ao_ctl_o-22"),
+	SLAVE_SMMU_SEC("apu_ao_ctl_o-23"),
+	SLAVE_ARE0("apu_ao_ctl_o-24"),
+	SLAVE_ARE1("apu_ao_ctl_o-25"),
+	SLAVE_SONC("apu_ao_ctl_o-26"),
+	SLAVE_RPC("apu_ao_ctl_o-28"),
+	SLAVE_PCU("apu_ao_ctl_o-29"),
+	SLAVE_AO_CTRL("apu_ao_ctl_o-30"),
+
+	/* ctrl index = 30 */
+	SLAVE_AO_CTRL("apu_ao_ctl_o-31"),
+	SLAVE_ACC("apu_ao_ctl_o-32"),
+	SLAVE_SEC("apu_ao_ctl_o-33"),
+	SLAVE_PLL("apu_ao_ctl_o-34"),
+	SLAVE_RPC_MDLA("apu_ao_ctl_o-35"),
+	SLAVE_TOP_PMU("apu_ao_ctl_o-36"),
+	SLAVE_AO_BCRM("apu_ao_ctl_o-37"),
+	SLAVE_AO_DAPC_WRAP("apu_ao_ctl_o-38"),
+	SLAVE_AO_DAPC_CON("apu_ao_ctl_o-39"),
+	SLAVE_UNDEFINE0("apu_ao_ctl_o-40"),
+
+	/* ctrl index = 40 */
+	SLAVE_UNDEFINE1("apu_ao_ctl_o-41"),
+	SLAVE_RCX_BULK0("apu_ao_ctl_o-42"),
+	SLAVE_UNDEFINE2("apu_ao_ctl_o-43"),
+	SLAVE_UNDEFINE3("apu_ao_ctl_o-44"),
+	SLAVE_UNDEFINE4("apu_ao_ctl_o-45"),
+	SLAVE_UNDEFINE5("apu_ao_ctl_o-46"),
+	SLAVE_UNDEFINE6("apu_ao_ctl_o-47"),
+	SLAVE_UNDEFINE7("apu_ao_ctl_o-48"),
+	SLAVE_DATA_BULK("apu_ao_ctl_o-49"),
+	SLAVE_ACX0_BULK("apu_ao_ctl_o-50"),
+
+	/* ctrl index = 50 */
+	SLAVE_ACX0_AO("apu_ao_ctl_o-51"),
+	SLAVE_ACX1_BULK("apu_ao_ctl_o-52"),
+	SLAVE_ACX1_AO("apu_ao_ctl_o-53"),
+	SLAVE_NCX_BULK("apu_ao_ctl_o-54"),
+	SLAVE_NCX_AO("apu_ao_ctl_o-55"),
+	SLAVE_ACX0_BULK("apu_rcx2acx0_o-0"),
+	SLAVE_ACX0_AO("apu_rcx2acx0_o-1"),
+	SLAVE_ACX0_BULK("apu_sae2acx0_o-0"),
+	SLAVE_ACX0_AO("apu_sae2acx0_o-1"),
+	SLAVE_ACX1_BULK("apu_rcx2acx1_o-0"),
+
+	/* ctrl index = 60 */
+	SLAVE_ACX1_AO("apu_rcx2acx1_o-1"),
+	SLAVE_ACX1_BULK("apu_sae2acx1_o-0"),
+	SLAVE_ACX1_AO("apu_sae2acx1_o-1"),
+	SLAVE_NCX_BULK("apu_rcx2ncx_o-0"),
+	SLAVE_NCX_AO("apu_rcx2ncx_o-1"),
+	SLAVE_NCX_BULK("apu_sae2ncx_o-0"),
+	SLAVE_NCX_AO("apu_sae2ncx_o-1"),
+};
+
+
+/* RCX CONTROL DEVAPC - apu_rcx_infra_dapc_con */
+static const struct apc_dom_16 APUSYS_CTRL_DAPC_RCX[] = {
+	/* ctrl index = 0 */
+	SLAVE_ACX0_BULK("acx0_apbs-0"),
+	SLAVE_ACX0_RPC("acx0_apbs-1"),
+	SLAVE_ACX0_AO_CTRL("acx0_apbs-2"),
+	SLAVE_UNDEFINE8("acx0_apbs-3"),
+	SLAVE_ACX1_BULK("acx1_apbs-0"),
+	SLAVE_ACX1_RPC("acx1_apbs-1"),
+	SLAVE_ACX1_AO_CTRL("acx1_apbs-2"),
+	SLAVE_UNDEFINE9("acx1_apbs-3"),
+	SLAVE_NCX_BULK("ncx_apbs-0"),
+	SLAVE_NCX_RPC("ncx_apbs-1"),
+
+	/* ctrl index = 10 */
+	SLAVE_NCX_AO_CTRL("ncx_apbs-2"),
+	SLAVE_UNDEFINE10("ncx_apbs-3"),
+	SLAVE_MD32_SYSCTRL("md32_apb_s-0"),
+	SLAVE_MD32_PMU("md32_apb_s-1"),
+	SLAVE_MD32_WDT("md32_apb_s-2"),
+	SLAVE_MD32_CACHE("md32_apb_s-3"),
+	SLAVE_ARE0("apusys_ao-0"),
+	SLAVE_ARE1("apusys_ao-1"),
+	SLAVE_SONC("apusys_ao-2"),
+	SLAVE_RPC("apusys_ao-3"),
+
+	/* ctrl index = 20 */
+	SLAVE_PCU("apusys_ao-4"),
+	SLAVE_AO_CTRL("apusys_ao-5"),
+	SLAVE_AO_CTRL("apusys_ao-6"),
+	SLAVE_SEC("apusys_ao-7"),
+	SLAVE_PLL("apusys_ao-8"),
+	SLAVE_RPC_MDLA("apusys_ao-9"),
+	SLAVE_TOP_PMU("apusys_ao-10"),
+	SLAVE_AO_BCRM("apusys_ao-11"),
+	SLAVE_AO_DAPC_WRAP("apusys_ao-12"),
+	SLAVE_AO_DAPC_CON("apusys_ao-13"),
+
+	/* ctrl index = 30 */
+	SLAVE_VCORE("apusys_ao-14"),
+	SLAVE_IOMMU0_BANK0("apusys_ao-15"),
+	SLAVE_IOMMU0_BANK1("apusys_ao-16"),
+	SLAVE_IOMMU0_BANK2("apusys_ao-17"),
+	SLAVE_IOMMU0_BANK3("apusys_ao-18"),
+	SLAVE_IOMMU0_BANK4("apusys_ao-19"),
+	SLAVE_IOMMU1_BANK0("apu_ao_ctl_o-20"),
+	SLAVE_IOMMU1_BANK1("apu_ao_ctl_o-21"),
+	SLAVE_IOMMU1_BANK2("apu_ao_ctl_o-22"),
+	SLAVE_IOMMU1_BANK3("apu_ao_ctl_o-23"),
+
+	/* ctrl index = 40 */
+	SLAVE_IOMMU1_BANK4("apu_ao_ctl_o-24"),
+	SLAVE_S0_SSC("apu_ao_ctl_o-25"),
+	SLAVE_N0_SSC("apu_ao_ctl_o-26"),
+	SLAVE_S1_SSC("apu_ao_ctl_o-27"),
+	SLAVE_N1_SSC("apu_ao_ctl_o-28"),
+	SLAVE_ACP_SSC("apu_ao_ctl_o-29"),
+	SLAVE_ACP_TCU_SSC("apu_ao_ctl_o-30"),
+	SLAVE_PTP_THM("apu_ao_ctl_o-31"),
+	SLAVE_WDEC("apu_ao_ctl_o-32"),
+	SLAVE_SMMU_IP_REG("apu_ao_ctl_o-33"),
+
+	/* ctrl index = 50 */
+	SLAVE_SMMU_NSEC("apu_ao_ctl_o-34"),
+	SLAVE_SMMU_SEC("apu_ao_ctl_o-35"),
+	SLAVE_DATA_BULK("noc_axi"),
+	SLAVE_MD32_DBG("md32_dbg"),
+	SLAVE_MDLA_DBG("mdla_dbg"),
+	SLAVE_INFRA_DBG("apb_infra_dbg"),
+	SLAVE_LOG_TOP0("apu_logtop-0"),
+	SLAVE_LOG_TOP1("apu_logtop-1"),
+	SLAVE_RCX_CFG("apu_rcx_cfg"),
+	SLAVE_ACX_IPS("apu_acx_ips"),
+
+	/* ctrl index = 60 */
+	SLAVE_SEMA_STIMER("apu_sema_stimer"),
+	SLAVE_EMI_CFG("apu_emi_cfg"),
+	SLAVE_CPE_SENSOR("apu_cpe_sensor"),
+	SLAVE_CPE_COEF("apu_cpe_coef"),
+	SLAVE_CPE_CTRL("apu_cpe_ctrl"),
+	SLAVE_TPPA("apu_dfd"),
+	SLAVE_SENSOR_ACX0_DLA0("apu_sen_acx0_dla0"),
+	SLAVE_SENSOR_ACX0_VPU("apu_sen_acx0_vpu"),
+	SLAVE_SENSOR_ACX1_DLA0("apu_sen_acx1_dla0"),
+	SLAVE_SENSOR_ACX1_VPU("apu_sen_acx1_vpu"),
+
+	/* ctrl index = 70 */
+	SLAVE_SENSOR_NCX_DLA0("apu_sen_ncx_dla0"),
+	SLAVE_SENSOR_NCX_NVE("apu_sen_ncx_nve"),
+	SLAVE_RCX_TCU0("noc_cfg-0"),
+	SLAVE_RCX_TCU1("noc_cfg-1"),
+	SLAVE_RCX_TCU2("noc_cfg-2"),
+	SLAVE_RCX_TCU3("noc_cfg-3"),
+	SLAVE_RCX_TCU4("noc_cfg-4"),
+	SLAVE_RCX_TCU5("noc_cfg-5"),
+	SLAVE_RCX_TCU6("noc_cfg-6"),
+	SLAVE_RCX_NOC_CFG("noc_cfg-7"),
+
+	/* ctrl index = 80 */
+	SLAVE_SCMDQ("apu_hse-0"),
+	SLAVE_HSE("apu_hse-1"),
+	SLAVE_MDLA_CORE_CTRL("mdla_cfg-0"),
+	SLAVE_MDLA_BIU("mdla_cfg-1"),
+	SLAVE_MDLA_PMU("mdla_cfg-2"),
+	SLAVE_MDLA_CMDE("mdla_cfg-3"),
+	SLAVE_EDPA0("apu_edpa-0"),
+	SLAVE_EDPA1("apu_edpa-1"),
+	SLAVE_RCX_BCRM("infra_bcrm"),
+	SLAVE_RCX_DAPC_WRAP("infra_dpac_wrap"),
+
+	/* ctrl index = 90 */
+	SLAVE_RCX_DAPC_CON("infra_dapc_con"),
+	SLAVE_RCX_CMU("rcx_cmu"),
+	SLAVE_RCX_ACS("apu_rcx_acs"),
+	SLAVE_RCX_CBFC("rcx_cbfc"),
+	SLAVE_ACC("acc"),
+};
+
+static enum apusys_apc_err_status set_slave_ctrl_apc(uint32_t slave,
+						     enum apusys_apc_type type,
+						     enum apusys_apc_domain_id domain_id,
+						     enum apusys_apc_perm_type perm)
+{
+	uint32_t apc_register_index;
+	uint32_t apc_set_index;
+	uint32_t base = 0;
+	uint32_t clr_bit;
+	uint32_t set_bit;
+	uint32_t slave_num_in_1_dom;
+	uint32_t slave_num, dom_num;
+	uint32_t dapc_base;
+
+	if (perm >= PERM_NUM) {
+		ERROR("%s: permission type:0x%x is not supported!\n", __func__, perm);
+		return APUSYS_APC_ERR_PERMISSION_NOT_SUPPORTED;
+	}
+
+	switch (type) {
+	case DAPC_AO:
+		slave_num_in_1_dom = APUSYS_CTRL_DAPC_AO_SLAVE_NUM_IN_1_DOM;
+		slave_num = APUSYS_CTRL_DAPC_AO_SLAVE_NUM;
+		dom_num = APUSYS_CTRL_DAPC_AO_DOM_NUM;
+		dapc_base = APUSYS_CTRL_DAPC_AO_BASE;
+		break;
+	case DAPC_RCX:
+		slave_num_in_1_dom = APUSYS_CTRL_DAPC_RCX_SLAVE_NUM_IN_1_DOM;
+		slave_num = APUSYS_CTRL_DAPC_RCX_SLAVE_NUM;
+		dom_num = APUSYS_CTRL_DAPC_RCX_DOM_NUM;
+		dapc_base = APUSYS_CTRL_DAPC_RCX_BASE;
+		break;
+	default:
+		ERROR("%s: unsupported devapc type: %u\n", __func__, type);
+		return APUSYS_APC_ERR_GENERIC;
+	}
+
+	apc_register_index = slave / slave_num_in_1_dom;
+	apc_set_index = slave % slave_num_in_1_dom;
+
+	clr_bit = DEVAPC_MASK << (apc_set_index * DEVAPC_DOM_SHIFT);
+	set_bit = (uint32_t)perm << (apc_set_index * DEVAPC_DOM_SHIFT);
+
+	if (slave < slave_num && domain_id < dom_num) {
+		base = dapc_base + domain_id * DEVAPC_DOM_SIZE
+		       + apc_register_index * DEVAPC_REG_SIZE;
+	} else {
+		ERROR("%s: out of boundary, devapc type: %d, slave: 0x%x, domain_id: 0x%x\n",
+			__func__, type, slave, domain_id);
+		return APUSYS_APC_ERR_OUT_OF_BOUNDARY;
+	}
+
+	if (!base)
+		return APUSYS_APC_ERR_GENERIC;
+
+	mmio_clrsetbits_32(base, clr_bit, set_bit);
+	return APUSYS_APC_OK;
+}
+
+static enum apusys_apc_err_status set_slave_ao_ctrl_apc(uint32_t slave,
+							enum apusys_apc_domain_id domain_id,
+							enum apusys_apc_perm_type perm)
+{
+	return set_slave_ctrl_apc(slave, DAPC_AO, domain_id, perm);
+}
+
+static enum apusys_apc_err_status set_slave_rcx_ctrl_apc(uint32_t slave,
+							 enum apusys_apc_domain_id domain_id,
+							 enum apusys_apc_perm_type perm)
+{
+	return set_slave_ctrl_apc(slave, DAPC_RCX, domain_id, perm);
+}
+
+static void apusys_devapc_init(uint32_t base)
+{
+	mmio_write_32(APUSYS_DAPC_CON(base), APUSYS_DAPC_CON_VIO_MASK);
+}
+
+int apusys_devapc_ao_init(void)
+{
+	int32_t ret = APUSYS_APC_OK;
+
+	apusys_devapc_init(APUSYS_CTRL_DAPC_AO_BASE);
+
+	ret = SET_APUSYS_DAPC_V1(APUSYS_CTRL_DAPC_AO, set_slave_ao_ctrl_apc);
+
+	if (ret) {
+		ERROR("[APUAPC_AO] %s: set_apusys_ao_ctrl_dapc failed\n", __func__);
+		return ret;
+	}
+
+#ifdef DUMP_CFG
+	DUMP_APUSYS_DAPC_V1(APUSYS_CTRL_DAPC_AO);
+#endif
+
+	INFO("[APUAPC_AO] %s done\n", __func__);
+
+	return ret;
+}
+
+int apusys_devapc_rcx_init(void)
+{
+	int32_t ret = APUSYS_APC_OK;
+
+	apusys_devapc_init(APUSYS_CTRL_DAPC_RCX_BASE);
+
+	ret = SET_APUSYS_DAPC_V1(APUSYS_CTRL_DAPC_RCX, set_slave_rcx_ctrl_apc);
+	if (ret) {
+		ERROR("[APUAPC_RCX] %s: set_slave_rcx_ctrl_apc failed\n", __func__);
+		return ret;
+	}
+
+#ifdef DUMP_CFG
+	DUMP_APUSYS_DAPC_V1(APUSYS_CTRL_DAPC_RCX);
+#endif
+
+	INFO("[APUAPC_RCX] %s done\n", __func__);
+
+	return ret;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.h b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.h
new file mode 100644
index 0000000..8d6204e
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_DEVAPC_H
+#define APUSYS_DEVAPC_H
+
+enum apusys_apc_type {
+	DAPC_AO = 0,
+	DAPC_RCX
+};
+
+int apusys_devapc_ao_init(void);
+int apusys_devapc_rcx_init(void);
+
+#endif /* APUSYS_DEVAPC_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h
new file mode 100644
index 0000000..af63c0c
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_DEVAPC_DEF_H
+#define APUSYS_DEVAPC_DEF_H
+
+#include <lib/mmio.h>
+
+#include <devapc/apusys_dapc_v1.h>
+
+/* Control */
+#define SLAVE_RCX_BULK0		SLAVE_FORBID_EXCEPT_D0_D11_NO_PROTECT_D3_D5_D8_SEC_RW
+#define SLAVE_RCX_BULK1		SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D5_D8_SEC_RW
+#define SLAVE_MD32_APB		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D3_D5_SEC_RW
+#define SLAVE_ACP_TCU_SSC	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_VCORE		SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D3_D5_SEC_RW
+#define SLAVE_WDEC		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_SMMU_IP_REG	SLAVE_FORBID_EXCEPT_D3_D5_SEC_RW_D0_D4_D11_NO_PROTECT
+#define SLAVE_SMMU_NSEC		SLAVE_FORBID_EXCEPT_D5_SEC_RW_D0_NO_PROTECT
+#define SLAVE_SMMU_SEC		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_RPC		SLAVE_FORBID_EXCEPT_D3_D5_SEC_RW_D0_D11_NO_PROTECT
+#define SLAVE_PCU		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D3_D5_SEC_RW
+#define SLAVE_AO_CTRL		SLAVE_FORBID_EXCEPT_D0_D3_D5_SEC_RW
+#define SLAVE_ACC		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D3_D5_SEC_RW
+#define SLAVE_PLL		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_D8_SEC_RW
+#define SLAVE_SEC		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_ARE0		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ARE1		SLAVE_FORBID_EXCEPT_D0_D11_NO_PROTECT_D3_D5_D8_SEC_RW
+#define SLAVE_RPC_MDLA		SLAVE_FORBID_EXCEPT_D5_D8_SEC_RW
+#define SLAVE_MDLA_DBG		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_TOP_PMU		SLAVE_FORBID_EXCEPT_D5_D8_SEC_RW
+#define SLAVE_UNDEFINE0		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE1		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE2		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE3		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE4		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE5		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE6		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE7		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE8		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE9		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_UNDEFINE10	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_DATA_BULK		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_AO_BCRM		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_AO_DAPC_WRAP	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_AO_DAPC_CON	SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_ACX0_AO		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX0_BULK		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX0_RPC		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX0_AO_CTRL	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_ACX1_AO		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX1_BULK		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX1_RPC		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_ACX1_AO_CTRL	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_NCX_AO		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_NCX_BULK		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#define SLAVE_NCX_RPC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_NCX_AO_CTRL	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_MD32_SYSCTRL	SLAVE_FORBID_EXCEPT_D0_D3_D5_SEC_RW
+#define SLAVE_MD32_PMU		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D3_D5_SEC_RW
+#define SLAVE_LOG_TOP0		SLAVE_FORBID_EXCEPT_D0_D5_D7_D14_NO_PROTECT
+#define SLAVE_LOG_TOP1		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_CFG		SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D3_D5_SEC_RW
+#define SLAVE_ACX_IPS		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_TCU0		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_RCX_TCU1		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_RCX_TCU2		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_TCU3		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_TCU4		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_TCU5		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_TCU6		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_NOC_CFG	SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_MDLA_CORE_CTRL	SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_MDLA_BIU		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_MDLA_PMU		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_MDLA_CMDE		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_EDPA0		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_EDPA1		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_CMU		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_RCX_ACS		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_MD32_WDT		SLAVE_FORBID_EXCEPT_D0_D3_D5_SEC_RW
+#define SLAVE_MD32_CACHE	SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_MD32_DBG		SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D5_SEC_RW
+#define SLAVE_INFRA_DBG		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_IOMMU0_BANK0	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU0_BANK1	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU0_BANK2	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU0_BANK3	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU0_BANK4	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU1_BANK0	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU1_BANK1	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU1_BANK2	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU1_BANK3	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_IOMMU1_BANK4	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_S0_SSC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_N0_SSC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_ACP_SSC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_S1_SSC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_N1_SSC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SEMA_STIMER	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_EMI_CFG		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_CPE_SENSOR	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_CPE_COEF		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_CPE_CTRL		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_TPPA		SLAVE_FORBID_EXCEPT_D5_D8_SEC_RW
+#define SLAVE_SENSOR_ACX0_DLA0	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SENSOR_ACX0_VPU	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SENSOR_ACX1_DLA0	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SENSOR_ACX1_VPU	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SENSOR_NCX_DLA0	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SENSOR_NCX_NVE	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_BCRM		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_DAPC_WRAP	SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_DAPC_CON	SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_HSE		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_RCX_CBFC		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+#define SLAVE_SONC		SLAVE_FORBID_EXCEPT_D0_D5_SEC_RW
+#define SLAVE_SCMDQ		SLAVE_FORBID_EXCEPT_D5_SEC_RW
+
+#if DEBUG
+#define SLAVE_PTP_THM		SLAVE_FORBID_EXCEPT_D0_NO_PROTECT_D5_SEC_RW
+#else
+#define SLAVE_PTP_THM		SLAVE_FORBID_EXCEPT_D0_SEC_RW_NS_R_D5_SEC_RW
+#endif
+
+/* Power Domain: AO */
+#define APUSYS_CTRL_DAPC_AO_SLAVE_NUM_IN_1_DOM	(16)
+#define APUSYS_CTRL_DAPC_AO_DOM_NUM		(16)
+#define APUSYS_CTRL_DAPC_AO_SLAVE_NUM		(67)	/* 0~66 */
+#define DEVAPC_MASK				(0x3U)
+#define DEVAPC_DOM_SHIFT			(2)
+
+/* Power Domain: RCX */
+#define APUSYS_CTRL_DAPC_RCX_SLAVE_NUM_IN_1_DOM	(16)
+#define APUSYS_CTRL_DAPC_RCX_DOM_NUM		(16)
+#define APUSYS_CTRL_DAPC_RCX_SLAVE_NUM		(95)	/* 0~94 */
+
+/* Dump Config */
+#define DUMP_CFG
+
+#endif
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_power.c b/plat/mediatek/drivers/apusys/mt8196/apusys_power.c
new file mode 100644
index 0000000..4262d63
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_power.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+
+#define SPMI_ENABLE	(0)
+
+#if SPMI_ENABLE
+#include <include/drivers/spmi_api.h>
+#endif
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "apusys_power.h"
+
+static void apu_w_are(int entry, uint32_t reg, uint32_t data)
+{
+	uint32_t are_entry_addr;
+
+	are_entry_addr = APUSYS_BASE + APU_ARE + ARE_REG_SIZE * ARE_ENTRY(entry);
+	mmio_write_32(are_entry_addr, reg);
+	mmio_write_32((are_entry_addr + ARE_REG_SIZE), data);
+}
+
+static void get_pll_pcw(uint32_t clk_rate, uint32_t *r1, uint32_t *r2)
+{
+	unsigned int fvco = clk_rate;
+	unsigned int pcw_val;
+	unsigned int postdiv_val = 1;
+	unsigned int postdiv_reg = 0;
+
+	while (fvco <= OUT_CLK_FREQ_MIN) {
+		postdiv_val = postdiv_val << 1;
+		postdiv_reg = postdiv_reg + 1;
+		fvco = fvco << 1;
+	}
+
+	pcw_val = (fvco * (1 << DDS_SHIFT)) / BASIC_CLK_FREQ;
+
+	if (postdiv_reg == 0) {
+		pcw_val = pcw_val * 2;
+		postdiv_val = postdiv_val << 1;
+		postdiv_reg = postdiv_reg + 1;
+	}
+
+	*r1 = postdiv_reg;
+	*r2 = pcw_val;
+}
+
+static void buck_off_by_pcu(uint32_t ofs, uint32_t shift, uint32_t slv_id)
+{
+	uint32_t pmif_id = 0x0;
+	int retry = 10;
+
+	mmio_setbits_32(APUSYS_PCU + APU_PCUTOP_CTRL_SET, PMIC_IRQ_EN);
+	mmio_write_32(APUSYS_PCU + APU_PCU_PMIC_TAR_BUF1,
+		      (ofs << PMIC_OFF_ADDR_OFF) | BIT(shift));
+	mmio_write_32(APUSYS_PCU + APU_PCU_PMIC_TAR_BUF2,
+		      (slv_id << PMIC_SLVID_OFF) | (pmif_id << PMIC_PMIFID_OFF) | PCU_BUCK_OFF_CMD);
+	mmio_write_32(APUSYS_PCU + APU_PCU_PMIC_CMD, PMIC_CMD_EN);
+
+	while ((mmio_read_32(APUSYS_PCU + APU_PCU_PMIC_IRQ) & PMIC_CMD_IRQ) == 0) {
+		udelay(10);
+		if (--retry < 0)
+			ERROR("%s wait APU_PCU_PMIC_IRQ timeout !\n", __func__);
+	}
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_PMIC_IRQ, PMIC_CMD_IRQ);
+}
+
+static void apu_buck_off_cfg(void)
+{
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(10));
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(9));
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(12));
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(14));
+
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(10));
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(9));
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(12));
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CLR, BIT(14));
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, BUCK_PROT_REQ_SET);
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, SRAM_AOC_LHENB_SET);
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, SRAM_AOC_ISO_SET);
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, PLL_AOC_ISO_EN_SET);
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, BUCK_ELS_EN_SET);
+	udelay(1);
+
+	mmio_write_32(APUSYS_RPC + APU_RPC_HW_CON, BUCK_AO_RST_B_CLR);
+	udelay(1);
+
+	buck_off_by_pcu(BUCK_VAPU_PMIC_REG_EN_CLR_ADDR, BUCK_VAPU_PMIC_REG_EN_SHIFT,
+			BUCK_VAPU_PMIC_ID);
+
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(6));
+	udelay(1);
+	mmio_setbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(7));
+	udelay(1);
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(6));
+	udelay(1);
+	mmio_clrbits_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_SET, BIT(7));
+	udelay(1);
+}
+
+static void apu_acc_init(void)
+{
+	uint32_t top_acc_base_arr[] = {MNOC_ACC_BASE, UP_ACC_BASE};
+	uint32_t eng_acc_base_arr[] = {MVPU_ACC_BASE, MDLA_ACC_BASE};
+	int acc_idx;
+	int are_idx = ACC_ENTRY_BEGIN;
+	uint32_t base_reg;
+
+	for (acc_idx = 0 ; acc_idx < ARRAY_SIZE(top_acc_base_arr) ; acc_idx++) {
+		base_reg = APUSYS_ACC + top_acc_base_arr[acc_idx];
+#if CFG_APU_ARDCM_ENABLE
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL1, APU_ARDCM_CTRL1_VAL_0);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL0, APU_ARDCM_CTRL0_VAL_0);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL1, APU_ARDCM_CTRL1_VAL_1);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL0, APU_ARDCM_CTRL0_VAL_1);
+#endif
+		apu_w_are(are_idx++, base_reg + APU_ACC_CONFG_CLR0, CGEN_SOC);
+		apu_w_are(are_idx++, base_reg + APU_ACC_CONFG_SET0, HW_CTRL_EN);
+	}
+
+	for (acc_idx = 0 ; acc_idx < ARRAY_SIZE(eng_acc_base_arr) ; acc_idx++) {
+		base_reg = APUSYS_ACC + eng_acc_base_arr[acc_idx];
+#if CFG_APU_ARDCM_ENABLE
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL1, APU_ARDCM_CTRL1_VAL_0);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL0, APU_ARDCM_CTRL0_VAL_0);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL1, APU_ARDCM_CTRL1_VAL_1);
+		apu_w_are(are_idx++, base_reg + APU_ARDCM_CTRL0, APU_ARDCM_CTRL0_VAL_1);
+#endif
+		apu_w_are(are_idx++, base_reg + APU_ACC_CONFG_CLR0, CGEN_SOC);
+		apu_w_are(are_idx++, base_reg + APU_ACC_CONFG_SET0, HW_CTRL_EN);
+		apu_w_are(are_idx++, base_reg + APU_ACC_AUTO_CTRL_SET0, CLK_REQ_SW_EN);
+	}
+}
+
+static void apu_pll_init(void)
+{
+	uint32_t pll_base_arr[] = {MNOC_PLL_BASE, UP_PLL_BASE, MVPU_PLL_BASE, MDLA_PLL_BASE};
+	int32_t pll_freq_out[] = {
+		APUPLL0_DEFAULT_FREQ,
+		APUPLL1_DEFAULT_FREQ,
+		APUPLL2_DEFAULT_FREQ,
+		APUPLL3_DEFAULT_FREQ
+	};
+	uint32_t pcw_val, posdiv_val;
+	int pll_idx, are_idx;
+	uint32_t base_reg;
+
+	mmio_setbits_32(APUSYS_BASE + APU_ARE, ARE_RCX_AO_EN);
+	mmio_setbits_32(APUSYS_BASE + APU_ARE_REG, ARE_RCX_AO_EN);
+
+	mmio_write_32(APUSYS_BASE + APU_ARE + ARE_RCX_AO_CONFIG, ARE_ENTRY(RCX_AO_BEGIN) |
+		      (ARE_ENTRIES(RCX_AO_BEGIN, RCX_AO_END) << ARE_RCX_AO_CONFIG_HIGH_OFF));
+
+	are_idx = PLL_ENTRY_BEGIN;
+	for (pll_idx = 0 ; pll_idx < ARRAY_SIZE(pll_base_arr) ; pll_idx++) {
+		base_reg = APUSYS_PLL + pll_base_arr[pll_idx];
+
+		apu_w_are(are_idx++, base_reg + RG_PLLGP_LVR_REFSEL, RG_PLLGP_LVR_REFSEL_VAL);
+		apu_w_are(are_idx++, base_reg + PLL1CPLL_FHCTL_HP_EN, FHCTL_CTRL);
+		apu_w_are(are_idx++, base_reg + PLL1CPLL_FHCTL_RST_CON, FHCTL_NO_RESET);
+		apu_w_are(are_idx++, base_reg + PLL1CPLL_FHCTL_CLK_CON, FHCTL_CLKEN);
+		apu_w_are(are_idx++, base_reg + PLL1CPLL_FHCTL0_CFG,
+			  FHCTL_HOPPING_EN | FHCTL_SFSTR0_EN);
+
+		posdiv_val = 0;
+		pcw_val = 0;
+		get_pll_pcw(pll_freq_out[pll_idx], &posdiv_val, &pcw_val);
+
+		apu_w_are(are_idx++, base_reg + PLL1C_PLL1_CON1,
+			  ((0x1U << RG_PLL_SDM_PCW_CHG_OFF) |
+			   (posdiv_val << RG_PLL_POSDIV_OFF) | pcw_val));
+
+		apu_w_are(are_idx++, base_reg + PLL1CPLL_FHCTL0_DDS,
+			  ((0x1U << FHCTL0_PLL_TGL_ORG) | pcw_val));
+	}
+}
+
+static void apu_are_init(void)
+{
+	int entry = 0;
+
+	mmio_clrbits_32(APUSYS_BASE + APU_ARE, 0xFFFU << ARE_VCORE_OFF);
+
+	mmio_setbits_32(APUSYS_BASE + APU_ARE, ARE_VCORE_EN);
+	mmio_setbits_32(APUSYS_BASE + APU_ARE_REG, ARE_VCORE_EN);
+
+	for (entry = ARE_CONF_START; entry < ARE_CONF_END; entry += 4)
+		mmio_write_32(APUSYS_BASE + APU_ARE + entry, 0);
+}
+
+static void apu_rpclite_init(void)
+{
+	uint32_t sleep_type_offset[] = {
+		APU_RPC_SW_TYPE1_OFF,
+		APU_RPC_SW_TYPE2_OFF,
+		APU_RPC_SW_TYPE3_OFF,
+		APU_RPC_SW_TYPE4_OFF
+	};
+	uint32_t rpc_lite_base[] = {
+		APU_ACX0_RPC_LITE,
+		APU_ACX1_RPC_LITE,
+		APU_ACX2_RPC_LITE,
+	};
+	int ofs_idx, rpc_lite_idx;
+	uint32_t base;
+
+	for (rpc_lite_idx = 0; rpc_lite_idx < ARRAY_SIZE(rpc_lite_base); rpc_lite_idx++) {
+		base = APUSYS_BASE + rpc_lite_base[rpc_lite_idx];
+		for (ofs_idx = 0; ofs_idx < ARRAY_SIZE(sleep_type_offset); ofs_idx++)
+			mmio_clrbits_32(base + sleep_type_offset[ofs_idx],
+					SW_TYPE_MVPU_MDLA_RV);
+		mmio_setbits_32(base + APU_RPC_TOP_SEL, TOP_SEL_VAL);
+	}
+}
+
+static void apu_rpc_mdla_init(void)
+{
+	mmio_clrbits_32(APUSYS_BASE + APU_RPCTOP_MDLA + APU_RPC_SW_TYPE0_OFF, SW_TYPE_MVPU_MDLA_RV);
+}
+
+static void apu_rpc_init(void)
+{
+	mmio_write_32(APUSYS_RPC + APU_RPC_SW_TYPE0_OFF, RPC_TYPE_INIT_VAL);
+	mmio_setbits_32(APUSYS_RPC + APU_RPC_TOP_SEL, RPC_TOP_SEL_VAL);
+
+#if !CFG_CTL_RPC_BY_CE
+	mmio_clrbits_32(APUSYS_RPC + APU_RPC_TOP_SEL, CE_ENABLE);
+#endif
+
+	mmio_setbits_32(APUSYS_RPC + APU_RPC_TOP_SEL_1, BUCK_PROT_SEL);
+}
+
+static int apu_pcu_init(void)
+{
+	uint32_t pmif_id = 0x0;
+	uint32_t slave_id = BUCK_VAPU_PMIC_ID;
+	uint32_t en_set_offset = BUCK_VAPU_PMIC_REG_EN_SET_ADDR;
+	uint32_t en_clr_offset = BUCK_VAPU_PMIC_REG_EN_CLR_ADDR;
+	uint32_t en_shift = BUCK_VAPU_PMIC_REG_EN_SHIFT;
+#if SPMI_ENABLE
+	struct spmi_device *vsram_sdev;
+#endif
+	unsigned char vsram = 0;
+
+	mmio_write_32(APUSYS_PCU + APU_PCUTOP_CTRL_SET, AUTO_BUCK_EN);
+
+	mmio_write_32((APUSYS_PCU + APU_PCU_BUCK_STEP_SEL), BUCK_STEP_SEL_VAL);
+
+#if SPMI_ENABLE
+	vsram_sdev = get_spmi_device(SPMI_MASTER_1, SPMI_SLAVE_4);
+	if (!vsram_sdev) {
+		ERROR("[APUPW] VSRAM BUCK4 get device fail\n");
+		return -1;
+	}
+
+	if (spmi_ext_register_readl(vsram_sdev, MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR, &vsram, 1)) {
+		ERROR("[APUPW] VSRAM BUCK4 read fail\n");
+		return -1;
+	}
+#endif
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_DAT0_L,
+		      (BUCK_VAPU_PMIC_REG_VOSEL_ADDR << PMIC_OFF_ADDR_OFF) | vsram);
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_DAT0_H,
+		      (slave_id << PMIC_SLVID_OFF) | (pmif_id << PMIC_PMIFID_OFF) | PCU_CMD_OP_W);
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_DAT1_L,
+		      (en_set_offset << PMIC_OFF_ADDR_OFF) | (0x1U << en_shift));
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_DAT1_H,
+		      (slave_id << PMIC_SLVID_OFF) | (pmif_id << PMIC_PMIFID_OFF) | PCU_CMD_OP_W);
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_OFF_DAT0_L,
+		      (en_clr_offset << PMIC_OFF_ADDR_OFF) | (0x1U << en_shift));
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_OFF_DAT0_H,
+		      (slave_id << PMIC_SLVID_OFF) | (pmif_id << PMIC_PMIFID_OFF) | PCU_CMD_OP_W);
+
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_SLE0, 0);
+	mmio_write_32(APUSYS_PCU + APU_PCU_BUCK_ON_SLE1, VAPU_BUCK_ON_SETTLE_TIME);
+
+	return 0;
+}
+
+static void apu_aoc_init(void)
+{
+	uint32_t reg;
+
+	mmio_setbits_32(SPM_BASE + 0xF6C, BIT(4));
+	mmio_clrbits_32(SPM_BASE + 0x414, BIT(1));
+
+	mmio_write_32(APUSYS_AO_CTL + APUSYS_AO_SRAM_CONFIG, APUSYS_AO_SRAM_EN);
+	udelay(1);
+
+	reg = APUSYS_AO_CTL + APUSYS_AO_SRAM_SET;
+
+#if !CFG_CTL_RPC_BY_CE
+	mmio_setbits_32(reg, BIT(8));
+	udelay(1);
+	mmio_setbits_32(reg, BIT(11));
+	udelay(1);
+	mmio_setbits_32(reg, BIT(13));
+	udelay(1);
+
+	mmio_clrbits_32(reg, BIT(8));
+	udelay(1);
+	mmio_clrbits_32(reg, BIT(11));
+	udelay(1);
+	mmio_clrbits_32(reg, BIT(13));
+#else
+	mmio_setbits_32(reg, BIT(9));
+	mmio_setbits_32(reg, BIT(12));
+	mmio_setbits_32(reg, BIT(14));
+
+	mmio_clrbits_32(reg, BIT(9));
+	mmio_clrbits_32(reg, BIT(12));
+	mmio_clrbits_32(reg, BIT(14));
+	udelay(1);
+#endif
+
+	reg = APUSYS_RPC + APU_RPC_HW_CON;
+
+	mmio_write_32(reg, BUCK_ELS_EN_CLR);
+	udelay(1);
+
+	mmio_write_32(reg, BUCK_AO_RST_B_SET);
+	udelay(1);
+
+	mmio_write_32(reg, BUCK_PROT_REQ_CLR);
+	udelay(1);
+
+	mmio_write_32(reg, SRAM_AOC_ISO_CLR);
+	udelay(1);
+
+	mmio_write_32(reg, PLL_AOC_ISO_EN_CLR);
+	udelay(1);
+}
+
+static int init_hw_setting(void)
+{
+	int ret;
+
+	apu_aoc_init();
+	ret = apu_pcu_init();
+	apu_rpc_init();
+	apu_rpc_mdla_init();
+	apu_rpclite_init();
+	apu_are_init();
+	apu_pll_init();
+	apu_acc_init();
+	apu_buck_off_cfg();
+
+	return ret;
+}
+
+int apusys_power_init(void)
+{
+	int ret;
+
+	ret = init_hw_setting();
+	if (ret != 0)
+		ERROR("%s init HW failed\n", __func__);
+	else
+		INFO("%s init HW done\n", __func__);
+
+	mmio_write_32(APU_ACE_HW_FLAG_DIS, APU_ACE_DIS_FLAG_VAL);
+
+	return ret;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_power.h b/plat/mediatek/drivers/apusys/mt8196/apusys_power.h
new file mode 100644
index 0000000..ddf35c5
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_power.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_POWER_H
+#define APUSYS_POWER_H
+
+#include <platform_def.h>
+
+#define CFG_APU_ARDCM_ENABLE	(0)
+#define CFG_CTL_RPC_BY_CE	(1)
+
+#define APUPLL0_DEFAULT_FREQ	(800)
+#define APUPLL1_DEFAULT_FREQ	(960)
+#define APUPLL2_DEFAULT_FREQ	(1200)
+#define APUPLL3_DEFAULT_FREQ	(1230)
+
+enum t_acx_id {
+	D_ACX0 = 0,
+	ACX0,
+	ACX1,
+	ACX2,
+	CLUSTER_NUM,
+	RCX,
+};
+
+enum rcx_ao_range {
+	RCX_AO_BEGIN = 0,
+	PLL_ENTRY_BEGIN = 0,
+	PLL_ENTRY_END = 27,
+	ACC_ENTRY_BEGIN = 28,
+	ACC_ENTRY_END = 37,
+	RCX_AO_END = 37,
+};
+
+#define SYS_VLP			(0x000000)
+#define SYS_SPM			(0x000000)
+#define APU_RCX			(0x020000)
+#define APU_RCX_DLA		(0x040000)
+#define APU_ARE			(0x0a0000)
+#define APU_ARE_REG		(0x0b0000)
+#define APU_VCORE		(0x0e0000)
+#define APU_MD32_MBOX		(0x0e1000)
+#define APU_RPC			(0x0f0000)
+#define APU_PCU			(0x0f1000)
+#define APU_AO_CTL		(0x0f2000)
+#define APU_ACC			(0x0f3000)
+#define APU_PLL			(0x0f6000)
+#define APU_RPCTOP_MDLA		(0x0F7400)
+#define APU_ACX0		(0x100000)
+#define APU_ACX0_RPC_LITE	(0x140000)
+#define APU_ACX1		(0x200000)
+#define APU_ACX1_RPC_LITE	(0x240000)
+#define APU_ACX2		(0x300000)
+#define APU_ACX2_RPC_LITE	(0x340000)
+
+/* APU GRP offset define */
+#define APU_GRP_0_BASE		(0x0000)
+#define APU_GRP_1_BASE		(0x0400)
+#define APU_GRP_2_BASE		(0x0800)
+#define APU_GRP_3_BASE		(0x0C00)
+
+#define MDLA_PLL_BASE		APU_GRP_0_BASE
+#define MVPU_PLL_BASE		APU_GRP_1_BASE
+#define MNOC_PLL_BASE		APU_GRP_2_BASE
+#define UP_PLL_BASE		APU_GRP_3_BASE
+
+#define MDLA_ACC_BASE		APU_GRP_0_BASE
+#define MVPU_ACC_BASE		APU_GRP_1_BASE
+#define MNOC_ACC_BASE		APU_GRP_2_BASE
+#define UP_ACC_BASE		APU_GRP_3_BASE
+
+/* RPC / RPC_LITE control */
+#define APU_RPC_SW_TYPE0_OFF	(0x200)
+#define APU_RPC_SW_TYPE1_OFF	(0x204)
+#define APU_RPC_SW_TYPE2_OFF	(0x208)
+#define APU_RPC_SW_TYPE3_OFF	(0x20C)
+#define APU_RPC_SW_TYPE4_OFF	(0x210)
+#define SW_TYPE_MVPU_MDLA_RV	BIT(0)
+#define CE_ENABLE		BIT(10)
+#define BUCK_PROT_SEL		BIT(20)
+#define RPC_TYPE_INIT_VAL	(0x18)
+#define TOP_SEL_VAL		(0xB2)
+#define RPC_TOP_SEL_VAL		(0xB800D50F)
+
+#define APUSYS_AO_CTL		(APUSYS_BASE + APU_AO_CTL)
+#define APUSYS_RPC		(APUSYS_BASE + APU_RPC)
+#define APUSYS_ACC		(APUSYS_BASE + APU_ACC)
+#define APUSYS_PLL		(APUSYS_BASE + APU_PLL)
+#define APUSYS_PCU		(APUSYS_BASE + APU_PCU)
+
+/* ARE control */
+#define ARE_VCORE_EN		BIT(20)
+#define ARE_RCX_AO_EN		BIT(21)
+#define ARE_VCORE_OFF		(20)
+#define ARE_CONF_START		(0x04)
+#define ARE_CONF_END		(0x6C)
+#define ARE_REG_SIZE		(4)
+
+/* ACC offset */
+#define APU_ACC_CONFG_SET0	(0x000)
+#define APU_ACC_CONFG_CLR0	(0x010)
+#define APU_ACC_AUTO_CTRL_SET0	(0x084)
+#define APU_ARDCM_CTRL0		(0x100)
+#define APU_ARDCM_CTRL1		(0x104)
+
+/* ACC control */
+#define APU_ARDCM_CTRL0_VAL_0	(0x00000016)
+#define APU_ARDCM_CTRL0_VAL_1	(0x00000036)
+#define APU_ARDCM_CTRL1_VAL_0	(0x00001006)
+#define APU_ARDCM_CTRL1_VAL_1	(0x07F0F006)
+#define CGEN_SOC		BIT(2)
+#define CLK_REQ_SW_EN		BIT(8)
+#define HW_CTRL_EN		BIT(15)
+
+/* APU PLL1C offset */
+#define RG_PLLGP_LVR_REFSEL	(0x204)
+#define PLL1C_PLL1_CON1		(0x20C)
+#define PLL1CPLL_FHCTL_HP_EN	(0x300)
+#define PLL1CPLL_FHCTL_CLK_CON	(0x308)
+#define PLL1CPLL_FHCTL_RST_CON	(0x30C)
+#define PLL1CPLL_FHCTL0_CFG	(0x314)
+#define PLL1CPLL_FHCTL0_DDS	(0x31C)
+
+/* PLL control */
+#define RG_PLLGP_LVR_REFSEL_VAL	(0x3)
+#define FHCTL_CTRL		(0x1)
+#define FHCTL_NO_RESET		(0x1)
+#define FHCTL_CLKEN		(0x1)
+#define FHCTL_HOPPING_EN	BIT(0)
+#define FHCTL_SFSTR0_EN		BIT(2)
+#define RG_PLL_SDM_PCW_CHG_OFF	(31)
+#define RG_PLL_POSDIV_OFF	(24)
+#define FHCTL0_PLL_TGL_ORG	(31)
+
+/* RPC offset define */
+#define APU_RPC_TOP_SEL		(0x0004)
+#define APU_RPC_TOP_SEL_1	(0x0018)
+#define APU_RPC_HW_CON		(0x001C)
+#define APU_RPC_STATUS_1	(0x0034)
+#define APU_RPC_INTF_PWR_RDY	(0x0044)
+
+/* RPC control */
+#define SRAM_AOC_LHENB_SET	BIT(4)
+#define	SRAM_AOC_ISO_SET	BIT(6)
+#define SRAM_AOC_ISO_CLR	BIT(7)
+#define PLL_AOC_ISO_EN_SET	BIT(8)
+#define PLL_AOC_ISO_EN_CLR	BIT(9)
+#define BUCK_ELS_EN_SET		BIT(10)
+#define BUCK_ELS_EN_CLR		BIT(11)
+#define BUCK_AO_RST_B_SET	BIT(12)
+#define BUCK_AO_RST_B_CLR	BIT(13)
+#define BUCK_PROT_REQ_SET	BIT(14)
+#define BUCK_PROT_REQ_CLR	BIT(15)
+
+/* mt6373_vbuck2 */
+#define MT6373_SLAVE_ID				(0x5)
+#define MT6373_RG_BUCK_VBUCK2_SET		(0x241)
+#define MT6373_RG_BUCK_VBUCK2_CLR		(0x242)
+#define MT6373_RG_BUCK_VBUCK2_EN_SHIFT		(2)
+#define MT6373_RG_BUCK_VBUCK2_VOSEL_ADDR	(0x24e)
+
+/* PCU initial data */
+#define APU_PCUTOP_CTRL_SET		(0x0)
+#define APU_PCU_BUCK_STEP_SEL		(0x0030)
+#define APU_PCU_BUCK_ON_DAT0_L		(0x0080)
+#define APU_PCU_BUCK_ON_DAT0_H		(0x0084)
+#define APU_PCU_BUCK_ON_DAT1_L		(0x0088)
+#define APU_PCU_BUCK_ON_DAT1_H		(0x008C)
+#define APU_PCU_BUCK_OFF_DAT0_L		(0x00A0)
+#define APU_PCU_BUCK_OFF_DAT0_H		(0x00A4)
+#define APU_PCU_BUCK_ON_SLE0		(0x00C0)
+#define APU_PCU_BUCK_ON_SLE1		(0x00C4)
+#define VAPU_BUCK_ON_SETTLE_TIME	(0x00C8)
+#define APU_PCU_PMIC_TAR_BUF1		(0x0190)
+#define APU_PCU_PMIC_TAR_BUF2		(0x0194)
+#define APU_PCU_PMIC_CMD		(0x0184)
+#define APU_PCU_PMIC_IRQ		(0x0180)
+
+/* PCU control */
+#define PMIC_CMD_IRQ			BIT(0)
+#define PMIC_IRQ_EN			BIT(2)
+#define AUTO_BUCK_EN			BIT(3)
+#define PMIC_PMIFID_OFF			(3)
+#define PMIC_SLVID_OFF			(4)
+#define PCU_CMD_OP_W			(0x7)
+#define PMIC_OFF_ADDR_OFF		(16)
+#define PMIC_CMD_EN			(0x1)
+#define BUCK_STEP_SEL_VAL		(0x13)
+#define PCU_BUCK_OFF_CMD		(0x7)
+
+/* sram_core: mt6363_vbuck4 */
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR	(0x250)
+
+/* sub_pmic */
+#define BUCK_VAPU_PMIC_ID		MT6373_SLAVE_ID
+#define BUCK_VAPU_PMIC_REG_VOSEL_ADDR	MT6373_RG_BUCK_VBUCK2_VOSEL_ADDR
+#define BUCK_VAPU_PMIC_REG_EN_SET_ADDR	MT6373_RG_BUCK_VBUCK2_SET
+#define BUCK_VAPU_PMIC_REG_EN_CLR_ADDR	MT6373_RG_BUCK_VBUCK2_CLR
+#define BUCK_VAPU_PMIC_REG_EN_SHIFT	MT6373_RG_BUCK_VBUCK2_EN_SHIFT
+
+/* vlp offset define */
+#define APUSYS_AO_SRAM_CONFIG		(0x70)
+#define APUSYS_AO_SRAM_SET		(0x74)
+#define APUSYS_AO_SRAM_CLR		(0x78)
+
+#define APUSYS_AO_SRAM_EN		(0x1)
+
+#define ARE_ENTRIES(x, y)		((((y) - (x)) + 1) * 2)
+#define ARE_ENTRY(x)			(((x) * 2) + 36)
+#define ARE_RCX_AO_CONFIG		(0x0014)
+#define ARE_RCX_AO_CONFIG_HIGH_OFF	(16)
+
+#define APU_ACE_HW_FLAG_DIS		(APUSYS_CE_BASE + 0x05D4)
+#define APU_ACE_DIS_FLAG_VAL		(0xffff7ff8)
+
+#define OUT_CLK_FREQ_MIN		(1500)
+#define DDS_SHIFT			(14)
+#define BASIC_CLK_FREQ			(26)
+
+int apusys_power_init(void);
+
+#endif /* APUSYS_POWER_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_rv_mbox_mpu.h b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_mbox_mpu.h
new file mode 100644
index 0000000..7a5b212
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_mbox_mpu.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_RV_MBOX_MPU_H
+#define APUSYS_RV_MBOX_MPU_H
+
+#define MPU_EN		(0)
+#define MPU_DIS		(1)
+#define MBOX0_TX_DOMAIN	(0)
+#define MBOX0_TX_NS	(1)
+#define MBOX1_TX_DOMAIN	(11)
+#define MBOX1_TX_NS	(1)
+#define MBOX3_TX_DOMAIN	(3)
+#define MBOX3_TX_NS	(0)
+#define MBOX4_RX_DOMAIN	(0)
+#define MBOX4_RX_NS	(0)
+#define MBOX5_TX_DOMAIN	(8)
+#define MBOX5_TX_NS	(0)
+#define MBOX6_TX_DOMAIN	(4)
+#define MBOX6_TX_NS	(1)
+#define MBOX7_RX_DOMAIN	(0)
+#define MBOX7_RX_NS	(0)
+#define MBOXN_RX_DOMAIN	(5)
+#define MBOXN_RX_NS	(0)
+#define MBOXN_TX_DOMAIN	(0)
+#define MBOXN_TX_NS	(0)
+
+struct mbox_mpu_setting {
+	uint32_t no_mpu;
+	uint32_t rx_ns;
+	uint32_t rx_domain;
+	uint32_t tx_ns;
+	uint32_t tx_domain;
+};
+
+static const struct mbox_mpu_setting mbox_mpu_setting_tab[] = {
+	/* no_mpu,	rx_ns,		rx_domain,		tx_ns,		tx_domain */
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOX0_TX_NS,	MBOX0_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOX1_TX_NS,	MBOX1_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOXN_TX_NS,	MBOXN_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOX3_TX_NS,	MBOX3_TX_DOMAIN},
+	{MPU_DIS,	MBOX4_RX_NS,	MBOX4_RX_DOMAIN,	MBOXN_TX_NS,	MBOXN_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOX5_TX_NS,	MBOX5_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOX6_TX_NS,	MBOX6_TX_DOMAIN},
+	{MPU_DIS,	MBOX7_RX_NS,	MBOX7_RX_DOMAIN,	MBOXN_TX_NS,	MBOXN_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOXN_TX_NS,	MBOXN_TX_DOMAIN},
+	{MPU_EN,	MBOXN_RX_NS,	MBOXN_RX_DOMAIN,	MBOXN_TX_NS,	MBOXN_TX_DOMAIN},
+};
+
+#define APU_MBOX_NUM ARRAY_SIZE(mbox_mpu_setting_tab)
+
+#endif /* APUSYS_RV_MBOX_MPU_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.c b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.c
new file mode 100644
index 0000000..632af52
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "apusys_power.h"
+#include "apusys_rv.h"
+#include "apusys_rv_pwr_ctrl.h"
+
+#define RPC_POWER_OFF_TIMEOUT_CNT	(100000) /* 100ms */
+
+static int wait_for_state_ready(uint32_t reg, uint32_t mask, uint32_t expect,
+				uint32_t retry_times, uint32_t set_reg, uint32_t set_val)
+{
+	uint32_t count = 0;
+
+	while ((mmio_read_32(reg) & mask) != expect) {
+		if (count > retry_times) {
+			ERROR("%s: timed out, reg = %x, mask = %x, expect = %x\n",
+			       __func__, reg, mask, expect);
+			return -EBUSY;
+		}
+		count += 1;
+
+		if (set_reg)
+			mmio_write_32(set_reg, set_val);
+		udelay(1);
+	}
+
+	return 0;
+}
+
+int apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr, uint32_t sem_sta_addr,
+			     uint8_t usr_bit, enum apu_hw_sem_op ctl, uint32_t timeout,
+			     uint8_t bypass)
+{
+	int ret;
+	uint8_t ctl_bit = 0;
+
+	if (ctl == HW_SEM_GET)
+		ctl_bit = 0x1;
+	else if (ctl == HW_SEM_PUT)
+		ctl_bit = 0x2;
+	else
+		return -EINVAL;
+
+	/* return fail if semaphore is currently not held by this user */
+	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_sta_addr) & BIT(usr_bit)) == 0)
+	    && !bypass) {
+		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
+		       __func__, usr_bit, ctl, sem_sta_addr, mmio_read_32(sem_sta_addr));
+		return -EINVAL;
+	}
+
+	mmio_write_32(sem_ctrl_addr, ctl_bit);
+
+	if (ctl == HW_SEM_PUT)
+		return 0;
+
+	ret = wait_for_state_ready(sem_sta_addr, BIT(usr_bit), BIT(usr_bit), timeout,
+				   sem_ctrl_addr, ctl_bit);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int apusys_rv_pwr_ctrl(enum APU_PWR_OP op)
+{
+	int ret;
+	uint32_t global_ref_cnt;
+
+	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
+				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
+				       APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_TIMEOUT, 0);
+
+	if (ret) {
+		ERROR("%s(%d): sem acquire timeout\n", __func__, op);
+		return ret;
+	}
+
+	global_ref_cnt = mmio_read_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY);
+
+	if (global_ref_cnt > 2) {
+		ERROR("%s: global_ref_cnt(%d) > 2\n", __func__, global_ref_cnt);
+	} else if (op == APU_PWR_OFF) {
+		global_ref_cnt--;
+		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
+		if (global_ref_cnt == 0)
+			mmio_write_32(APU_MBOX_WKUP_CFG(11), 0);
+	} else if (op == APU_PWR_ON) {
+		global_ref_cnt++;
+		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
+		if (global_ref_cnt == 1)
+			mmio_write_32(APU_MBOX_WKUP_CFG(11), 1);
+	}
+
+	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
+				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
+				       APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_TIMEOUT, 0);
+
+	if (ret)
+		ERROR("%s(%d): sem release timeout\n", __func__, op);
+
+	return ret;
+}
+
+int rv_iommu_hw_sem_trylock(void)
+{
+	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
+					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
+					APU_HW_SEM_SYS_APMCU, HW_SEM_GET, 0, 0);
+}
+
+int rv_iommu_hw_sem_unlock(void)
+{
+	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
+					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
+					APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, 0, 0);
+}
+
+int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout,
+		    uint8_t bypass)
+{
+	int ret;
+	uint8_t ctl_bit = 0;
+
+	if (ctl == HW_SEM_GET)
+		ctl_bit = usr_bit;
+	else if (ctl == HW_SEM_PUT)
+		ctl_bit = usr_bit + HW_SEM_PUT_BIT_SHIFT;
+	else
+		return -EINVAL;
+
+	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_addr) & BIT(ctl_bit)) == 0) && !bypass) {
+		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
+		       __func__, usr_bit, ctl, sem_addr, mmio_read_32(sem_addr));
+		return -EINVAL;
+	}
+
+	mmio_write_32(sem_addr, BIT(ctl_bit));
+
+	if (ctl == HW_SEM_PUT)
+		goto end;
+
+	ret = wait_for_state_ready(sem_addr, BIT(ctl_bit), BIT(ctl_bit), timeout,
+				   sem_addr, BIT(ctl_bit));
+	if (ret)
+		return ret;
+
+end:
+	VERBOSE("%s: sem_addr = 0x%x, usr_bit: %d, ctl: %d, sem_addr = 0x%08x\n",
+		 __func__, sem_addr, usr_bit, ctl, mmio_read_32(sem_addr));
+
+	return 0;
+}
+
+int apusys_infra_dcm_setup(void)
+{
+	mmio_write_32(APU_REG_AO_GLUE_CONFG,
+		      mmio_read_32(APU_REG_AO_GLUE_CONFG) | BIT(24) | BIT(26));
+
+	return 0;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.h b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.h
new file mode 100644
index 0000000..b5a48e2
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_RV_PWR_CTL_H
+#define APUSYS_RV_PWR_CTL_H
+
+#include <platform_def.h>
+
+#include "apusys_rv.h"
+
+#define SUPPORT_APU_CLEAR_MBOX_DUMMY	(1)
+
+enum apu_hw_sem_sys_id {
+	APU_HW_SEM_SYS_APU   = 0UL,	/* mbox0 */
+	APU_HW_SEM_SYS_GZ    = 1UL,	/* mbox1 */
+	APU_HW_SEM_SYS_SCP   = 3UL,	/* mbox3 */
+	APU_HW_SEM_SYS_APMCU = 11UL,	/* mbox11 */
+};
+
+int apusys_rv_pwr_ctrl(enum APU_PWR_OP op);
+int rv_iommu_hw_sem_unlock(void);
+int rv_iommu_hw_sem_trylock(void);
+int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout,
+		    uint8_t bypass);
+
+#define HW_SEM_TIMEOUT	(300) /* 300 us */
+
+/* APU MBOX */
+#define MBOX_WKUP_CFG		(0x80)
+#define MBOX_WKUP_MASK		(0x84)
+#define MBOX_FUNC_CFG		(0xb0)
+#define MBOX_DOMAIN_CFG		(0xe0)
+
+#define MBOX_CTRL_LOCK		BIT(0)
+#define MBOX_NO_MPU_SHIFT	(16)
+#define MBOX_RC_SHIFT		(24)
+
+#define MBOX_RX_NS_SHIFT	(16)
+#define MBOX_RX_DOMAIN_SHIFT	(17)
+#define MBOX_TX_NS_SHIFT	(24)
+#define MBOX_TX_DOMAIN_SHIFT	(25)
+
+#define APU_REG_AO_GLUE_CONFG	(APU_AO_CTRL + 0x20)
+
+#define ENABLE_INFRA_WA
+
+enum apu_infra_bit_id {
+	APU_INFRA_SYS_APMCU = 1UL,
+	APU_INFRA_SYS_GZ    = 2UL,
+	APU_INFRA_SYS_SCP   = 3UL,
+};
+
+#define APU_MBOX(i)		(APU_MBOX0 + 0x10000 * i)
+
+#define APU_MBOX_FUNC_CFG(i)	(APU_MBOX(i) + MBOX_FUNC_CFG)
+#define APU_MBOX_DOMAIN_CFG(i)	(APU_MBOX(i) + MBOX_DOMAIN_CFG)
+#define APU_MBOX_WKUP_CFG(i)	(APU_MBOX(i) + MBOX_WKUP_CFG)
+
+enum apu_hw_sem_op {
+	HW_SEM_PUT = 0,
+	HW_SEM_GET = 1,
+};
+
+#define HW_SEM_PUT_BIT_SHIFT	(16)
+
+/* bypass mbox register Dump for secure master */
+#define APU_MBOX_DBG_EN		(0x190f2380)
+
+/* apu_mbox register definition for mbox addr change*/
+#define APU_MBOX_SEMA0_CTRL	(0x090)
+#define APU_MBOX_SEMA0_RST	(0x094)
+#define APU_MBOX_SEMA0_STA	(0x098)
+#define APU_MBOX_SEMA1_CTRL	(0x0A0)
+#define APU_MBOX_SEMA1_RST	(0x0A4)
+#define APU_MBOX_SEMA1_STA	(0x0A8)
+#define APU_MBOX_DUMMY		(0x040)
+#define APU_MBOX_OFFSET(i)	(0x10000 * i)
+
+/* apu infra workaround */
+#define APU_INFRA_DISABLE	(APU_INFRA_BASE + 0xC18)
+#define APU_INFRA_ENABLE	(APU_INFRA_BASE + 0xC14)
+#define APU_INFRA_STATUS	(APU_INFRA_BASE + 0xC10)
+#define APU_INFRA_STATUS_MASK	(0x1fffe)
+#define APU_INFRA_HW_SEM	(APUSYS_CE_BASE + 0xE00)
+#define APU_RPC_STATUS		(0x190f0044)
+
+#define APU_INFRA_BIT_OFF	(16)
+#define APU_RPC_STATUS_BIT	BIT(0)
+
+#endif /* APUSYS_RV_PWR_CTL_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.c b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.c
new file mode 100644
index 0000000..f6c8f58
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "apusys_security_ctrl_perm.h"
+#include "apusys_security_ctrl_perm_plat.h"
+
+#define SEC_CTRL_APU_SEC_CON_BASE	(0x190F5000)
+#define SEC_CTRL_RV_DOMAIN_OFS		(0x60)
+#define SEC_CTRL_RV_NS_OFS		(0x64)
+#define SEC_CTRL_RV_DOMAIN_SHF		(4)
+#define SEC_CTRL_RV_NS_SHF		(1)
+
+#define SEC_LEVEL_NORMAL_DOMAIN		(7)
+#define SEC_LEVEL_NORMAL_NS		(1)
+#define SEC_LEVEL_SAPU_DOMAIN		(5)
+#define SEC_LEVEL_SAPU_NS		(1)
+#define SEC_LEVEL_AOV_DOMAIN		(14)
+#define SEC_LEVEL_AOV_NS		(1)
+#define SEC_LEVEL_UP_SECURE_DOMAIN	(5)
+#define SEC_LEVEL_UP_SECURE_NS		(0)
+#define SEC_LEVEL_MVPU_SECURE_DOMAIN	(7)
+#define SEC_LEVEL_MVPU_SECURE_NS	(0)
+#define SEC_LEVEL_MDLA_SECURE_DOMAIN	(14)
+#define SEC_LEVEL_MDLA_SECURE_NS	(0)
+#define DOMAIN(SEC_LVL)	SEC_LEVEL_##SEC_LVL##_DOMAIN
+#define NS(SEC_LVL)	SEC_LEVEL_##SEC_LVL##_NS
+
+int sec_get_dns(enum apusys_dev_type dev_type, enum apusys_sec_level sec_level,
+		uint8_t *domain, uint8_t *ns)
+{
+	if ((dev_type < 0) || (dev_type >= APUSYS_DEVICE_NUM)) {
+		ERROR("invalid dev type %d\n", dev_type);
+		return -EINVAL;
+	}
+
+	if ((sec_level < 0) || (sec_level >= SEC_LEVEL_NUM)) {
+		ERROR("invalid sec_level %d\n", sec_level);
+		return -EINVAL;
+	}
+
+	switch (sec_level) {
+	case SEC_LEVEL_NORMAL:
+		*domain = DOMAIN(NORMAL);
+		*ns = NS(NORMAL);
+		break;
+	case SEC_LEVEL_SECURE:
+		switch (dev_type) {
+		case APUSYS_DEVICE_MVPU:
+			*domain = DOMAIN(MVPU_SECURE);
+			*ns = NS(MVPU_SECURE);
+			break;
+		case APUSYS_DEVICE_MDLA:
+			*domain = DOMAIN(MDLA_SECURE);
+			*ns = NS(MDLA_SECURE);
+			break;
+		case APUSYS_DEVICE_UP:
+			*domain = DOMAIN(UP_SECURE);
+			*ns = NS(UP_SECURE);
+			break;
+		default:
+			ERROR("invalid dev type %d\n", dev_type);
+			return -EINVAL;
+		};
+		break;
+	case SEC_LEVEL_SAPU:
+		*domain = DOMAIN(SAPU);
+		*ns = NS(SAPU);
+		break;
+	case SEC_LEVEL_AOV:
+		*domain = DOMAIN(AOV);
+		*ns = NS(AOV);
+		break;
+	default:
+		ERROR("invalid sec_level %d\n", sec_level);
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+int sec_set_rv_dns(void)
+{
+	uint8_t normal_domain;
+	uint8_t normal_ns;
+	uint8_t sec_domain;
+	uint8_t sec_ns;
+	int ret;
+
+	ret = sec_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_SECURE, &sec_domain, &sec_ns);
+	if (ret) {
+		ERROR("%s failed.\n", __func__);
+		return ret;
+	}
+
+	ret = sec_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_NORMAL, &normal_domain, &normal_ns);
+	if (ret) {
+		ERROR("%s failed.\n", __func__);
+		return ret;
+	}
+
+	mmio_write_32(SEC_CTRL_APU_SEC_CON_BASE + SEC_CTRL_RV_DOMAIN_OFS,
+		      (sec_domain << SEC_CTRL_RV_DOMAIN_SHF) | normal_domain);
+	mmio_write_32(SEC_CTRL_APU_SEC_CON_BASE + SEC_CTRL_RV_NS_OFS,
+		      (sec_ns << SEC_CTRL_RV_NS_SHF) | normal_ns);
+
+	return 0;
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.h b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.h
new file mode 100644
index 0000000..d57a536
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_perm_plat.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_SECURITY_CTRL_PERM_PLAT_H
+#define APUSYS_SECURITY_CTRL_PERM_PLAT_H
+
+enum apusys_dev_type {
+	APUSYS_DEVICE_MDLA,
+	APUSYS_DEVICE_EDPA,
+	APUSYS_DEVICE_MVPU,
+	APUSYS_DEVICE_UP,
+	APUSYS_DEVICE_NUM,
+};
+
+#endif /* APUSYS_SECURITY_CTRL_PERM_PLAT_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.c b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.c
new file mode 100644
index 0000000..fbd2aa0
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define ENABLE_SMPU_PROTECT	(0)
+
+#if ENABLE_SMPU_PROTECT
+#include "emi.h"
+#include "mt_emi.h"
+#endif
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <apusys_security_ctrl_plat.h>
+
+#define APUSYS_SEC_FW_EMI_REGION	(23)
+
+#define bits_clr(x, m, o)	(x & (~(m << o)))
+#define bits_set(x, v, m, o)	((bits_clr(x, m, o)) | ((v & m) << o))
+
+static void sec_sideband_init(void)
+{
+	uint32_t value = mmio_read_32(SEC_CTRL_SIDE_BAND);
+
+	value = bits_set(value, SEC_CTRL_NARE_DOMAIN, SEC_CTRL_DOMAIN_MASK,
+			 SEC_CTRL_NARE_DOMAIN_SHF);
+	value = bits_set(value, SEC_CTRL_NARE_NS, SEC_CTRL_NS_MASK, SEC_CTRL_NARE_NS_SHF);
+	value = bits_set(value, SEC_CTRL_SARE0_DOMAIN, SEC_CTRL_DOMAIN_MASK,
+			 SEC_CTRL_SARE0_DOMAIN_SHF);
+	value = bits_set(value, SEC_CTRL_SARE0_NS, SEC_CTRL_NS_MASK, SEC_CTRL_SARE0_NS_SHF);
+	value = bits_set(value, SEC_CTRL_SARE1_DOMAIN, SEC_CTRL_DOMAIN_MASK,
+			 SEC_CTRL_SARE1_DOMAIN_SHF);
+	value = bits_set(value, SEC_CTRL_SARE1_NS, SEC_CTRL_NS_MASK, SEC_CTRL_SARE1_NS_SHF);
+
+	mmio_write_32(SEC_CTRL_SIDE_BAND, value);
+}
+
+static void domain_remap_init(void)
+{
+	const uint32_t remap_domains[] = {
+		D0_REMAP_DOMAIN,  D1_REMAP_DOMAIN,  D2_REMAP_DOMAIN,  D3_REMAP_DOMAIN,
+		D4_REMAP_DOMAIN,  D5_REMAP_DOMAIN,  D6_REMAP_DOMAIN,  D7_REMAP_DOMAIN,
+		D8_REMAP_DOMAIN,  D9_REMAP_DOMAIN,  D10_REMAP_DOMAIN, D11_REMAP_DOMAIN,
+		D12_REMAP_DOMAIN, D13_REMAP_DOMAIN, D14_REMAP_DOMAIN, D15_REMAP_DOMAIN,
+	};
+	uint32_t lower_domain = 0;
+	uint32_t higher_domain = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(remap_domains); i++) {
+		if (i < SEC_CTRL_REG_DOMAIN_NUM)
+			lower_domain |= (remap_domains[i] << (i * REG_DOMAIN_BITS));
+		else
+			higher_domain |= (remap_domains[i] <<
+					  ((i - SEC_CTRL_REG_DOMAIN_NUM) * REG_DOMAIN_BITS));
+	}
+
+	mmio_write_32(SEC_CTRL_SOC2APU_SET1_0, lower_domain);
+	mmio_write_32(SEC_CTRL_SOC2APU_SET1_1, higher_domain);
+	mmio_setbits_32(APU_SEC_CON, SEC_CTRL_DOMAIN_REMAP_SEL);
+}
+
+void apusys_security_ctrl_init(void)
+{
+	domain_remap_init();
+	sec_sideband_init();
+}
+
+int apusys_plat_setup_sec_mem(void)
+{
+#if ENABLE_SMPU_PROTECT
+	return sip_emi_mpu_set_protection(APU_RESERVE_MEMORY >> EMI_MPU_ALIGN_BITS,
+		(APU_RESERVE_MEMORY + APU_RESERVE_SIZE) >> EMI_MPU_ALIGN_BITS,
+		APUSYS_SEC_FW_EMI_REGION);
+#else
+	INFO("%s: Bypass SMPU protection setup.\n", __func__);
+	return 0;
+#endif
+}
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.h b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.h
new file mode 100644
index 0000000..5e69777
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_security_ctrl_plat.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_SECURITY_CTRL_PLAT_H
+#define APUSYS_SECURITY_CTRL_PLAT_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+#define SEC_CTRL_SOC2APU_SET1_0		(APU_SEC_CON + 0xC)
+#define SEC_CTRL_SOC2APU_SET1_1		(APU_SEC_CON + 0x10)
+#define SEC_CTRL_SIDE_BAND		(APU_SEC_CON + 0x24)
+
+#define SEC_CTRL_REG_DOMAIN_NUM		(8)
+#define SEC_CTRL_DOMAIN_REMAP_SEL	BIT(6)
+#define SEC_CTRL_DOMAIN_MASK		(0xF)
+#define SEC_CTRL_NS_MASK		(0x1)
+
+#define SEC_CTRL_NARE_DOMAIN		(5)
+#define SEC_CTRL_NARE_NS		(0)
+#define SEC_CTRL_NARE_DOMAIN_SHF	(0)
+#define SEC_CTRL_NARE_NS_SHF		(4)
+
+#define SEC_CTRL_SARE0_DOMAIN		(5)
+#define SEC_CTRL_SARE0_NS		(0)
+#define SEC_CTRL_SARE0_DOMAIN_SHF	(5)
+#define SEC_CTRL_SARE0_NS_SHF		(9)
+
+#define SEC_CTRL_SARE1_DOMAIN		(5)
+#define SEC_CTRL_SARE1_NS		(0)
+#define SEC_CTRL_SARE1_DOMAIN_SHF	(10)
+#define SEC_CTRL_SARE1_NS_SHF		(14)
+
+#define REG_DOMAIN_BITS		(4)
+
+#define D0_REMAP_DOMAIN		(0)
+#define D1_REMAP_DOMAIN		(1)
+#define D2_REMAP_DOMAIN		(2)
+#define D3_REMAP_DOMAIN		(3)
+#define D4_REMAP_DOMAIN		(4)
+#define D5_REMAP_DOMAIN		(6)
+#define D6_REMAP_DOMAIN		(6)
+#define D7_REMAP_DOMAIN		(6)
+#define D8_REMAP_DOMAIN		(8)
+#define D9_REMAP_DOMAIN		(9)
+#define D10_REMAP_DOMAIN	(10)
+#define D11_REMAP_DOMAIN	(11)
+#define D12_REMAP_DOMAIN	(12)
+#define D13_REMAP_DOMAIN	(13)
+#define D14_REMAP_DOMAIN	(6)
+#define D15_REMAP_DOMAIN	(15)
+
+void apusys_security_ctrl_init(void);
+int apusys_plat_setup_sec_mem(void);
+
+#endif /* APUSYS_SECURITY_CTRL_PLAT_H */
diff --git a/plat/mediatek/drivers/apusys/mt8196/rules.mk b/plat/mediatek/drivers/apusys/mt8196/rules.mk
new file mode 100644
index 0000000..4ffaf73
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/mt8196/rules.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2024, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := apusys_${MTK_SOC}
+
+ifeq (${CONFIG_MTK_APUSYS_EMI_SUPPORT}, y)
+PLAT_INCLUDES += -I${MTK_PLAT}/drivers/emi/common
+PLAT_INCLUDES += -I${MTK_PLAT}/drivers/emi/${MTK_SOC}
+endif
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/apusys_ammu.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/apusys_devapc.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/apusys_power.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/apusys_rv_pwr_ctrl.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/apusys_security_ctrl_plat.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/apusys_security_ctrl_perm_plat.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/apusys/rules.mk b/plat/mediatek/drivers/apusys/rules.mk
index 498925c..24cc79c 100644
--- a/plat/mediatek/drivers/apusys/rules.mk
+++ b/plat/mediatek/drivers/apusys/rules.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, MediaTek Inc. All rights reserved.
+# Copyright (c) 2023-2024, MediaTek Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -12,10 +12,19 @@
 
 PLAT_INCLUDES += -I${LOCAL_DIR} -I${LOCAL_DIR}/${MTK_SOC} -I${LOCAL_DIR}/apusys_rv/2.0
 
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_CE_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_EMI_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_LOGTOP_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_RV_APUMMU_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_RV_COREDUMP_WA_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_APUSYS_SEC_CTRL))
+
 $(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
 
 SUB_RULES-y := ${LOCAL_DIR}/${MTK_SOC}
 SUB_RULES-y += ${LOCAL_DIR}/devapc
 SUB_RULES-y += ${LOCAL_DIR}/apusys_rv/2.0
+SUB_RULES-${CONFIG_MTK_APUSYS_SEC_CTRL} += $(LOCAL_DIR)/security_ctrl
 
 $(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/drivers/apusys/security_ctrl/apusys_security_ctrl_perm.h b/plat/mediatek/drivers/apusys/security_ctrl/apusys_security_ctrl_perm.h
new file mode 100644
index 0000000..17ccacf
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/security_ctrl/apusys_security_ctrl_perm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURITY_CTRL_PERM_H
+#define SECURITY_CTRL_PERM_H
+
+#include "apusys_security_ctrl_perm_plat.h"
+
+enum apusys_sec_level {
+	SEC_LEVEL_NORMAL,
+	SEC_LEVEL_SECURE,
+	SEC_LEVEL_SAPU,
+	SEC_LEVEL_AOV,
+	SEC_LEVEL_NUM,
+};
+
+int sec_set_rv_dns(void);
+int sec_get_dns(enum apusys_dev_type dev_type, enum apusys_sec_level sec_level,
+		uint8_t *domain, uint8_t *ns);
+
+#endif
diff --git a/plat/mediatek/drivers/apusys/security_ctrl/rules.mk b/plat/mediatek/drivers/apusys/security_ctrl/rules.mk
new file mode 100644
index 0000000..a7ed5c9
--- /dev/null
+++ b/plat/mediatek/drivers/apusys/security_ctrl/rules.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2024, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES += -I${MTK_PLAT}/drivers/apusys/security_ctrl
+PLAT_INCLUDES += -I${MTK_PLAT}/drivers/apusys/${MTK_SOC}
diff --git a/plat/mediatek/drivers/emi/common/emi.h b/plat/mediatek/drivers/emi/common/emi.h
new file mode 100644
index 0000000..eb2a0d3
--- /dev/null
+++ b/plat/mediatek/drivers/emi/common/emi.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_H
+#define EMI_H
+
+#include <stdint.h>
+
+#define EMI_MPU_ALIGN_BITS	12
+
+uint64_t sip_emi_mpu_set_protection(u_register_t start, u_register_t end, u_register_t region);
+
+#endif /* EMI_H */
diff --git a/plat/mediatek/drivers/emi/emi_stub.c b/plat/mediatek/drivers/emi/emi_stub.c
new file mode 100644
index 0000000..3682bf7
--- /dev/null
+++ b/plat/mediatek/drivers/emi/emi_stub.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2025, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <common/debug.h>
+
+#include "common/emi.h"
+#include <mtk_sip_svc.h>
+
+uint64_t sip_emi_mpu_set_protection(u_register_t start, u_register_t end,
+				    u_register_t region)
+{
+	return MTK_SIP_E_NOT_SUPPORTED;
+}
diff --git a/plat/mediatek/drivers/emi/rules.mk b/plat/mediatek/drivers/emi/rules.mk
new file mode 100644
index 0000000..9f462bb
--- /dev/null
+++ b/plat/mediatek/drivers/emi/rules.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2025, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := emi
+
+ifeq ($(MTKLIB_PATH),)
+LOCAL_SRCS-y := $(LOCAL_DIR)/emi_stub.c
+endif
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/include/drivers/apusys_rv_public.h b/plat/mediatek/include/drivers/apusys_rv_public.h
new file mode 100644
index 0000000..485453f
--- /dev/null
+++ b/plat/mediatek/include/drivers/apusys_rv_public.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUSYS_RV_PUBLIC_H
+#define APUSYS_RV_PUBLIC_H
+
+#ifdef CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT
+int apusys_rv_iommu_hw_sem_trylock(void);
+int apusys_rv_iommu_hw_sem_unlock(void);
+#else
+#define apusys_rv_iommu_hw_sem_trylock() 0
+#define apusys_rv_iommu_hw_sem_unlock() 0
+#endif /* CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT */
+
+#endif /* APUSYS_RV_PUBLIC_H */
diff --git a/plat/mediatek/include/mtk_sip_def.h b/plat/mediatek/include/mtk_sip_def.h
index ff12408..6f496d2 100644
--- a/plat/mediatek/include/mtk_sip_def.h
+++ b/plat/mediatek/include/mtk_sip_def.h
@@ -13,6 +13,7 @@
 	_func(MTK_SIP_KERNEL_DFD, 0x205) \
 	_func(MTK_SIP_KERNEL_MSDC, 0x273) \
 	_func(MTK_SIP_VCORE_CONTROL, 0x506) \
+	_func(MTK_SIP_EMIDBG_CONTROL, 0x50B) \
 	_func(MTK_SIP_IOMMU_CONTROL, 0x514) \
 	_func(MTK_SIP_AUDIO_CONTROL, 0x517) \
 	_func(MTK_SIP_APUSYS_CONTROL, 0x51E) \
@@ -21,9 +22,11 @@
 	_func(MTK_SIP_KERNEL_VCP_CONTROL, 0x52C)
 
 #define MTK_SIP_SMC_FROM_S_EL1_TABLE(_func) \
-	_func(MTK_SIP_TEE_MPU_PERM_SET, 0x031)
+	_func(MTK_SIP_TEE_MPU_PERM_SET, 0x031) \
+	_func(MTK_SIP_TEE_EMI_MPU_CONTROL, 0x048)
 
 #define MTK_SIP_SMC_FROM_BL33_TABLE(_func) \
-	_func(MTK_SIP_KERNEL_BOOT, 0x115)
+	_func(MTK_SIP_KERNEL_BOOT, 0x115) \
+	_func(MTK_SIP_BL_EMIMPU_CONTROL, 0x415)
 
 #endif /* MTK_SIP_DEF_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
index 8c012e7..9eb348e 100644
--- a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
@@ -18,8 +18,6 @@
 #include <plat_mtk_lpm.h>
 #include <plat_pm.h>
 
-DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
-
 static int plat_mt_lp_cpu_rc;
 
 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
index b483c36..1df75f7 100644
--- a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
@@ -18,8 +18,6 @@
 #include <plat_mtk_lpm.h>
 #include <plat_pm.h>
 
-DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
-
 static int plat_mt_lp_cpu_rc;
 
 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c
index 5a80d95..d32a7df 100644
--- a/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c
@@ -18,8 +18,6 @@
 #include <plat_mtk_lpm.h>
 #include <plat_pm.h>
 
-DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
-
 static int plat_mt_lp_cpu_rc;
 
 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
diff --git a/plat/mediatek/mt8196/include/platform_def.h b/plat/mediatek/mt8196/include/platform_def.h
index 630a3f0..6b6416a 100644
--- a/plat/mediatek/mt8196/include/platform_def.h
+++ b/plat/mediatek/mt8196/include/platform_def.h
@@ -31,6 +31,37 @@
 #define AUDIO_BASE		(IO_PHYS + 0x0a110000)
 
 /*******************************************************************************
+ * APUSYS related constants
+ ******************************************************************************/
+#define APUSYS_BASE			(IO_PHYS + 0x09000000)
+#define APU_MD32_SYSCTRL		(IO_PHYS + 0x09001000)
+#define APU_MD32_WDT			(IO_PHYS + 0x09002000)
+#define APU_LOGTOP			(IO_PHYS + 0x09024000)
+#define APUSYS_CTRL_DAPC_RCX_BASE	(IO_PHYS + 0x09030000)
+#define APU_REVISER			(IO_PHYS + 0x0903C000)
+#define APU_RCX_UPRV_TCU		(IO_PHYS + 0x09060000)
+#define APU_RCX_EXTM_TCU		(IO_PHYS + 0x09061000)
+#define APU_CMU_TOP			(IO_PHYS + 0x09067000)
+#define APUSYS_CE_BASE			(IO_PHYS + 0x090B0000)
+#define APU_ARE_REG_BASE		(IO_PHYS + 0x090B0000)
+#define APU_RCX_VCORE_CONFIG		(IO_PHYS + 0x090E0000)
+#define APU_AO_CTRL			(IO_PHYS + 0x090F2000)
+#define APU_SEC_CON			(IO_PHYS + 0x090F5000)
+#define APUSYS_CTRL_DAPC_AO_BASE	(IO_PHYS + 0x090FC000)
+
+#define APU_MBOX0			(0x4C200000)
+#define APU_MD32_TCM			(0x4D000000)
+
+#define APU_MD32_TCM_SZ			(0x50000)
+#define APU_MBOX0_SZ			(0x100000)
+#define APU_INFRA_BASE			(0x1002C000)
+#define APU_INFRA_SZ			(0x1000)
+
+#define APU_RESERVE_MEMORY		(0x95000000)
+#define APU_SEC_INFO_OFFSET		(0x100000)
+#define APU_RESERVE_SIZE		(0x1400000)
+
+/*******************************************************************************
  * SPM related constants
  ******************************************************************************/
 #define SPM_BASE		(IO_PHYS + 0x0C004000)
@@ -138,8 +169,21 @@
 /*******************************************************************************
  * EMI MPU related constants
  *******************************************************************************/
-#define EMI_MPU_BASE		(IO_PHYS + 0x00428000)
-#define SUB_EMI_MPU_BASE	(IO_PHYS + 0x00528000)
+#define EMI_MPU_BASE			(IO_PHYS + 0x00428000)
+#define SUB_EMI_MPU_BASE		(IO_PHYS + 0x00528000)
+#define EMI_SLB_BASE			(IO_PHYS + 0x0042e000)
+#define SUB_EMI_SLB_BASE		(IO_PHYS + 0x0052e000)
+#define CHN0_EMI_APB_BASE		(IO_PHYS + 0x00201000)
+#define CHN1_EMI_APB_BASE		(IO_PHYS + 0x00205000)
+#define CHN2_EMI_APB_BASE		(IO_PHYS + 0x00209000)
+#define CHN3_EMI_APB_BASE		(IO_PHYS + 0x0020D000)
+#define EMI_APB_BASE			(IO_PHYS + 0x00429000)
+#define INFRA_EMI_DEBUG_CFG_BASE	(IO_PHYS + 0x00425000)
+#define NEMI_SMPU_BASE			(IO_PHYS + 0x0042f000)
+#define SEMI_SMPU_BASE			(IO_PHYS + 0x0052f000)
+#define SUB_EMI_APB_BASE		(IO_PHYS + 0x00529000)
+#define SUB_INFRA_EMI_DEBUG_CFG_BASE	(IO_PHYS + 0x00525000)
+#define SUB_INFRACFG_AO_MEM_BASE	(IO_PHYS + 0x00504000)
 
 /*******************************************************************************
  * System counter frequency related constants
diff --git a/plat/mediatek/mt8196/plat_config.mk b/plat/mediatek/mt8196/plat_config.mk
index dc78701..0239a3f 100644
--- a/plat/mediatek/mt8196/plat_config.mk
+++ b/plat/mediatek/mt8196/plat_config.mk
@@ -26,6 +26,14 @@
 CTX_INCLUDE_AARCH32_REGS := 0
 
 CONFIG_ARCH_ARM_V9 := y
+CONFIG_MTK_APUSYS_CE_SUPPORT := y
+CONFIG_MTK_APUSYS_EMI_SUPPORT := n
+CONFIG_MTK_APUSYS_LOGTOP_SUPPORT := y
+CONFIG_MTK_APUSYS_RV_APUMMU_SUPPORT := y
+CONFIG_MTK_APUSYS_RV_COREDUMP_WA_SUPPORT := y
+CONFIG_MTK_APUSYS_RV_IOMMU_HW_SEM_SUPPORT := y
+CONFIG_MTK_APUSYS_SEC_CTRL := y
+CONFIG_MTK_APUSYS_SETUP_CE := y
 CONFIG_MTK_MCUSYS := y
 MCUSYS_VERSION := v1
 CONFIG_MTK_PM_SUPPORT := y
diff --git a/plat/mediatek/mt8196/plat_mmap.c b/plat/mediatek/mt8196/plat_mmap.c
index 3d7be87..d32f4ee 100644
--- a/plat/mediatek/mt8196/plat_mmap.c
+++ b/plat/mediatek/mt8196/plat_mmap.c
@@ -21,6 +21,8 @@
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(EDP_SEC_BASE, EDP_SEC_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(APU_MBOX0, APU_MBOX0_SZ,
+			MT_DEVICE | MT_RW | MT_SECURE),
 	{ 0 }
 };
 DECLARE_MTK_MMAP_REGIONS(plat_mmap);
diff --git a/plat/mediatek/mt8196/platform.mk b/plat/mediatek/mt8196/platform.mk
index 0d6ca24..8ae8e28 100644
--- a/plat/mediatek/mt8196/platform.mk
+++ b/plat/mediatek/mt8196/platform.mk
@@ -25,13 +25,20 @@
 MODULES-y += $(MTK_PLAT)/common
 MODULES-y += $(MTK_PLAT)/lib/mtk_init
 MODULES-y += $(MTK_PLAT)/lib/pm
+MODULES-y += $(MTK_PLAT)/drivers/apusys
 MODULES-y += $(MTK_PLAT)/drivers/dp
+MODULES-y += $(MTK_PLAT)/drivers/emi
 MODULES-y += $(MTK_PLAT)/drivers/mcusys
 MODULES-y += $(MTK_PLAT)/drivers/timer
 MODULES-y += $(MTK_PLAT)/drivers/vcp
 MODULES-y += $(MTK_PLAT)/helpers
 MODULES-y += $(MTK_PLAT)/topology
 
+ifneq ($(MTKLIB_PATH),)
+LDFLAGS += -L $(dir $(MTKLIB_PATH))
+LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(MTKLIB_PATH)))
+endif
+
 PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \
 			  drivers/ti/uart/aarch64/16550_console.S \
 			  lib/bl_aux_params/bl_aux_params.c
diff --git a/plat/nuvoton/npcm845x/platform.mk b/plat/nuvoton/npcm845x/platform.mk
index 1959aac..d73756c 100644
--- a/plat/nuvoton/npcm845x/platform.mk
+++ b/plat/nuvoton/npcm845x/platform.mk
@@ -318,9 +318,8 @@
 endif
 
 # Pointer Authentication sources
-ifeq (${ENABLE_PAUTH}, 1)
-PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c \
-		lib/extensions/pauth/pauth_helpers.S
+ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3))
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
 endif
 
 ifeq (${SPD},spmd)
diff --git a/plat/nxp/s32/s32g274ardb2/include/platform_def.h b/plat/nxp/s32/s32g274ardb2/include/platform_def.h
index 1a4c495..cb16658 100644
--- a/plat/nxp/s32/s32g274ardb2/include/platform_def.h
+++ b/plat/nxp/s32/s32g274ardb2/include/platform_def.h
@@ -48,7 +48,7 @@
 /* We'll be doing a 1:1 mapping anyway */
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 36)
 
-#define MAX_MMAP_REGIONS		U(8)
+#define MAX_MMAP_REGIONS		U(18)
 #define MAX_XLAT_TABLES			U(32)
 
 /* Console settings */
diff --git a/plat/nxp/s32/s32g274ardb2/include/s32cc-bl-common.h b/plat/nxp/s32/s32g274ardb2/include/s32cc-bl-common.h
new file mode 100644
index 0000000..0f0c804
--- /dev/null
+++ b/plat/nxp/s32/s32g274ardb2/include/s32cc-bl-common.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef S32CC_BL_COMMON_H
+#define S32CC_BL_COMMON_H
+
+int s32cc_bl_mmu_setup(void);
+
+#endif /* S32CC_BL_COMMON_H */
diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
index 4645f01..0929f9d 100644
--- a/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
+++ b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
@@ -4,15 +4,21 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <errno.h>
+
 #include <common/debug.h>
 #include <common/desc_image_load.h>
 #include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 #include <plat_console.h>
 #include <s32cc-clk-drv.h>
+
 #include <plat_io_storage.h>
+#include <s32cc-bl-common.h>
 #include <s32cc-ncore.h>
 
+#define SIUL20_BASE		UL(0x4009C000)
 #define SIUL2_PC09_MSCR		UL(0x4009C2E4)
 #define SIUL2_PC10_MSCR		UL(0x4009C2E8)
 #define SIUL2_PC10_LIN0_IMCR	UL(0x4009CA40)
@@ -38,6 +44,20 @@
 
 void bl2_platform_setup(void)
 {
+	int ret;
+
+	ret = mmap_add_dynamic_region(S32G_FIP_BASE, S32G_FIP_BASE,
+				      S32G_FIP_SIZE,
+				      MT_MEMORY | MT_RW | MT_SECURE);
+	if (ret != 0) {
+		panic();
+	}
+}
+
+static int s32g_mmap_siul2(void)
+{
+	return mmap_add_dynamic_region(SIUL20_BASE, SIUL20_BASE, PAGE_SIZE,
+				       MT_DEVICE | MT_RW | MT_SECURE);
 }
 
 static void linflex_config_pinctrl(void)
@@ -55,14 +75,6 @@
 {
 	int ret;
 
-	ret = s32cc_init_early_clks();
-	if (ret != 0) {
-		panic();
-	}
-
-	linflex_config_pinctrl();
-	console_s32g2_register();
-
 	/* Restore (clear) the CAIUTC[IsolEn] bit for the primary cluster, which
 	 * we have manually set during early BL2 boot.
 	 */
@@ -71,6 +83,29 @@
 	ncore_init();
 	ncore_caiu_online(A53_CLUSTER0_CAIU);
 
+	ret = s32cc_init_core_clocks();
+	if (ret != 0) {
+		panic();
+	}
+
+	ret = s32cc_bl_mmu_setup();
+	if (ret != 0) {
+		panic();
+	}
+
+	ret = s32cc_init_early_clks();
+	if (ret != 0) {
+		panic();
+	}
+
+	ret = s32g_mmap_siul2();
+	if (ret != 0) {
+		panic();
+	}
+
+	linflex_config_pinctrl();
+	console_s32g2_register();
+
 	plat_s32g2_io_setup();
 }
 
@@ -78,3 +113,26 @@
 {
 }
 
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+	const struct bl_mem_params_node *desc = get_bl_mem_params_node(image_id);
+	const struct image_info *img_info;
+	size_t size;
+
+	if (desc == NULL) {
+		return -EINVAL;
+	}
+
+	img_info = &desc->image_info;
+
+	if ((img_info == NULL) || (img_info->image_max_size == 0U)) {
+		return -EINVAL;
+	}
+
+	size = page_align(img_info->image_max_size, UP);
+
+	return mmap_add_dynamic_region(img_info->image_base,
+				       img_info->image_base,
+				       size,
+				       MT_MEMORY | MT_RW | MT_SECURE);
+}
diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c b/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c
index 03bf35c..22c66b0 100644
--- a/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c
+++ b/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c
@@ -4,10 +4,14 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <common/debug.h>
 #include <drivers/arm/gicv3.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 #include <plat_console.h>
 
+#include <s32cc-bl-common.h>
+
 static entry_point_info_t bl33_image_ep_info;
 
 static unsigned int s32g2_mpidr_to_core_pos(unsigned long mpidr);
@@ -25,8 +29,6 @@
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 				u_register_t arg2, u_register_t arg3)
 {
-	console_s32g2_register();
-
 	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
 	bl33_image_ep_info.pc = BL33_BASE;
 	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
@@ -35,6 +37,14 @@
 
 void bl31_plat_arch_setup(void)
 {
+	int ret;
+
+	ret = s32cc_bl_mmu_setup();
+	if (ret != 0) {
+		panic();
+	}
+
+	console_s32g2_register();
 }
 
 struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type)
@@ -42,6 +52,31 @@
 	return &bl33_image_ep_info;
 }
 
+static int mmap_gic(const gicv3_driver_data_t *gic_data)
+{
+	size_t gicr_size;
+	int ret;
+
+	ret = mmap_add_dynamic_region(gic_data->gicd_base,
+				      gic_data->gicd_base,
+				      PAGE_SIZE_64KB,
+				      MT_DEVICE | MT_RW | MT_SECURE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	gicr_size = gicv3_redist_size(0x0U);
+	ret = mmap_add_dynamic_region(gic_data->gicr_base,
+				      gic_data->gicr_base,
+				      gicr_size * gic_data->rdistif_num,
+				      MT_DEVICE | MT_RW | MT_SECURE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
 void bl31_platform_setup(void)
 {
 	static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
@@ -52,8 +87,13 @@
 		.rdistif_base_addrs = rdistif_base_addrs,
 		.mpidr_to_core_pos = s32g2_mpidr_to_core_pos,
 	};
-
 	unsigned int pos = plat_my_core_pos();
+	int ret;
+
+	ret = mmap_gic(&plat_gic_data);
+	if (ret != 0) {
+		panic();
+	}
 
 	gicv3_driver_init(&plat_gic_data);
 	gicv3_distif_init();
diff --git a/plat/nxp/s32/s32g274ardb2/plat_console.c b/plat/nxp/s32/s32g274ardb2/plat_console.c
index 542fa7b..e65e439 100644
--- a/plat/nxp/s32/s32g274ardb2/plat_console.c
+++ b/plat/nxp/s32/s32g274ardb2/plat_console.c
@@ -5,6 +5,7 @@
  */
 
 #include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
 #include <linflex.h>
 #include <plat_console.h>
 #include <platform_def.h>
@@ -17,6 +18,12 @@
 	};
 	int ret;
 
+	ret = mmap_add_dynamic_region(UART_BASE, UART_BASE, PAGE_SIZE,
+				      MT_DEVICE | MT_RW | MT_SECURE);
+	if (ret != 0) {
+		panic();
+	}
+
 	ret = console_linflex_register(UART_BASE, UART_CLOCK_HZ,
 				       UART_BAUDRATE, &s32g2_console);
 	if (ret == 0) {
diff --git a/plat/nxp/s32/s32g274ardb2/platform.mk b/plat/nxp/s32/s32g274ardb2/platform.mk
index 7d6e960..4ec7cd0 100644
--- a/plat/nxp/s32/s32g274ardb2/platform.mk
+++ b/plat/nxp/s32/s32g274ardb2/platform.mk
@@ -38,6 +38,9 @@
 ERRATA_SPECULATIVE_AT := 1
 ERRATA_S32_051700 := 1
 
+PLAT_XLAT_TABLES_DYNAMIC := 1
+$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
+
 # Selecting Drivers for SoC
 $(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
 $(eval $(call SET_NXP_MAKE_FLAG,CLK_NEEDED,BL_COMM))
@@ -47,6 +50,8 @@
 BL_COMMON_SOURCES += \
 	${PLAT_S32G274ARDB2}/plat_console.c \
 	${PLAT_S32G274ARDB2}/plat_helpers.S \
+	${PLAT_S32G274ARDB2}/s32cc_bl_common.c \
+	${XLAT_TABLES_LIB_SRCS} \
 
 BL2_SOURCES += \
 	${BL_COMMON_SOURCES} \
diff --git a/plat/nxp/s32/s32g274ardb2/s32cc_bl_common.c b/plat/nxp/s32/s32g274ardb2/s32cc_bl_common.c
new file mode 100644
index 0000000..4664438
--- /dev/null
+++ b/plat/nxp/s32/s32g274ardb2/s32cc_bl_common.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <s32cc-bl-common.h>
+
+int s32cc_bl_mmu_setup(void)
+{
+	const unsigned long code_start = BL_CODE_BASE;
+	const unsigned long rw_start = BL_CODE_END;
+	unsigned long code_size;
+	unsigned long rw_size;
+
+	if (code_start > BL_CODE_END) {
+		return -EINVAL;
+	}
+
+	if (rw_start > BL_END) {
+		return -EINVAL;
+	}
+
+	code_size = BL_CODE_END - code_start;
+	rw_size = BL_END - rw_start;
+
+	mmap_add_region(code_start, code_start, code_size,
+			MT_RO | MT_MEMORY | MT_SECURE);
+	mmap_add_region(rw_start, rw_start, rw_size,
+			MT_RW | MT_MEMORY | MT_SECURE);
+
+	init_xlat_tables();
+	enable_mmu_el3(0);
+
+	return 0;
+}
diff --git a/plat/nxp/soc-lx2160a/ddr_fip.mk b/plat/nxp/soc-lx2160a/ddr_fip.mk
index c303ced..c1f14dc 100644
--- a/plat/nxp/soc-lx2160a/ddr_fip.mk
+++ b/plat/nxp/soc-lx2160a/ddr_fip.mk
@@ -1,5 +1,6 @@
 #
 # Copyright 2020 NXP
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -67,7 +68,7 @@
 
 # Variables for use with Certificate Generation Tool
 CRTTOOLPATH	?=	tools/cert_create
-CRTTOOL		?=	${CRTTOOLPATH}/cert_create${BIN_EXT}
+CRTTOOL		?=	${CRTTOOLPATH}/cert_create$(.exe)
 
 ifneq (${GENERATE_COT},0)
 ddr_certificates: ${DDR_CRT_DEPS} ${CRTTOOL}
@@ -82,7 +83,7 @@
 
 # Variables for use with Firmware Image Package
 FIPTOOLPATH	?=	tools/fiptool
-FIPTOOL		?=	${FIPTOOLPATH}/fiptool${BIN_EXT}
+FIPTOOL		?=	${FIPTOOLPATH}/fiptool$(.exe)
 
 ${BUILD_PLAT}/${DDR_FIP_NAME}: ${DDR_FIP_DEPS} ${FIPTOOL}
 	$(eval ${CHECK_DDR_FIP_CMD})
diff --git a/plat/qemu/common/common.mk b/plat/qemu/common/common.mk
index 51497bd..5e3a61a 100644
--- a/plat/qemu/common/common.mk
+++ b/plat/qemu/common/common.mk
@@ -149,9 +149,8 @@
 endif
 
 # Pointer Authentication sources
-ifeq (${ENABLE_PAUTH}, 1)
+ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3))
 PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
-CTX_INCLUDE_PAUTH_REGS	:=	1
 endif
 
 endif
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index e502e7b..81ce102 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -68,6 +68,9 @@
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 				u_register_t arg2, u_register_t arg3)
 {
+	bool is64 = false;
+	uint64_t hval;
+
 	/* Initialize the console to provide early debug support */
 	qemu_console_init();
 
@@ -92,6 +95,11 @@
 	 * They are stored in Secure RAM, in BL2's address space.
 	 */
 	while (bl_params) {
+#ifdef __aarch64__
+		if (bl_params->image_id == BL31_IMAGE_ID &&
+		    GET_RW(bl_params->ep_info->spsr) == MODE_RW_64)
+			is64 = true;
+#endif
 		if (bl_params->image_id == BL32_IMAGE_ID)
 			bl32_image_ep_info = *bl_params->ep_info;
 
@@ -113,11 +121,19 @@
 		panic();
 #endif
 
-	if (TRANSFER_LIST && arg1 == (TRANSFER_LIST_SIGNATURE |
-				      REGISTER_CONVENTION_VERSION_MASK) &&
-	    transfer_list_check_header((void *)arg3) != TL_OPS_NON) {
-		bl31_tl = (void *)arg3; /* saved TL address from BL2 */
-	}
+	if (!TRANSFER_LIST ||
+	    !transfer_list_check_header((void *)arg3))
+		return;
+
+	if (is64)
+		hval = TRANSFER_LIST_HANDOFF_X1_VALUE(REGISTER_CONVENTION_VERSION);
+	else
+		hval = TRANSFER_LIST_HANDOFF_R1_VALUE(REGISTER_CONVENTION_VERSION);
+
+	if (arg1 != hval)
+		return;
+
+	bl31_tl = (void *)arg3; /* saved TL address from BL2 */
 }
 
 #if ENABLE_RME
@@ -309,10 +325,12 @@
 #if TRANSFER_LIST
 	if (bl31_tl) {
 		/*
-		 * update the TL from S to NS memory before jump to BL33
+		 * Relocate the TL from S to NS memory before EL3 exit
 		 * to reflect all changes in TL done by BL32
 		 */
-		memcpy((void *)FW_NS_HANDOFF_BASE, bl31_tl, bl31_tl->max_size);
+		if (!transfer_list_relocate(bl31_tl, (void *)FW_NS_HANDOFF_BASE,
+					    bl31_tl->max_size))
+			ERROR("Relocate TL to NS memory failed\n");
 	}
 #endif
 
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index 0bfb126..5dc39a1 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -258,6 +258,23 @@
 }
 #endif /* PLAT_qemu */
 
+/*
+ * Calculate checksum of 64-bit words @buffer, of @size bytes
+ */
+static uint64_t checksum_calc(uint64_t *buffer, size_t size)
+{
+	uint64_t sum = 0UL;
+
+	assert(((uintptr_t)buffer & (sizeof(uint64_t) - 1UL)) == 0UL);
+	assert((size & (sizeof(uint64_t) - 1UL)) == 0UL);
+
+	for (unsigned long i = 0UL; i < (size / sizeof(uint64_t)); i++) {
+		sum += buffer[i];
+	}
+
+	return sum;
+}
+
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
 {
 	int i, last;
@@ -352,10 +369,12 @@
 	last = num_banks - 1;
 	for (i = 0; i < num_banks; i++) {
 		plat_get_memory_node(i, &bank_ptr[last]);
-		checksum += bank_ptr[last].base + bank_ptr[last].size;
 		last--;
 	}
 
+	checksum += checksum_calc((uint64_t *)bank_ptr,
+				  num_banks * sizeof(*bank_ptr));
+
 	/* Checksum must be 0 */
 	manifest->plat_dram.checksum = ~checksum + 1UL;
 
@@ -373,8 +392,8 @@
 	strlcpy(console_ptr[0].name, "pl011", sizeof(console_ptr[0].name));
 
 	/* Update checksum */
-	checksum += console_ptr[0].base + console_ptr[0].map_pages +
-		console_ptr[0].clk_in_hz + console_ptr[0].baud_rate;
+	checksum += checksum_calc((uint64_t *)console_ptr,
+				  num_consoles * sizeof(*console_ptr));
 
 	/* Checksum must be 0 */
 	manifest->plat_console.checksum = ~checksum + 1UL;
diff --git a/plat/qemu/qemu/qemu_measured_boot.c b/plat/qemu/qemu/qemu_measured_boot.c
index 76a4da1..54a4156 100644
--- a/plat/qemu/qemu/qemu_measured_boot.c
+++ b/plat/qemu/qemu/qemu_measured_boot.c
@@ -65,6 +65,14 @@
 
 	event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_base);
 
+	dump_event_log((uint8_t *)event_log_base, event_log_cur_size);
+
+#if TRANSFER_LIST
+	if (!plat_handoff_mboot((void *)event_log_base, event_log_cur_size,
+				(void *)(uintptr_t)FW_HANDOFF_BASE))
+		return;
+#endif
+
 	rc = qemu_set_nt_fw_info(
 #ifdef SPD_opteed
 			    (uintptr_t)event_log_base,
@@ -101,7 +109,6 @@
 	}
 #endif /* defined(SPD_tspd) || defined(SPD_spmd) */
 
-	dump_event_log((uint8_t *)event_log_base, event_log_cur_size);
 }
 
 int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk
index e4ae87b..7a5a03c 100644
--- a/plat/socionext/synquacer/platform.mk
+++ b/plat/socionext/synquacer/platform.mk
@@ -25,6 +25,14 @@
 # Libraries
 include lib/xlat_tables_v2/xlat_tables.mk
 
+ifeq (${TRANSFER_LIST}, 1)
+include lib/transfer_list/transfer_list.mk
+endif
+
+ifeq (${HOB_LIST}, 1)
+include lib/hob/hob.mk
+endif
+
 PLAT_PATH		:=	plat/socionext/synquacer
 PLAT_INCLUDES		:=	-I$(PLAT_PATH)/include		\
 				-I$(PLAT_PATH)/drivers/scpi	\
diff --git a/plat/st/common/common.mk b/plat/st/common/common.mk
index 7395a36..dc753a0 100644
--- a/plat/st/common/common.mk
+++ b/plat/st/common/common.mk
@@ -1,5 +1,6 @@
 #
 # Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -76,7 +77,7 @@
 
 # Variables for use with stm32image
 STM32IMAGEPATH			?=	tools/stm32image
-STM32IMAGE			?=	${STM32IMAGEPATH}/stm32image${BIN_EXT}
+STM32IMAGE			?=	${STM32IMAGEPATH}/stm32image$(.exe)
 STM32IMAGE_SRC			:=	${STM32IMAGEPATH}/stm32image.c
 STM32_DEPS			+=	${STM32IMAGE}
 
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index f864700..237761a 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -112,7 +112,8 @@
 	VERBOSE("CPU power down request received\n");
 
 	/* Send powerdown request to online secondary core(s) */
-	ret = psci_stop_other_cores(PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt);
+	ret = psci_stop_other_cores(plat_my_core_pos(), PWRDWN_WAIT_TIMEOUT,
+				    raise_pwr_down_interrupt);
 	if (ret != (uint32_t)PSCI_E_SUCCESS) {
 		ERROR("Failed to powerdown secondary core(s)\n");
 	}
diff --git a/plat/xilinx/versal_net/bl31_versal_net_setup.c b/plat/xilinx/versal_net/bl31_versal_net_setup.c
index 5dd7b7f..d131a92 100644
--- a/plat/xilinx/versal_net/bl31_versal_net_setup.c
+++ b/plat/xilinx/versal_net/bl31_versal_net_setup.c
@@ -117,6 +117,9 @@
 
 	set_cnt_freq();
 
+	/* Initialize the platform config for future decision making */
+	versal_net_config_setup();
+
 	setup_console();
 
 	NOTICE("TF-A running on %s %d.%d\n", board_name_decode(),
@@ -124,8 +127,6 @@
 
 	versal_net_setup_qos();
 
-	/* Initialize the platform config for future decision making */
-	versal_net_config_setup();
 
 	/*
 	 * Do initial security configuration to allow DRAM/device access. On
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
index 669237b..412238d 100644
--- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -9,7 +9,6 @@
 #include <string.h>
 
 #include <common/debug.h>
-#include <drivers/generic_delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/smccc.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
@@ -395,20 +394,10 @@
 
 void zynqmp_config_setup(void)
 {
-	uint64_t counter_freq;
-
 	/* Configure IPI data for ZynqMP */
 	zynqmp_ipi_config_table_init();
 
 	zynqmp_print_platform_name();
-
-	/* Configure counter frequency */
-	counter_freq = read_cntfrq_el0();
-	if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
-		write_cntfrq_el0(plat_get_syscnt_freq2());
-	}
-
-	generic_delay_timer_init();
 }
 
 uint32_t plat_get_syscnt_freq2(void)
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index 77fbb58..b29e1c6 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -13,6 +13,7 @@
 #include <common/debug.h>
 #include <common/fdt_fixup.h>
 #include <common/fdt_wrappers.h>
+#include <drivers/generic_delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <libfdt.h>
@@ -77,6 +78,15 @@
 	(void)arg2;
 	(void)arg3;
 	uint64_t tfa_handoff_addr;
+	uint64_t counter_freq;
+
+	/* Configure counter frequency */
+	counter_freq = read_cntfrq_el0();
+	if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
+		write_cntfrq_el0(plat_get_syscnt_freq2());
+	}
+
+	generic_delay_timer_init();
 
 	setup_console();
 
diff --git a/poetry.lock b/poetry.lock
index 91203d2..4127bcd 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
 
 [[package]]
 name = "alabaster"
@@ -399,13 +399,13 @@
 
 [[package]]
 name = "jinja2"
-version = "3.1.4"
+version = "3.1.5"
 description = "A very fast and expressive template engine."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
-    {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+    {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
+    {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
 ]
 
 [package.dependencies]
@@ -1247,13 +1247,13 @@
 
 [[package]]
 name = "virtualenv"
-version = "20.26.4"
+version = "20.26.6"
 description = "Virtual Python Environment builder"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "virtualenv-20.26.4-py3-none-any.whl", hash = "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55"},
-    {file = "virtualenv-20.26.4.tar.gz", hash = "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c"},
+    {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"},
+    {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"},
 ]
 
 [package.dependencies]
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
index 5456164..6acd1b6 100644
--- a/services/arm_arch_svc/arm_arch_svc_setup.c
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -14,6 +14,9 @@
 #include <services/arm_arch_svc.h>
 #include <smccc_helpers.h>
 #include <plat/common/platform.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/context_mgmt.h>
 
 static int32_t smccc_version(void)
 {
@@ -90,6 +93,12 @@
 		}
 		return 0; /* ERRATA_APPLIES || ERRATA_MISSING */
 #endif
+
+#if ARCH_FEATURE_AVAILABILITY
+	case SMCCC_ARCH_FEATURE_AVAILABILITY:
+		return SMC_ARCH_CALL_SUCCESS;
+#endif /* ARCH_FEATURE_AVAILABILITY */
+
 #endif /* __aarch64__ */
 
 	/* Fallthrough */
@@ -111,6 +120,91 @@
 	}
 	return SMC_ARCH_CALL_INVAL_PARAM;
 }
+
+/*
+ * Reads a system register, sanitises its value, and returns a bitmask
+ * representing which feature in that sysreg has been enabled by firmware. The
+ * bitmask is a 1:1 mapping to the register's fields.
+ */
+#if ARCH_FEATURE_AVAILABILITY
+static uintptr_t smccc_arch_feature_availability(u_register_t reg,
+						 void *handle,
+						 u_register_t flags)
+{
+	cpu_context_t *caller_context;
+	per_world_context_t *caller_per_world_context;
+	el3_state_t *state;
+	u_register_t bitmask, check;
+
+	/* check the caller security state */
+	if (is_caller_secure(flags)) {
+		caller_context = cm_get_context(SECURE);
+		caller_per_world_context = &per_world_context[CPU_CONTEXT_SECURE];
+	} else if (is_caller_non_secure(flags)) {
+		caller_context = cm_get_context(NON_SECURE);
+		caller_per_world_context = &per_world_context[CPU_CONTEXT_NS];
+	} else {
+#if ENABLE_RME
+		caller_context = cm_get_context(REALM);
+		caller_per_world_context = &per_world_context[CPU_CONTEXT_REALM];
+#else /* !ENABLE_RME */
+		assert(0); /* shouldn't be possible */
+#endif /* ENABLE_RME */
+	}
+
+	state = get_el3state_ctx(caller_context);
+
+	switch (reg) {
+	case SCR_EL3_OPCODE:
+		bitmask  = read_ctx_reg(state, CTX_SCR_EL3);
+		bitmask &= ~SCR_EL3_IGNORED;
+		check    = bitmask & ~SCR_EL3_FEATS;
+		bitmask &= SCR_EL3_FEATS;
+		bitmask ^= SCR_EL3_FLIPPED;
+		/* will only report 0 if neither is implemented */
+		if (is_feat_rng_trap_supported() || is_feat_rng_present())
+			bitmask |= SCR_TRNDR_BIT;
+		break;
+	case CPTR_EL3_OPCODE:
+		bitmask  = caller_per_world_context->ctx_cptr_el3;
+		check    = bitmask & ~CPTR_EL3_FEATS;
+		bitmask &= CPTR_EL3_FEATS;
+		bitmask ^= CPTR_EL3_FLIPPED;
+		break;
+	case MDCR_EL3_OPCODE:
+		bitmask  = read_ctx_reg(state, CTX_MDCR_EL3);
+		bitmask &= ~MDCR_EL3_IGNORED;
+		check    = bitmask & ~MDCR_EL3_FEATS;
+		bitmask &= MDCR_EL3_FEATS;
+		bitmask ^= MDCR_EL3_FLIPPED;
+		break;
+#if ENABLE_FEAT_MPAM
+	case MPAM3_EL3_OPCODE:
+		bitmask  = caller_per_world_context->ctx_mpam3_el3;
+		bitmask &= ~MPAM3_EL3_IGNORED;
+		check    = bitmask & ~MPAM3_EL3_FEATS;
+		bitmask &= MPAM3_EL3_FEATS;
+		bitmask ^= MPAM3_EL3_FLIPPED;
+		break;
+#endif /* ENABLE_FEAT_MPAM */
+	default:
+		SMC_RET2(handle, SMC_INVALID_PARAM, ULL(0));
+	}
+
+	/*
+	 * failing this means that the requested register has a bit set that
+	 * hasn't been declared as a known feature bit or an ignore bit. This is
+	 * likely to happen when support for a new feature is added but the
+	 * bitmask macros are not updated.
+	 */
+	if (ENABLE_ASSERTIONS && check != 0) {
+		ERROR("Unexpected bits 0x%lx were set in register %lx!\n", check, reg);
+		assert(0);
+	}
+
+	SMC_RET2(handle, SMC_ARCH_CALL_SUCCESS, bitmask);
+}
+#endif /* ARCH_FEATURE_AVAILABILITY */
 
 /*
  * Top-level Arm Architectural Service SMC handler.
@@ -161,6 +255,11 @@
 		SMC_RET0(handle);
 #endif
 #endif /* __aarch64__ */
+#if ARCH_FEATURE_AVAILABILITY
+	/* return is 64 bit so only reply on SMC64 requests */
+	case SMCCC_ARCH_FEATURE_AVAILABILITY | (SMC_64 << FUNCID_CC_SHIFT):
+		return smccc_arch_feature_availability(x1, handle, flags);
+#endif /* ARCH_FEATURE_AVAILABILITY */
 	default:
 		WARN("Unimplemented Arm Architecture Service Call: 0x%x \n",
 			smc_fid);
diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c
index 9e83848..8910ec6 100644
--- a/services/spd/opteed/opteed_main.c
+++ b/services/spd/opteed/opteed_main.c
@@ -190,24 +190,28 @@
 	if (!optee_ep_info->pc)
 		return 1;
 
-	if (TRANSFER_LIST &&
-		optee_ep_info->args.arg1 == (TRANSFER_LIST_SIGNATURE |
-					REGISTER_CONVENTION_VERSION_MASK)) {
-		tl = (void *)optee_ep_info->args.arg3;
-		if (transfer_list_check_header(tl) == TL_OPS_NON) {
-			return 1;
-		}
-
-		opteed_rw = GET_RW(optee_ep_info->spsr);
+	tl = (void *)optee_ep_info->args.arg3;
+	if (TRANSFER_LIST && transfer_list_check_header(tl)) {
 		te = transfer_list_find(tl, TL_TAG_FDT);
 		dt = transfer_list_entry_data(te);
 
+		opteed_rw = GET_RW(optee_ep_info->spsr);
 		if (opteed_rw == OPTEE_AARCH64) {
+			if (optee_ep_info->args.arg1 !=
+			    TRANSFER_LIST_HANDOFF_X1_VALUE(
+				REGISTER_CONVENTION_VERSION))
+				return 1;
+
 			arg0 = (uint64_t)dt;
 			arg2 = 0;
 		} else {
-			arg2 = (uint64_t)dt;
+			if (optee_ep_info->args.arg1 !=
+			    TRANSFER_LIST_HANDOFF_R1_VALUE(
+				REGISTER_CONVENTION_VERSION))
+				return 1;
+
 			arg0 = 0;
+			arg2 = (uint64_t)dt;
 		}
 
 		arg1 = optee_ep_info->args.arg1;
diff --git a/services/std_svc/drtm/drtm_main.c b/services/std_svc/drtm/drtm_main.c
index 8d27e96..f58f615 100644
--- a/services/std_svc/drtm/drtm_main.c
+++ b/services/std_svc/drtm/drtm_main.c
@@ -108,7 +108,7 @@
 				plat_drtm_get_imp_def_dlme_region_size();
 
 	dlme_data_min_size += dlme_data_hdr_init.dlme_addr_map_size +
-			      PLAT_DRTM_EVENT_LOG_MAX_SIZE +
+			      ARM_DRTM_MIN_EVENT_LOG_SIZE +
 			      dlme_data_hdr_init.dlme_tcb_hashes_table_size +
 			      dlme_data_hdr_init.dlme_impdef_region_size;
 
@@ -208,7 +208,7 @@
 		return DENIED;
 	}
 
-	running_on_single_core = psci_is_last_on_cpu_safe();
+	running_on_single_core = psci_is_last_on_cpu_safe(plat_my_core_pos());
 	if (!running_on_single_core) {
 		ERROR("DRTM: invalid launch due to non-boot PE not being turned off\n");
 		return SECONDARY_PE_NOT_OFF;
@@ -282,9 +282,9 @@
 
 	/* Prepare DRTM event log for DLME. */
 	drtm_serialise_event_log(dlme_data_cursor, &serialised_bytes_actual);
-	assert(serialised_bytes_actual <= PLAT_DRTM_EVENT_LOG_MAX_SIZE);
-	dlme_data_hdr->dlme_tpm_log_size = serialised_bytes_actual;
-	dlme_data_cursor += serialised_bytes_actual;
+	assert(serialised_bytes_actual <= ARM_DRTM_MIN_EVENT_LOG_SIZE);
+	dlme_data_hdr->dlme_tpm_log_size = ARM_DRTM_MIN_EVENT_LOG_SIZE;
+	dlme_data_cursor +=  dlme_data_hdr->dlme_tpm_log_size;
 
 	/*
 	 * TODO: Prepare the TCB hashes for DLME, currently its size
diff --git a/services/std_svc/drtm/drtm_main.h b/services/std_svc/drtm/drtm_main.h
index a7d053f..c105b56 100644
--- a/services/std_svc/drtm/drtm_main.h
+++ b/services/std_svc/drtm/drtm_main.h
@@ -37,6 +37,11 @@
 		(((a)->dlme_paddr + (a)->dlme_img_off + (a)->dlme_img_ep_off))
 
 /*
+ * Minimum size of Event Log in DLME data (64 KiB)
+ */
+#define ARM_DRTM_MIN_EVENT_LOG_SIZE	U(0x10000)
+
+/*
  * Range(Min/Max) of DRTM parameter structure versions supported
  */
 #define ARM_DRTM_PARAMS_MIN_VERSION	U(1)
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index d063ea3..13ea5db 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -33,6 +33,8 @@
 #include <smccc_helpers.h>
 #include <lib/extensions/sme.h>
 #include <lib/extensions/sve.h>
+#include <lib/extensions/spe.h>
+#include <lib/extensions/trbe.h>
 #include "rmmd_initial_context.h"
 #include "rmmd_private.h"
 
@@ -127,6 +129,20 @@
 	if (is_feat_sme_supported()) {
 		sme_enable(ctx);
 	}
+
+	/*
+	 * SPE and TRBE cannot be fully disabled from EL3 registers alone, only
+	 * sysreg access can. In case the EL1 controls leave them active on
+	 * context switch, we want the owning security state to be NS so Realm
+	 * can't be DOSed.
+	 */
+	if (is_feat_spe_supported()) {
+		spe_disable(ctx);
+	}
+
+	if (is_feat_trbe_supported()) {
+		trbe_disable(ctx);
+	}
 }
 
 static void manage_extensions_realm_per_world(void)
diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h
index e093a82..6fd0f2b 100644
--- a/services/std_svc/spm/el3_spmc/spmc.h
+++ b/services/std_svc/spm/el3_spmc/spmc.h
@@ -134,6 +134,9 @@
 
 	/* Track the source partition ID to validate a direct response. */
 	uint16_t dir_req_origin_id;
+
+	/* Track direct message function id to validate a direct response. */
+	uint16_t dir_req_funcid;
 };
 
 /*
diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c
index c6ec30c..b0d6ba6 100644
--- a/services/std_svc/spm/el3_spmc/spmc_main.c
+++ b/services/std_svc/spm/el3_spmc/spmc_main.c
@@ -304,6 +304,7 @@
 					void *handle)
 {
 	/* Retrieve populated Direct Response Arguments. */
+	uint64_t smc_fid = SMC_GET_GP(handle, CTX_GPREG_X0);
 	uint64_t x1 = SMC_GET_GP(handle, CTX_GPREG_X1);
 	uint64_t x2 = SMC_GET_GP(handle, CTX_GPREG_X2);
 	uint16_t src_id = ffa_endpoint_source(x1);
@@ -323,7 +324,8 @@
 		return false;
 	}
 
-	if (!direct_msg_validate_arg2(x2)) {
+	if ((smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) &&
+			!direct_msg_validate_arg2(x2)) {
 		ERROR("Invalid EL3 LP message encoding.\n");
 		return false;
 	}
@@ -331,6 +333,21 @@
 }
 
 /*******************************************************************************
+ * Helper function to check that partition can receive direct msg or not.
+ ******************************************************************************/
+static bool direct_msg_receivable(uint32_t properties, uint16_t dir_req_fnum)
+{
+	if ((dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ &&
+			((properties & FFA_PARTITION_DIRECT_REQ_RECV) == 0U)) ||
+			(dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ2 &&
+			((properties & FFA_PARTITION_DIRECT_REQ2_RECV) == 0U))) {
+		return false;
+	}
+
+	return true;
+}
+
+/*******************************************************************************
  * Handle direct request messages and route to the appropriate destination.
  ******************************************************************************/
 static uint64_t direct_req_smc_handler(uint32_t smc_fid,
@@ -345,14 +362,21 @@
 {
 	uint16_t src_id = ffa_endpoint_source(x1);
 	uint16_t dst_id = ffa_endpoint_destination(x1);
+	uint16_t dir_req_funcid;
 	struct el3_lp_desc *el3_lp_descs;
 	struct secure_partition_desc *sp;
 	unsigned int idx;
 
-	/* Check if arg2 has been populated correctly based on message type. */
-	if (!direct_msg_validate_arg2(x2)) {
-		return spmc_ffa_error_return(handle,
-					     FFA_ERROR_INVALID_PARAMETER);
+	dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_REQ2_SMC64) ?
+		FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2;
+
+	/*
+	 * Sanity check for DIRECT_REQ:
+	 * Check if arg2 has been populated correctly based on message type
+	 */
+	if ((dir_req_funcid == FFA_FNUM_MSG_SEND_DIRECT_REQ) &&
+			!direct_msg_validate_arg2(x2)) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_INVALID_PARAMETER);
 	}
 
 	/* Validate Sender is either the current SP or from the normal world. */
@@ -368,6 +392,10 @@
 	/* Check if the request is destined for a Logical Partition. */
 	for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) {
 		if (el3_lp_descs[i].sp_id == dst_id) {
+			if (!direct_msg_receivable(el3_lp_descs[i].properties, dir_req_funcid)) {
+				return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+			}
+
 			uint64_t ret = el3_lp_descs[i].direct_req(
 						smc_fid, secure_origin, x1, x2,
 						x3, x4, cookie, handle, flags);
@@ -402,6 +430,10 @@
 					     FFA_ERROR_INVALID_PARAMETER);
 	}
 
+	if (!direct_msg_receivable(sp->properties, dir_req_funcid)) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
 	/* Protect the runtime state of a UP S-EL0 SP with a lock. */
 	if (sp->runtime_el == S_EL0) {
 		spin_lock(&sp->rt_state_lock);
@@ -430,6 +462,7 @@
 	sp->ec[idx].rt_state = RT_STATE_RUNNING;
 	sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
 	sp->ec[idx].dir_req_origin_id = src_id;
+	sp->ec[idx].dir_req_funcid = dir_req_funcid;
 
 	if (sp->runtime_el == S_EL0) {
 		spin_unlock(&sp->rt_state_lock);
@@ -453,9 +486,13 @@
 					uint64_t flags)
 {
 	uint16_t dst_id = ffa_endpoint_destination(x1);
+	uint16_t dir_req_funcid;
 	struct secure_partition_desc *sp;
 	unsigned int idx;
 
+	dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) ?
+		FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2;
+
 	/* Check if arg2 has been populated correctly based on message type. */
 	if (!direct_msg_validate_arg2(x2)) {
 		return spmc_ffa_error_return(handle,
@@ -507,6 +544,15 @@
 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
 	}
 
+	if (dir_req_funcid != sp->ec[idx].dir_req_funcid) {
+		WARN("Unmatched direct req/resp func id. req:%x, resp:%x on core%u.\n",
+		     sp->ec[idx].dir_req_funcid, (smc_fid & FUNCID_NUM_MASK), idx);
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
 	if (sp->ec[idx].dir_req_origin_id != dst_id) {
 		WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n",
 		     dst_id, sp->ec[idx].dir_req_origin_id, idx);
@@ -522,6 +568,9 @@
 	/* Clear the ongoing direct request ID. */
 	sp->ec[idx].dir_req_origin_id = INV_SP_ID;
 
+	/* Clear the ongoing direct request message version. */
+	sp->ec[idx].dir_req_funcid = 0U;
+
 	if (sp->runtime_el == S_EL0) {
 		spin_unlock(&sp->rt_state_lock);
 	}
@@ -647,6 +696,8 @@
 {
 	struct secure_partition_desc *sp;
 	unsigned int idx;
+	uint16_t dst_id = ffa_endpoint_destination(x1);
+	bool cancel_dir_req = false;
 
 	/* Check that the response did not originate from the Normal world. */
 	if (!secure_origin) {
@@ -674,6 +725,32 @@
 		panic();
 	}
 
+	if (sp->runtime_el == S_EL0) {
+		spin_lock(&sp->rt_state_lock);
+	}
+
+	if (sp->ec[idx].rt_state == RT_STATE_RUNNING &&
+			sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
+		sp->ec[idx].rt_state = RT_STATE_WAITING;
+		sp->ec[idx].dir_req_origin_id = INV_SP_ID;
+		sp->ec[idx].dir_req_funcid = 0x00;
+		cancel_dir_req = true;
+	}
+
+	if (sp->runtime_el == S_EL0) {
+		spin_unlock(&sp->rt_state_lock);
+	}
+
+	if (cancel_dir_req) {
+		if (dst_id == FFA_SPMC_ID) {
+			spmc_sp_synchronous_exit(&sp->ec[idx], x4);
+			/* Should not get here. */
+			panic();
+		} else
+			return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
+					       handle, cookie, flags, dst_id);
+	}
+
 	return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
 }
 
@@ -1267,6 +1344,7 @@
 	case FFA_RX_RELEASE:
 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+	case FFA_MSG_SEND_DIRECT_REQ2_SMC64:
 	case FFA_PARTITION_INFO_GET:
 	case FFA_RXTX_MAP_SMC32:
 	case FFA_RXTX_MAP_SMC64:
@@ -1289,6 +1367,7 @@
 	case FFA_SECONDARY_EP_REGISTER_SMC64:
 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
+	case FFA_MSG_SEND_DIRECT_RESP2_SMC64:
 	case FFA_MEM_RELINQUISH:
 	case FFA_MSG_WAIT:
 	case FFA_CONSOLE_LOG_SMC32:
@@ -1909,7 +1988,9 @@
 
 	/* Validate this entry, we currently only support direct messaging. */
 	if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV |
-			  FFA_PARTITION_DIRECT_REQ_SEND)) != 0U) {
+			  FFA_PARTITION_DIRECT_REQ_SEND |
+			  FFA_PARTITION_DIRECT_REQ2_RECV |
+			  FFA_PARTITION_DIRECT_REQ2_SEND)) != 0U) {
 		WARN("Invalid Secure Partition messaging method (0x%x)\n",
 		     config_32);
 		return -EINVAL;
@@ -2077,39 +2158,34 @@
 		return ret;
 	}
 
-	/* Check that the runtime EL in the manifest was correct. */
-	if (sp->runtime_el != S_EL0 && sp->runtime_el != S_EL1) {
-		ERROR("Unexpected runtime EL: %d\n", sp->runtime_el);
-		return -EINVAL;
-	}
-
 	/* Perform any common initialisation. */
 	spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg);
 
 	/* Perform any initialisation specific to S-EL1 SPs. */
 	if (sp->runtime_el == S_EL1) {
 		spmc_el1_sp_setup(sp, next_image_ep_info);
+		spmc_sp_common_ep_commit(sp, next_image_ep_info);
 	}
-
 #if SPMC_AT_EL3_SEL0_SP
-	/* Setup spsr in endpoint info for common context management routine. */
-	if (sp->runtime_el == S_EL0) {
+	/* Perform any initialisation specific to S-EL0 SPs. */
+	else if (sp->runtime_el == S_EL0) {
+		/* Setup spsr in endpoint info for common context management routine. */
 		spmc_el0_sp_spsr_setup(next_image_ep_info);
-	}
-#endif /* SPMC_AT_EL3_SEL0_SP */
 
-	/* Initialize the SP context with the required ep info. */
-	spmc_sp_common_ep_commit(sp, next_image_ep_info);
+		spmc_sp_common_ep_commit(sp, next_image_ep_info);
 
-#if SPMC_AT_EL3_SEL0_SP
-	/*
-	 * Perform any initialisation specific to S-EL0 not set by common
-	 * context management routine.
-	 */
-	if (sp->runtime_el == S_EL0) {
+		/*
+		 * Perform any initialisation specific to S-EL0 not set by common
+		 * context management routine.
+		 */
 		spmc_el0_sp_setup(sp, boot_info_reg, sp_manifest);
 	}
 #endif /* SPMC_AT_EL3_SEL0_SP */
+	else {
+		ERROR("Unexpected runtime EL: %u\n", sp->runtime_el);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -2356,11 +2432,13 @@
 
 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+	case FFA_MSG_SEND_DIRECT_REQ2_SMC64:
 		return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
 					      x3, x4, cookie, handle, flags);
 
 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
+	case FFA_MSG_SEND_DIRECT_RESP2_SMC64:
 		return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2,
 					       x3, x4, cookie, handle, flags);
 
@@ -2426,11 +2504,13 @@
 		return spmc_ffa_console_log(smc_fid, secure_origin, x1, x2, x3,
 						x4, cookie, handle, flags);
 
-	case FFA_MEM_PERM_GET:
+	case FFA_MEM_PERM_GET_SMC32:
+	case FFA_MEM_PERM_GET_SMC64:
 		return ffa_mem_perm_get_handler(smc_fid, secure_origin, x1, x2,
 						x3, x4, cookie, handle, flags);
 
-	case FFA_MEM_PERM_SET:
+	case FFA_MEM_PERM_SET_SMC32:
+	case FFA_MEM_PERM_SET_SMC64:
 		return ffa_mem_perm_set_handler(smc_fid, secure_origin, x1, x2,
 						x3, x4, cookie, handle, flags);
 
diff --git a/services/std_svc/spm/el3_spmc/spmc_pm.c b/services/std_svc/spm/el3_spmc/spmc_pm.c
index 517d6d5..0a6215c 100644
--- a/services/std_svc/spm/el3_spmc/spmc_pm.c
+++ b/services/std_svc/spm/el3_spmc/spmc_pm.c
@@ -147,6 +147,8 @@
 	ec->rt_model = RT_MODEL_DIR_REQ;
 	ec->rt_state = RT_STATE_RUNNING;
 	ec->dir_req_origin_id = FFA_SPMC_ID;
+	/* Expect a direct message response from the SP. */
+	ec->dir_req_funcid = FFA_FNUM_MSG_SEND_DIRECT_REQ;
 
 	rc = spmc_sp_synchronous_entry(ec);
 	if (rc != 0ULL) {
diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c
index f7357f1..d42115d 100644
--- a/services/std_svc/spm/el3_spmc/spmc_setup.c
+++ b/services/std_svc/spm/el3_spmc/spmc_setup.c
@@ -5,14 +5,22 @@
  */
 
 #include <assert.h>
+#include <errno.h>
 #include <string.h>
 
 #include <arch.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <common/fdt_wrappers.h>
+
 #include <context.h>
 #include <lib/el3_runtime/context_mgmt.h>
+#if HOB_LIST
+#include <lib/hob/hob.h>
+#include <lib/hob/hob_guid.h>
+#include <lib/hob/mmram.h>
+#include <lib/hob/mpinfo.h>
+#endif
 #include <lib/utils.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <libfdt.h>
@@ -51,6 +59,199 @@
 	SP_MEM_REGION_NOT_SPECIFIED
 };
 
+
+#if HOB_LIST
+static int get_memory_region_info(void *sp_manifest, int mem_region_node,
+		const char *name, uint32_t granularity,
+		uint64_t *base_address, uint32_t *size)
+{
+	char *property;
+	int node, ret;
+
+	if (name != NULL) {
+		node = fdt_subnode_offset_namelen(sp_manifest, mem_region_node,
+				name, strlen(name));
+		if (node < 0) {
+			ERROR("Not found '%s' region in memory regions configuration for SP.\n",
+					name);
+			return -ENOENT;
+		}
+	} else {
+		node = mem_region_node;
+	}
+
+	property = "base-address";
+	ret = fdt_read_uint64(sp_manifest, node, property, base_address);
+	if (ret < 0) {
+		ERROR("Not found property(%s) in memory region(%s).\n",
+				property, name);
+		return -ENOENT;
+	}
+
+	property = "pages-count";
+	ret = fdt_read_uint32(sp_manifest, node, property, size);
+	if (ret < 0) {
+		ERROR("Not found property(%s) in memory region(%s).\n",
+				property, name);
+		return -ENOENT;
+	}
+
+	*size = ((*size) << (PAGE_SIZE_SHIFT + (granularity << 1)));
+
+	return 0;
+}
+
+static struct efi_hob_handoff_info_table *build_sp_boot_hob_list(
+		void *sp_manifest, uintptr_t hob_table_start, size_t *hob_table_size)
+{
+	struct efi_hob_handoff_info_table *hob_table;
+	uintptr_t base_address;
+	int mem_region_node;
+	int32_t node, ret;
+	const char *name;
+	uint32_t granularity, size;
+	uint32_t mem_region_num;
+	struct efi_guid ns_buf_guid = MM_NS_BUFFER_GUID;
+	struct efi_guid mmram_resv_guid = MM_PEI_MMRAM_MEMORY_RESERVE_GUID;
+	struct efi_mmram_descriptor *mmram_desc_data;
+	struct efi_mmram_hob_descriptor_block *mmram_hob_desc_data;
+
+	if (sp_manifest == NULL || hob_table_size == NULL || *hob_table_size == 0) {
+		return NULL;
+	}
+
+	node = fdt_path_offset(sp_manifest, "/");
+	if (node < 0) {
+		ERROR("Failed to get root in sp_manifest.\n");
+		return NULL;
+	}
+
+	ret = fdt_read_uint32(sp_manifest, node, "xlat-granule", &granularity);
+	if (ret < 0) {
+		ERROR("Not found property(xlat-granule) in sp_manifest.\n");
+		return NULL;
+	}
+
+	if (granularity > 0x02) {
+		ERROR("Invalid granularity value: 0x%x\n", granularity);
+		return NULL;
+	}
+
+	mem_region_node = fdt_subnode_offset_namelen(sp_manifest, 0, "memory-regions",
+			sizeof("memory-regions") - 1);
+	if (node < 0) {
+		ERROR("Not found memory-region configuration for SP.\n");
+		return NULL;
+	}
+
+	INFO("Generating PHIT_HOB...\n");
+
+	hob_table = create_hob_list(BL32_BASE, BL32_LIMIT,
+			hob_table_start, *hob_table_size);
+	if (hob_table == NULL) {
+		ERROR("Failed to create Hob Table.\n");
+		return NULL;
+	}
+
+	/*
+	 * Create fv hob.
+	 */
+	ret = get_memory_region_info(sp_manifest, mem_region_node,
+			"stmm_region", granularity, &base_address, &size);
+	if (ret < 0) {
+		return NULL;
+	}
+
+	if (base_address != BL32_BASE &&
+			base_address + size > BL32_LIMIT) {
+		ERROR("Image is ouf of bound(0x%lx/0x%x), should be in (0x%llx/0x%llx)\n",
+				base_address, size, BL32_BASE, BL32_LIMIT - BL32_BASE);
+		return NULL;
+	}
+
+	ret = create_fv_hob(hob_table, base_address, size);
+	if (ret < 0) {
+		ERROR("Failed to create fv hob... ret:%d\n", ret);
+		return NULL;
+	}
+
+	INFO("Success to create FV hob(0x%lx/0x%x).\n", base_address, size);
+
+	/*
+	 * Create Ns Buffer hob.
+	 */
+	ret = get_memory_region_info(sp_manifest, mem_region_node,
+			"ns_comm_buffer", granularity, &base_address, &size);
+	if (ret < 0) {
+		return NULL;
+	}
+
+	ret = create_guid_hob(hob_table, &ns_buf_guid,
+			sizeof(struct efi_mmram_descriptor), (void **) &mmram_desc_data);
+	if (ret < 0) {
+		ERROR("Failed to create ns buffer hob\n");
+		return NULL;
+	}
+
+	mmram_desc_data->physical_start = base_address;
+	mmram_desc_data->physical_size = size;
+	mmram_desc_data->cpu_start = base_address;
+	mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+
+	/*
+	 * Create mmram_resv hob.
+	 */
+	for (node = fdt_first_subnode(sp_manifest, mem_region_node), mem_region_num = 0;
+			node >= 0;
+			node = fdt_next_subnode(sp_manifest, node), mem_region_num++) {
+		ret = get_memory_region_info(sp_manifest, node, NULL, granularity,
+				&base_address, &size);
+		if (ret < 0) {
+			name = fdt_get_name(sp_manifest, node, NULL);
+			ERROR("Invalid memory region(%s) found!\n", name);
+			return NULL;
+		}
+	}
+
+	ret = create_guid_hob(hob_table, &mmram_resv_guid,
+			(sizeof(struct efi_mmram_hob_descriptor_block) +
+			 (sizeof(struct efi_mmram_descriptor) * mem_region_num)),
+			(void **) &mmram_hob_desc_data);
+	if (ret < 0) {
+		ERROR("Failed to create mmram_resv hob. ret: %d\n", ret);
+		return NULL;
+	}
+
+	mmram_hob_desc_data->number_of_mm_reserved_regions = mem_region_num;
+
+	for (node = fdt_first_subnode(sp_manifest, mem_region_node), mem_region_num = 0;
+			node >= 0;
+			node = fdt_next_subnode(sp_manifest, node), mem_region_num++) {
+		get_memory_region_info(sp_manifest, node, NULL, granularity,
+				&base_address, &size);
+		name = fdt_get_name(sp_manifest, node, NULL);
+
+		mmram_desc_data = &mmram_hob_desc_data->descriptor[mem_region_num];
+		mmram_desc_data->physical_start = base_address;
+		mmram_desc_data->physical_size = size;
+		mmram_desc_data->cpu_start = base_address;
+
+		if (!strcmp(name, "heap")) {
+			mmram_desc_data->region_state = EFI_CACHEABLE;
+		} else {
+			mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+		}
+	}
+
+	*hob_table_size = hob_table->efi_free_memory_bottom -
+		(efi_physical_address_t) hob_table;
+
+  return hob_table;
+}
+#endif
+
+
+
 /*
  * This function creates a initialization descriptor in the memory reserved
  * for passing boot information to an SP. It then copies the partition manifest
@@ -62,14 +263,13 @@
 {
 	struct ffa_boot_info_header *boot_header;
 	struct ffa_boot_info_desc *boot_descriptor;
-	uintptr_t manifest_addr;
+	uintptr_t content_addr;
 
 	/*
 	 * Calculate the maximum size of the manifest that can be accommodated
 	 * in the boot information memory region.
 	 */
-	const unsigned int
-	max_manifest_sz = sizeof(ffa_boot_info_mem) -
+	size_t max_sz = sizeof(ffa_boot_info_mem) -
 			  (sizeof(struct ffa_boot_info_header) +
 			   sizeof(struct ffa_boot_info_desc));
 
@@ -83,17 +283,6 @@
 		return;
 	}
 
-	/*
-	 * Check if the manifest will fit into the boot info memory region else
-	 * bail.
-	 */
-	if (ep_info->args.arg1 > max_manifest_sz) {
-		WARN("Unable to copy manifest into boot information. ");
-		WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n",
-		     max_manifest_sz, ep_info->args.arg1);
-		return;
-	}
-
 	/* Zero the memory region before populating. */
 	memset(ffa_boot_info_mem, 0, PAGE_SIZE);
 
@@ -125,29 +314,58 @@
 	/* Set the count. Currently 1 since only the manifest is specified. */
 	boot_header->count_boot_info_desc = 1;
 
+	boot_descriptor->flags =
+		FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) |
+		FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR);
+
+	content_addr = (uintptr_t) (ffa_boot_info_mem +
+				     boot_header->offset_boot_info_desc +
+				     boot_header->size_boot_info_desc);
+
+#if HOB_LIST
+	/* Populate the boot information descriptor for the hob_list. */
+	boot_descriptor->type =
+		FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) |
+		FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_HOB);
+
+	content_addr = (uintptr_t) build_sp_boot_hob_list(
+			(void *) ep_info->args.arg0, content_addr, &max_sz);
+	if (content_addr == (uintptr_t) NULL) {
+		WARN("Unable to create phit hob properly.");
+		return;
+	}
+
+	boot_descriptor->size_boot_info = max_sz;
+	boot_descriptor->content = content_addr;
+#else
+	/*
+	 * Check if the manifest will fit into the boot info memory region else
+	 * bail.
+	 */
+	if (ep_info->args.arg1 > max_sz) {
+		WARN("Unable to copy manifest into boot information. ");
+		WARN("Max sz = %lu bytes. Manifest sz = %lu bytes\n",
+		     max_sz, ep_info->args.arg1);
+		return;
+	}
+
 	/* Populate the boot information descriptor for the manifest. */
 	boot_descriptor->type =
 		FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) |
 		FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT);
 
-	boot_descriptor->flags =
-		FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) |
-		FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR);
-
 	/*
 	 * Copy the manifest into boot info region after the boot information
 	 * descriptor.
 	 */
 	boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1;
 
-	manifest_addr = (uintptr_t) (ffa_boot_info_mem +
-				     boot_header->offset_boot_info_desc +
-				     boot_header->size_boot_info_desc);
 
-	memcpy((void *) manifest_addr, (void *) ep_info->args.arg0,
+	memcpy((void *) content_addr, (void *) ep_info->args.arg0,
 	       boot_descriptor->size_boot_info);
 
-	boot_descriptor->content = manifest_addr;
+	boot_descriptor->content = content_addr;
+#endif
 
 	/* Calculate the size of the total boot info blob. */
 	boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc +
@@ -158,7 +376,7 @@
 	INFO("SP boot info @ 0x%lx, size: %u bytes.\n",
 	     (uintptr_t) ffa_boot_info_mem,
 	     boot_header->size_boot_info_blob);
-	INFO("SP manifest @ 0x%lx, size: %u bytes.\n",
+	INFO("SP content @ 0x%lx, size: %u bytes.\n",
 	     boot_descriptor->content,
 	     boot_descriptor->size_boot_info);
 }
@@ -194,6 +412,7 @@
 		out[0] = '\0';
 	} else {
 		memcpy(out, prop, MIN(lenp, (int)len));
+		out[MIN(lenp, (int)len) - 1] = '\0';
 	}
 }
 
@@ -292,10 +511,11 @@
 		sp_mem_regions.base_va = base_address;
 		sp_mem_regions.size = size;
 
-		INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx attr:0x%x\n",
+		INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx mem_attr: 0x%x, attr:0x%x\n",
 		     sp_mem_regions.base_pa,
 		     sp_mem_regions.base_va,
 		     sp_mem_regions.size,
+		     mem_attr,
 		     sp_mem_regions.attr);
 
 		if (type == SP_MEM_REGION_DEVICE) {
@@ -464,7 +684,6 @@
 	}
 
 	spmc_el0_sp_setup_system_registers(sp, ctx);
-
 }
 #endif /* SPMC_AT_EL3_SEL0_SP */
 
diff --git a/services/std_svc/spm/spm_mm/spm_mm_setup.c b/services/std_svc/spm/spm_mm/spm_mm_setup.c
index de05459..66ce84c 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_setup.c
+++ b/services/std_svc/spm/spm_mm/spm_mm_setup.c
@@ -13,6 +13,15 @@
 #include <context.h>
 #include <common/debug.h>
 #include <lib/el3_runtime/context_mgmt.h>
+#if HOB_LIST
+#include <lib/hob/hob.h>
+#include <lib/hob/hob_guid.h>
+#include <lib/hob/mmram.h>
+#include <lib/hob/mpinfo.h>
+#endif
+#if TRANSFER_LIST
+#include <lib/transfer_list.h>
+#endif
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <platform_def.h>
 #include <plat/common/common_def.h>
@@ -23,6 +32,92 @@
 #include "spm_mm_private.h"
 #include "spm_shim_private.h"
 
+#if HOB_LIST && TRANSFER_LIST
+static struct efi_hob_handoff_info_table *build_sp_boot_hob_list(
+		const spm_mm_boot_info_t *sp_boot_info, uint16_t *hob_table_size)
+{
+	int ret;
+	struct efi_hob_handoff_info_table *hob_table;
+	struct efi_guid ns_buf_guid = MM_NS_BUFFER_GUID;
+	struct efi_guid mmram_resv_guid = MM_PEI_MMRAM_MEMORY_RESERVE_GUID;
+	struct efi_mmram_descriptor *mmram_desc_data;
+	uint16_t mmram_resv_data_size;
+	struct efi_mmram_hob_descriptor_block *mmram_hob_desc_data;
+	uint64_t hob_table_offset;
+
+	hob_table_offset = sizeof(struct transfer_list_header) +
+		sizeof(struct transfer_list_entry);
+
+	*hob_table_size = 0U;
+
+	hob_table = create_hob_list(sp_boot_info->sp_mem_base,
+			sp_boot_info->sp_mem_limit - sp_boot_info->sp_mem_base,
+			sp_boot_info->sp_shared_buf_base + hob_table_offset,
+			sp_boot_info->sp_shared_buf_size);
+	if (hob_table == NULL) {
+		return NULL;
+	}
+
+	ret = create_fv_hob(hob_table, sp_boot_info->sp_image_base,
+			sp_boot_info->sp_image_size);
+	if (ret) {
+		return NULL;
+	}
+
+	ret = create_guid_hob(hob_table, &ns_buf_guid,
+			sizeof(struct efi_mmram_descriptor), (void **) &mmram_desc_data);
+	if (ret) {
+		return NULL;
+	}
+
+	mmram_desc_data->physical_start = sp_boot_info->sp_ns_comm_buf_base;
+	mmram_desc_data->physical_size = sp_boot_info->sp_ns_comm_buf_size;
+	mmram_desc_data->cpu_start = sp_boot_info->sp_ns_comm_buf_base;
+	mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+
+	mmram_resv_data_size = sizeof(struct efi_mmram_hob_descriptor_block) +
+		sizeof(struct efi_mmram_descriptor) * sp_boot_info->num_sp_mem_regions;
+
+	ret = create_guid_hob(hob_table, &mmram_resv_guid,
+			mmram_resv_data_size, (void **) &mmram_hob_desc_data);
+	if (ret) {
+		return NULL;
+	}
+
+	*hob_table_size = hob_table->efi_free_memory_bottom -
+		(efi_physical_address_t) hob_table;
+
+	mmram_hob_desc_data->number_of_mm_reserved_regions = 4U;
+	mmram_desc_data = &mmram_hob_desc_data->descriptor[0];
+
+	/* First, should be image mm range. */
+	mmram_desc_data[0].physical_start = sp_boot_info->sp_image_base;
+	mmram_desc_data[0].physical_size = sp_boot_info->sp_image_size;
+	mmram_desc_data[0].cpu_start = sp_boot_info->sp_image_base;
+	mmram_desc_data[0].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+
+	/* Second, should be shared buffer mm range. */
+	mmram_desc_data[1].physical_start = sp_boot_info->sp_shared_buf_base;
+	mmram_desc_data[1].physical_size = sp_boot_info->sp_shared_buf_size;
+	mmram_desc_data[1].cpu_start = sp_boot_info->sp_shared_buf_base;
+	mmram_desc_data[1].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+
+	/* Ns Buffer mm range */
+	mmram_desc_data[2].physical_start = sp_boot_info->sp_ns_comm_buf_base;
+	mmram_desc_data[2].physical_size = sp_boot_info->sp_ns_comm_buf_size;
+	mmram_desc_data[2].cpu_start = sp_boot_info->sp_ns_comm_buf_base;
+	mmram_desc_data[2].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
+
+	/* Heap mm range */
+	mmram_desc_data[3].physical_start = sp_boot_info->sp_heap_base;
+	mmram_desc_data[3].physical_size = sp_boot_info->sp_heap_size;
+	mmram_desc_data[3].cpu_start = sp_boot_info->sp_heap_base;
+	mmram_desc_data[3].region_state = EFI_CACHEABLE;
+
+	return hob_table;
+}
+#endif
+
 /* Setup context of the Secure Partition */
 void spm_sp_setup(sp_context_t *sp_ctx)
 {
@@ -32,6 +127,15 @@
 	const spm_mm_boot_info_t *sp_boot_info =
 			plat_get_secure_partition_boot_info(NULL);
 
+#if HOB_LIST && TRANSFER_LIST
+	struct efi_hob_handoff_info_table *hob_table;
+	struct transfer_list_header *sp_boot_tl;
+	struct transfer_list_entry *sp_boot_te;
+	uint16_t hob_table_size;
+#endif
+
+	assert(sp_boot_info != NULL);
+
 	/*
 	 * Initialize CPU context
 	 * ----------------------
@@ -195,7 +299,35 @@
 	 * Prepare information in buffer shared between EL3 and S-EL0
 	 * ----------------------------------------------------------
 	 */
+#if HOB_LIST && TRANSFER_LIST
+	sp_boot_tl = transfer_list_init((void *) sp_boot_info->sp_shared_buf_base,
+			sp_boot_info->sp_shared_buf_size);
+	assert(sp_boot_tl != NULL);
 
+	hob_table = build_sp_boot_hob_list(sp_boot_info, &hob_table_size);
+	assert(hob_table != NULL);
+
+	transfer_list_update_checksum(sp_boot_tl);
+
+	sp_boot_te = transfer_list_add(sp_boot_tl, TL_TAG_HOB_LIST,
+			hob_table_size, hob_table);
+	if (sp_boot_te == NULL) {
+		ERROR("Failed to add HOB list to xfer list\n");
+	}
+
+	transfer_list_set_handoff_args(sp_boot_tl, &ep_info);
+
+	transfer_list_dump(sp_boot_tl);
+
+	write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0,
+			ep_info.args.arg0);
+	write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1,
+			ep_info.args.arg1);
+	write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2,
+			ep_info.args.arg2);
+	write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3,
+			ep_info.args.arg3);
+#else
 	void *shared_buf_ptr = (void *) sp_boot_info->sp_shared_buf_base;
 
 	/* Copy the boot information into the shared buffer with the SP. */
@@ -205,7 +337,6 @@
 	assert(sp_boot_info->sp_shared_buf_base <=
 				(UINTPTR_MAX - sp_boot_info->sp_shared_buf_size + 1));
 
-	assert(sp_boot_info != NULL);
 
 	memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
 	       sizeof(spm_mm_boot_info_t));
@@ -256,4 +387,5 @@
 		if (plat_my_core_pos() == sp_mp_info[index].linear_id)
 			sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
 	}
+#endif
 }
diff --git a/tools/amlogic/Makefile b/tools/amlogic/Makefile
index 7bfee7d..cdaf7e7 100644
--- a/tools/amlogic/Makefile
+++ b/tools/amlogic/Makefile
@@ -1,5 +1,6 @@
 #
 # Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier:     BSD-3-Clause
 # https://spdx.org/licenses
@@ -7,11 +8,10 @@
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
 
-PROJECT := doimage${BIN_EXT}
+PROJECT := doimage$(.exe)
 OBJECTS := doimage.o
 
 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE
@@ -38,6 +38,6 @@
 	$(q)$(host-cc) -c ${HOSTCCFLAGS} $< -o $@
 
 clean:
-	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
+	$(q)rm -rf $(PROJECT) $(OBJECTS)
 
 distclean: clean
diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile
index ce12a66..e403b2d 100644
--- a/tools/cert_create/Makefile
+++ b/tools/cert_create/Makefile
@@ -1,18 +1,17 @@
 #
-# 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
 #
 
 PLAT		:= none
 DEBUG		:= 0
-CRTTOOL		?= cert_create${BIN_EXT}
+CRTTOOL		?= cert_create$(.exe)
 BINARY		:= $(notdir ${CRTTOOL})
 COT		:= tbbr
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}defaults.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
@@ -95,7 +94,7 @@
 endif
 
 clean:
-	$(call SHELL_DELETE_ALL,${OBJECTS})
+	$(q)rm -rf $(OBJECTS)
 
 realclean: clean
-	$(call SHELL_DELETE,${BINARY})
+	$(q)rm -f $(BINARY)
diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h
index f7adfab..83a7b18 100644
--- a/tools/cert_create/include/key.h
+++ b/tools/cert_create/include/key.h
@@ -45,8 +45,8 @@
 	{ 2048, 1024, 3072, 4096 },	/* KEY_ALG_RSA */
 #ifndef OPENSSL_NO_EC
 	{ 256, 384 },			/* KEY_ALG_ECDSA_NIST */
-	{},				/* KEY_ALG_ECDSA_BRAINPOOL_R */
-	{}				/* KEY_ALG_ECDSA_BRAINPOOL_T */
+	{ 256 },			/* KEY_ALG_ECDSA_BRAINPOOL_R */
+	{ 256 }				/* KEY_ALG_ECDSA_BRAINPOOL_T */
 #endif /* OPENSSL_NO_EC */
 };
 
diff --git a/tools/cot_dt2c/poetry.lock b/tools/cot_dt2c/poetry.lock
index df58d54..eea96cd 100644
--- a/tools/cot_dt2c/poetry.lock
+++ b/tools/cot_dt2c/poetry.lock
@@ -1,35 +1,6 @@
 # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
 
 [[package]]
-name = "atomicwrites"
-version = "1.4.1"
-description = "Atomic file writes."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
-]
-
-[[package]]
-name = "attrs"
-version = "24.2.0"
-description = "Classes Without Boilerplate"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
-    {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
-]
-
-[package.extras]
-benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
-tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
-
-[[package]]
 name = "click"
 version = "8.1.7"
 description = "Composable command line interface toolkit"
@@ -54,6 +25,20 @@
     {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 ]
 
+[[package]]
+name = "exceptiongroup"
+version = "1.2.2"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
+    {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
 [[package]]
 name = "igraph"
 version = "0.11.6"
@@ -218,17 +203,6 @@
 testing = ["pytest", "pytest-benchmark"]
 
 [[package]]
-name = "py"
-version = "1.11.0"
-description = "library with cross-python path, ini-parsing, io, code, log facilities"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-files = [
-    {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
-    {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
-]
-
-[[package]]
 name = "pydevicetree"
 version = "0.0.13"
 description = "A library for parsing Devicetree Source v1"
@@ -258,27 +232,25 @@
 
 [[package]]
 name = "pytest"
-version = "6.2.5"
+version = "8.3.4"
 description = "pytest: simple powerful testing with Python"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 files = [
-    {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
-    {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
+    {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"},
+    {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"},
 ]
 
 [package.dependencies]
-atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
-attrs = ">=19.2.0"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
 iniconfig = "*"
 packaging = "*"
-pluggy = ">=0.12,<2.0"
-py = ">=1.8.2"
-toml = "*"
+pluggy = ">=1.5,<2"
+tomli = {version = ">=1", markers = "python_version < \"3.11\""}
 
 [package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
 
 [[package]]
 name = "tenacity"
@@ -318,6 +290,47 @@
 ]
 
 [[package]]
+name = "tomli"
+version = "2.2.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
+    {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
+    {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
+    {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
+    {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
+    {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
+    {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
+    {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
+    {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
+    {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
+    {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
+    {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
+    {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
+    {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
+    {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
+    {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
+    {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
+    {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
+    {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
+    {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
+    {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
+    {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
+    {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
+    {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
+    {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
+    {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
+    {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
+    {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
+    {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
+    {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
+    {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
+    {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
+]
+
+[[package]]
 name = "typing-extensions"
 version = "4.12.2"
 description = "Backported and Experimental Type Hints for Python 3.8+"
@@ -331,4 +344,4 @@
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "afa5cb49be96467a848bab753a630c6f5ec42d6750d67d29920c3e3971774e36"
+content-hash = "0f5b2b008bb5de8545881eaeacfdd1a6fe50e5271feea4635d622ffce9e550dc"
diff --git a/tools/cot_dt2c/pyproject.toml b/tools/cot_dt2c/pyproject.toml
index 73251d7..fc31d54 100644
--- a/tools/cot_dt2c/pyproject.toml
+++ b/tools/cot_dt2c/pyproject.toml
@@ -38,7 +38,7 @@
 
 [tool.poetry.group.dev.dependencies]
 mypy = "^0.910"
-pytest = "^6.2.5"
+pytest = "^8.3.4"
 
 [tool.mypy]
 # https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
diff --git a/tools/encrypt_fw/Makefile b/tools/encrypt_fw/Makefile
index 50b0fa2..14def1d 100644
--- a/tools/encrypt_fw/Makefile
+++ b/tools/encrypt_fw/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2024, Arm Limited. All rights reserved.
+# Copyright (c) 2024-2025, Arm Limited. All rights reserved.
 # Copyright (c) 2019-2022, Linaro Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
@@ -7,13 +7,12 @@
 
 BUILD_INFO	?= 1
 DEBUG		:= 0
-ENCTOOL		?= encrypt_fw${BIN_EXT}
+ENCTOOL		?= encrypt_fw$(.exe)
 BINARY		:= $(notdir ${ENCTOOL})
 OPENSSL_DIR	:= /usr
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}defaults.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
@@ -75,7 +74,7 @@
 endif
 
 clean:
-	$(call SHELL_DELETE_ALL,${OBJECTS})
+	$(q)rm -rf $(OBJECTS)
 
 realclean: clean
-	$(call SHELL_DELETE,${BINARY})
+	$(q)rm -f $(BINARY)
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
index 54dee87..a660a50 100644
--- a/tools/fiptool/Makefile
+++ b/tools/fiptool/Makefile
@@ -1,17 +1,16 @@
 #
-# Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}defaults.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
 
-FIPTOOL ?= fiptool${BIN_EXT}
+FIPTOOL ?= fiptool$(.exe)
 PROJECT := $(notdir ${FIPTOOL})
 OBJECTS := fiptool.o tbbr_config.o
 STATIC ?= 0
@@ -93,4 +92,4 @@
 endif # STATIC
 
 clean:
-	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS} $(DEPS))
+	$(q)rm -rf $(PROJECT) $(OBJECTS) $(DEPS)
diff --git a/tools/fiptool/Makefile.msvc b/tools/fiptool/Makefile.msvc
deleted file mode 100644
index 9081bc6..0000000
--- a/tools/fiptool/Makefile.msvc
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-CC = cl.exe
-LD = link.exe
-
-# FIPTOOLPATH and FIPTOOL are passed from the main makefile.
-
-OBJECTS = $(FIPTOOLPATH)\fiptool.obj     \
-          $(FIPTOOLPATH)\tbbr_config.obj \
-          $(FIPTOOLPATH)\win_posix.obj
-
-INC = -I$(FIPTOOLPATH) -Iinclude\tools_share
-
-CFLAGS = $(CFLAGS) /nologo /Za /Zi /c /O2 /MT
-
-all: $(FIPTOOL)
-
-$(FIPTOOL): $(OBJECTS)
-	$(LD) /nologo /INCREMENTAL:NO /debug /nodefaultlib:libc.lib /out:$@ $(LIBS) $**
-
-.PHONY: clean realclean
-
-clean:
-	-@del /f /q $(OBJECTS) > nul
-	-@del /f /q $(FIPTOOLPATH)\*.pdb > nul
-
-realclean:
-	-@del /f /q $(OBJECTS) > nul
-	-@del /f /q $(FIPTOOLPATH)\*.pdb > nul
-	-@del /f /q $(FIPTOOL) > nul
-
-.c.obj:
-	$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
diff --git a/tools/nxp/create_pbl/Makefile b/tools/nxp/create_pbl/Makefile
index 22aa921..965cc51 100644
--- a/tools/nxp/create_pbl/Makefile
+++ b/tools/nxp/create_pbl/Makefile
@@ -1,18 +1,18 @@
 #
 # Copyright 2018-2020 NXP
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 MAKE_HELPERS_DIRECTORY := ../../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
 
-PROJECT_1 := create_pbl${BIN_EXT}
+PROJECT_1 := create_pbl$(.exe)
 OBJECTS_1 := create_pbl.o
-PROJECT_2 := byte_swap${BIN_EXT}
+PROJECT_2 := byte_swap$(.exe)
 OBJECTS_2 := byte_swap.o
 
 override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700
@@ -49,5 +49,5 @@
 	$(q)$(host-cc) -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
 
 clean:
-	$(call SHELL_DELETE_ALL, ${PROJECT_1} ${OBJECTS_1})
-	$(call SHELL_DELETE_ALL, ${PROJECT_2} ${OBJECTS_2})
+	$(q)rm -rf $(PROJECT_1) $(OBJECTS_1)
+	$(q)rm -rf $(PROJECT_2) $(OBJECTS_2)
diff --git a/tools/nxp/create_pbl/create_pbl.mk b/tools/nxp/create_pbl/create_pbl.mk
index 305c049..81f6d13 100644
--- a/tools/nxp/create_pbl/create_pbl.mk
+++ b/tools/nxp/create_pbl/create_pbl.mk
@@ -1,12 +1,13 @@
 #
 # Copyright 2018-2020 NXP
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #
 
-CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
-BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl$(.exe)
+BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap$(.exe)
 
 HOST_GCC	:= gcc
 
diff --git a/tools/nxp/create_pbl/pbl_ch2.mk b/tools/nxp/create_pbl/pbl_ch2.mk
index bf05a12..47ff892 100644
--- a/tools/nxp/create_pbl/pbl_ch2.mk
+++ b/tools/nxp/create_pbl/pbl_ch2.mk
@@ -1,12 +1,13 @@
 #
 # Copyright 2020 NXP
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #
 
-CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
-BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl$(.exe)
+BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap$(.exe)
 
 HOST_GCC	:= gcc
 
diff --git a/tools/nxp/create_pbl/pbl_ch3.mk b/tools/nxp/create_pbl/pbl_ch3.mk
index 15129e4..f5d42cd 100644
--- a/tools/nxp/create_pbl/pbl_ch3.mk
+++ b/tools/nxp/create_pbl/pbl_ch3.mk
@@ -1,13 +1,14 @@
 #
 # Copyright 2018-2022 NXP
+# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #
 SHELL=/bin/bash
 
-CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
-BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+CREATE_PBL	?=	${CREATE_PBL_TOOL_PATH}/create_pbl$(.exe)
+BYTE_SWAP	?=	${CREATE_PBL_TOOL_PATH}/byte_swap$(.exe)
 
 HOST_GCC	:= gcc
 
diff --git a/tools/sptool/Makefile b/tools/sptool/Makefile
index 0da5c09..f579a42 100644
--- a/tools/sptool/Makefile
+++ b/tools/sptool/Makefile
@@ -1,16 +1,15 @@
 #
-# Copyright (c) 2018-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
 
-SPTOOL  ?= sptool${BIN_EXT}
+SPTOOL  ?= sptool$(.exe)
 PROJECT := $(notdir ${SPTOOL})
 OBJECTS := sptool.o
 
@@ -40,4 +39,4 @@
 	$(q)$(host-cc) -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
 
 clean:
-	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
+	$(q)rm -rf $(PROJECT) $(OBJECTS)
diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile
index 453daae..64b6ccf 100644
--- a/tools/stm32image/Makefile
+++ b/tools/stm32image/Makefile
@@ -1,16 +1,15 @@
 #
-# Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 MAKE_HELPERS_DIRECTORY := ../../make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
-include ${MAKE_HELPERS_DIRECTORY}build_env.mk
 include ${MAKE_HELPERS_DIRECTORY}common.mk
 include ${MAKE_HELPERS_DIRECTORY}toolchain.mk
 
-PROJECT := stm32image${BIN_EXT}
+PROJECT := stm32image$(.exe)
 OBJECTS := stm32image.o
 
 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE
@@ -37,6 +36,6 @@
 	$(q)$(host-cc) -c ${HOSTCCFLAGS} $< -o $@
 
 clean:
-	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
+	$(q)rm -rf $(PROJECT) $(OBJECTS)
 
 distclean: clean
diff --git a/tools/tlc/poetry.lock b/tools/tlc/poetry.lock
index decec59..ea1b750 100644
--- a/tools/tlc/poetry.lock
+++ b/tools/tlc/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
 
 [[package]]
 name = "astroid"
@@ -495,13 +495,13 @@
 
 [[package]]
 name = "jinja2"
-version = "3.1.4"
+version = "3.1.5"
 description = "A very fast and expressive template engine."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
-    {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+    {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
+    {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
 ]
 
 [package.dependencies]
@@ -1331,13 +1331,13 @@
 
 [[package]]
 name = "virtualenv"
-version = "20.26.5"
+version = "20.26.6"
 description = "Virtual Python Environment builder"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6"},
-    {file = "virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4"},
+    {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"},
+    {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"},
 ]
 
 [package.dependencies]
@@ -1431,4 +1431,4 @@
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "aac9123f3fa544b8c3e9b085f41f5a1c6c4ed2d59ce3236dcda6ea2aef5a694c"
+content-hash = "a4b9c3bababadba14f49a8de0ccee1f5a141b6cea23d02a19ab8bf4f8c45533f"
diff --git a/tools/tlc/pyproject.toml b/tools/tlc/pyproject.toml
index b606238..e9ff26f 100644
--- a/tools/tlc/pyproject.toml
+++ b/tools/tlc/pyproject.toml
@@ -39,7 +39,7 @@
 click = "^8.1.7"
 pyyaml = "^6.0.1"
 tox = "^4.18.0"
-jinja2 = "^3.1.4"
+jinja2 = "^3.1.5"
 
 [tool.poetry.group.dev]
 optional = true