Merge "refactor(fvp_r): remove unused files and clean up makefiles" into integration
diff --git a/Makefile b/Makefile
index ec6f885..e5ab324 100644
--- a/Makefile
+++ b/Makefile
@@ -150,8 +150,6 @@
 ifeq (${USE_SPINLOCK_CAS},1)
 ifneq (${ARCH},aarch64)
         $(error USE_SPINLOCK_CAS requires AArch64)
-else
-        $(info USE_SPINLOCK_CAS is an experimental feature)
 endif
 endif
 
@@ -525,7 +523,6 @@
     endif
 
     ifeq (${SPD},spmd)
-        $(warning "SPMD is an experimental feature")
         # SPMD is located in std_svc directory
         SPD_DIR := std_svc
 
@@ -731,12 +728,7 @@
 
 # SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled.
 ifeq ($(SDEI_SUPPORT)-$(SDEI_IN_FCONF),0-1)
-$(error "SDEI_IN_FCONF is an experimental feature and is only supported when \
-	SDEI_SUPPORT is enabled")
-endif
-
-ifeq ($(COT_DESC_IN_DTB),1)
-    $(info CoT in device tree is an experimental feature)
+$(error "SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled")
 endif
 
 # If pointer authentication is used in the firmware, make sure that all the
@@ -751,24 +743,12 @@
 ifeq ($(CTX_INCLUDE_PAUTH_REGS),1)
     ifneq (${ARCH},aarch64)
         $(error CTX_INCLUDE_PAUTH_REGS requires AArch64)
-    else
-        $(info CTX_INCLUDE_PAUTH_REGS is an experimental feature)
     endif
 endif
 
-ifeq ($(ENABLE_PAUTH),1)
-    $(info Pointer Authentication is an experimental feature)
-endif
-
-ifeq ($(ENABLE_BTI),1)
-    $(info Branch Protection is an experimental feature)
-endif
-
 ifeq ($(CTX_INCLUDE_MTE_REGS),1)
     ifneq (${ARCH},aarch64)
         $(error CTX_INCLUDE_MTE_REGS requires AArch64)
-    else
-        $(info CTX_INCLUDE_MTE_REGS is an experimental feature)
     endif
 endif
 
@@ -778,8 +758,6 @@
 ifeq ($(MEASURED_BOOT),1)
     ifneq (${TRUSTED_BOARD_BOOT},1)
         $(error MEASURED_BOOT requires TRUSTED_BOARD_BOOT=1)
-    else
-        $(info MEASURED_BOOT is an experimental feature)
     endif
 endif
 
@@ -796,8 +774,6 @@
 ifneq (${DECRYPTION_SUPPORT},none)
     ifeq (${TRUSTED_BOARD_BOOT}, 0)
         $(error TRUSTED_BOARD_BOOT must be enabled for DECRYPTION_SUPPORT to be set)
-    else
-        $(info DECRYPTION_SUPPORT is an experimental feature)
     endif
 endif
 
@@ -955,6 +931,8 @@
         DYN_DISABLE_AUTH \
         EL3_EXCEPTION_HANDLING \
         ENABLE_AMU \
+        ENABLE_AMU_AUXILIARY_COUNTERS \
+        ENABLE_AMU_FCONF \
         AMU_RESTRICT_COUNTERS \
         ENABLE_ASSERTIONS \
         ENABLE_MPAM_FOR_LOWER_ELS \
@@ -1013,6 +991,8 @@
         ENABLE_SYS_REG_TRACE_FOR_NS \
         ENABLE_TRF_FOR_NS \
         ENABLE_FEAT_HCX \
+        ENABLE_MPMM \
+        ENABLE_MPMM_FCONF \
 )))
 
 $(eval $(call assert_numerics,\
@@ -1056,6 +1036,8 @@
         DECRYPTION_SUPPORT_${DECRYPTION_SUPPORT} \
         DISABLE_MTPMU \
         ENABLE_AMU \
+        ENABLE_AMU_AUXILIARY_COUNTERS \
+        ENABLE_AMU_FCONF \
         AMU_RESTRICT_COUNTERS \
         ENABLE_ASSERTIONS \
         ENABLE_BTI \
@@ -1119,6 +1101,8 @@
         ENABLE_SYS_REG_TRACE_FOR_NS \
         ENABLE_TRF_FOR_NS \
         ENABLE_FEAT_HCX \
+        ENABLE_MPMM \
+        ENABLE_MPMM_FCONF \
 )))
 
 ifeq (${SANITIZE_UB},trap)
@@ -1185,6 +1169,8 @@
 
 # Expand build macros for the different images
 ifeq (${NEED_BL1},yes)
+BL1_SOURCES := $(sort ${BL1_SOURCES})
+
 $(eval $(call MAKE_BL,bl1))
 endif
 
@@ -1193,6 +1179,8 @@
 FIP_BL2_ARGS := tb-fw
 endif
 
+BL2_SOURCES := $(sort ${BL2_SOURCES})
+
 $(if ${BL2}, $(eval $(call TOOL_ADD_IMG,bl2,--${FIP_BL2_ARGS})),\
 	$(eval $(call MAKE_BL,bl2,${FIP_BL2_ARGS})))
 endif
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 106d410..9baa0c2 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -22,6 +22,8 @@
   endif
 endif
 
+include lib/extensions/amu/amu.mk
+include lib/mpmm/mpmm.mk
 include lib/psci/psci_lib.mk
 
 BL31_SOURCES		+=	bl31/bl31_main.c				\
@@ -78,8 +80,11 @@
 endif
 
 ifeq (${ENABLE_AMU},1)
-BL31_SOURCES		+=	lib/extensions/amu/aarch64/amu.c		\
-				lib/extensions/amu/aarch64/amu_helpers.S
+BL31_SOURCES		+=	${AMU_SOURCES}
+endif
+
+ifeq (${ENABLE_MPMM},1)
+BL31_SOURCES		+=	${MPMM_SOURCES}
 endif
 
 ifeq (${ENABLE_SVE_FOR_NS},1)
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index 6339cf8..590b032 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -8,6 +8,7 @@
 	$(error SP_MIN is only supported on AArch32 platforms)
 endif
 
+include lib/extensions/amu/amu.mk
 include lib/psci/psci_lib.mk
 
 INCLUDES		+=	-Iinclude/bl32/sp_min
@@ -27,9 +28,8 @@
 BL32_SOURCES		+=	lib/pmf/pmf_main.c
 endif
 
-ifeq (${ENABLE_AMU}, 1)
-BL32_SOURCES		+=	lib/extensions/amu/aarch32/amu.c\
-				lib/extensions/amu/aarch32/amu_helpers.S
+ifeq (${ENABLE_AMU},1)
+BL32_SOURCES		+=	${AMU_SOURCES}
 endif
 
 ifeq (${WORKAROUND_CVE_2017_5715},1)
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
index 795c586..7d77f47 100644
--- a/bl32/tsp/aarch64/tsp_entrypoint.S
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -100,11 +100,27 @@
 	 * sections. This is done to safeguard against
 	 * possible corruption of this memory by dirty
 	 * cache lines in a system cache as a result of
-	 * use by an earlier boot loader stage.
+	 * use by an earlier boot loader stage. If PIE
+	 * is enabled however, RO sections including the
+	 * GOT may be modified during pie fixup.
+	 * Therefore, to be on the safe side, invalidate
+	 * the entire image region if PIE is enabled.
 	 * ---------------------------------------------
 	 */
-	adr	x0, __RW_START__
-	adr	x1, __RW_END__
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+	adrp	x0, __TEXT_START__
+	add	x0, x0, :lo12:__TEXT_START__
+#else
+	adrp	x0, __RO_START__
+	add	x0, x0, :lo12:__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
+	adrp	x0, __RW_START__
+	add	x0, x0, :lo12:__RW_START__
+#endif /* ENABLE_PIE */
+	adrp	x1, __RW_END__
+	add     x1, x1, :lo12:__RW_END__
 	sub	x1, x1, x0
 	bl	inv_dcache_range
 
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
index dd7a0fa..64e01ea 100644
--- a/common/fdt_wrappers.c
+++ b/common/fdt_wrappers.c
@@ -572,3 +572,47 @@
 	/* Translate the local device address recursively */
 	return fdtw_translate_address(dtb, local_bus_node, global_address);
 }
+
+/*
+ * For every CPU node (`/cpus/cpu@n`) in an FDT, execute a callback passing a
+ * pointer to the FDT and the offset of the CPU node. If the return value of the
+ * callback is negative, it is treated as an error and the loop is aborted. In
+ * this situation, the value of the callback is returned from the function.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+int fdtw_for_each_cpu(const void *dtb,
+		      int (*callback)(const void *dtb, int node, uintptr_t mpidr))
+{
+	int ret = 0;
+	int parent, node = 0;
+
+	parent = fdt_path_offset(dtb, "/cpus");
+	if (parent < 0) {
+		return parent;
+	}
+
+	fdt_for_each_subnode(node, dtb, parent) {
+		const char *name;
+		int len;
+
+		uintptr_t mpidr = 0U;
+
+		name = fdt_get_name(dtb, node, &len);
+		if (strncmp(name, "cpu@", 4) != 0) {
+			continue;
+		}
+
+		ret = fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
+		if (ret < 0) {
+			break;
+		}
+
+		ret = callback(dtb, node, mpidr);
+		if (ret < 0) {
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/common/fdt_wrappers.mk b/common/fdt_wrappers.mk
new file mode 100644
index 0000000..62b8c6e
--- /dev/null
+++ b/common/fdt_wrappers.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+FDT_WRAPPERS_SOURCES	:=	common/fdt_wrappers.c
diff --git a/docs/about/features.rst b/docs/about/features.rst
index f5fc1e0..4b7fbe5 100644
--- a/docs/about/features.rst
+++ b/docs/about/features.rst
@@ -74,7 +74,7 @@
    loading of a hardware configuration (for example, a kernel device tree)
    as part of the FIP, to be passed through the firmware stages.
    This feature is now incorporated inside the firmware configuration framework
-   (fconf), which is still flagged as experimental.
+   (fconf).
 
 -  Support for alternative boot flows, for example to support platforms where
    the EL3 Runtime Software is loaded using other firmware or a separate
@@ -94,9 +94,7 @@
 -  Support for ARMv8.3 pointer authentication in the normal and secure worlds.
    The use of pointer authentication in the normal world is enabled whenever
    architectural support is available, without the need for additional build
-   flags. Use of pointer authentication in the secure world remains an
-   experimental configuration at this time and requires the
-   ``BRANCH_PROTECTION`` option to be set to non-zero.
+   flags.
 
 -  Position-Independent Executable (PIE) support. Currently for BL2, BL31, and
    TSP, with further support to be added in a future release.
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 7db81fc..337dde6 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -217,6 +217,8 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
 :|G|: `AlexeiFedorov`_
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
 :|F|: lib/extensions/amu/
 
 Memory Partitioning And Monitoring (MPAM) extensions
@@ -326,6 +328,13 @@
 :|F|: drivers/scmi-msg
 :|F|: include/drivers/scmi\*
 
+Max Power Mitigation Mechanism (MPMM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: include/lib/mpmm/
+:|F|: lib/mpmm/
+
 Platform Ports
 ~~~~~~~~~~~~~~
 
diff --git a/docs/components/activity-monitors.rst b/docs/components/activity-monitors.rst
new file mode 100644
index 0000000..dd45c43
--- /dev/null
+++ b/docs/components/activity-monitors.rst
@@ -0,0 +1,34 @@
+Activity Monitors
+=================
+
+FEAT_AMUv1 of the Armv8-A architecture introduces the Activity Monitors
+extension. This extension describes the architecture for the Activity Monitor
+Unit (|AMU|), an optional non-invasive component for monitoring core events
+through a set of 64-bit counters.
+
+When the ``ENABLE_AMU=1`` build option is provided, Trusted Firmware-A sets up
+the |AMU| prior to its exit from EL3, and will save and restore architected
+|AMU| counters as necessary upon suspend and resume.
+
+.. _Activity Monitor Auxiliary Counters:
+
+Auxiliary counters
+------------------
+
+FEAT_AMUv1 describes a set of implementation-defined auxiliary counters (also
+known as group 1 counters), controlled by the ``ENABLE_AMU_AUXILIARY_COUNTERS``
+build option.
+
+As a security precaution, Trusted Firmware-A does not enable these by default.
+Instead, platforms may configure their auxiliary counters through one of two
+possible mechanisms:
+
+- |FCONF|, controlled by the ``ENABLE_AMU_FCONF`` build option.
+- A platform implementation of the ``plat_amu_topology`` function (the default).
+
+See :ref:`Activity Monitor Unit (AMU) Bindings` for documentation on the |FCONF|
+device tree bindings.
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
diff --git a/docs/components/fconf/amu-bindings.rst b/docs/components/fconf/amu-bindings.rst
new file mode 100644
index 0000000..047f75e
--- /dev/null
+++ b/docs/components/fconf/amu-bindings.rst
@@ -0,0 +1,142 @@
+Activity Monitor Unit (AMU) Bindings
+====================================
+
+To support platform-defined Activity Monitor Unit (|AMU|) auxiliary counters
+through FCONF, the ``HW_CONFIG`` device tree accepts several |AMU|-specific
+nodes and properties.
+
+Bindings
+^^^^^^^^
+
+.. contents::
+    :local:
+
+``/cpus/cpus/cpu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+The ``cpu`` node has been augmented to support a handle to an associated |AMU|
+view, which should describe the counters offered by the core.
+
++---------------+-------+---------------+-------------------------------------+
+| Property name | Usage | Value type    | Description                         |
++===============+=======+===============+=====================================+
+| ``amu``       | O     | ``<phandle>`` | If present, indicates that an |AMU| |
+|               |       |               | is available and its counters are   |
+|               |       |               | described by the node provided.     |
++---------------+-------+---------------+-------------------------------------+
+
+``/cpus/amus`` node properties
+""""""""""""""""""""""""""""""
+
+The ``amus`` node describes the |AMUs| implemented by the cores in the system.
+This node does not have any properties.
+
+``/cpus/amus/amu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+An ``amu`` node describes the layout and meaning of the auxiliary counter
+registers of one or more |AMUs|, and may be shared by multiple cores.
+
++--------------------+-------+------------+------------------------------------+
+| Property name      | Usage | Value type | Description                        |
++====================+=======+============+====================================+
+| ``#address-cells`` | R     | ``<u32>``  | Value shall be 1. Specifies that   |
+|                    |       |            | the ``reg`` property array of      |
+|                    |       |            | children of this node uses a       |
+|                    |       |            | single cell.                       |
++--------------------+-------+------------+------------------------------------+
+| ``#size-cells``    | R     | ``<u32>``  | Value shall be 0. Specifies that   |
+|                    |       |            | no size is required in the ``reg`` |
+|                    |       |            | property in children of this node. |
++--------------------+-------+------------+------------------------------------+
+
+``/cpus/amus/amu*/counter*`` node properties
+""""""""""""""""""""""""""""""""""""""""""""
+
+A ``counter`` node describes an auxiliary counter belonging to the parent |AMU|
+view.
+
++-------------------+-------+-------------+------------------------------------+
+| Property name     | Usage | Value type  | Description                        |
++===================+=======+=============+====================================+
+| ``reg``           | R     | array       | Represents the counter register    |
+|                   |       |             | index, and must be a single cell.  |
++-------------------+-------+-------------+------------------------------------+
+| ``enable-at-el3`` | O     | ``<empty>`` | The presence of this property      |
+|                   |       |             | indicates that this counter should |
+|                   |       |             | be enabled prior to EL3 exit.      |
++-------------------+-------+-------------+------------------------------------+
+
+Example
+^^^^^^^
+
+An example system offering four cores made up of two clusters, where the cores
+of each cluster share different |AMUs|, may use something like the following:
+
+.. code-block::
+
+    cpus {
+        #address-cells = <2>;
+        #size-cells = <0>;
+
+        amus {
+            amu0: amu-0 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                counterX: counter@0 {
+                    reg = <0>;
+
+                    enable-at-el3;
+                };
+
+                counterY: counter@1 {
+                    reg = <1>;
+
+                    enable-at-el3;
+                };
+            };
+
+            amu1: amu-1 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                counterZ: counter@0 {
+                    reg = <0>;
+
+                    enable-at-el3;
+                };
+            };
+        };
+
+        cpu0@00000 {
+            ...
+
+            amu = <&amu0>;
+        };
+
+        cpu1@00100 {
+            ...
+
+            amu = <&amu0>;
+        };
+
+        cpu2@10000 {
+            ...
+
+            amu = <&amu1>;
+        };
+
+        cpu3@10100 {
+            ...
+
+            amu = <&amu1>;
+        };
+    }
+
+In this situation, ``cpu0`` and ``cpu1`` (the two cores in the first cluster),
+share the view of their AMUs defined by ``amu0``. Likewise, ``cpu2`` and
+``cpu3`` (the two cores in the second cluster), share the view of their |AMUs|
+defined by ``amu1``. This will cause ``counterX`` and ``counterY`` to be enabled
+for both ``cpu0`` and ``cpu1``, and ``counterZ`` to be enabled for both ``cpu2``
+and ``cpu3``.
diff --git a/docs/components/fconf/index.rst b/docs/components/fconf/index.rst
index 9020633..029f324 100644
--- a/docs/components/fconf/index.rst
+++ b/docs/components/fconf/index.rst
@@ -145,3 +145,5 @@
   :maxdepth: 1
 
   fconf_properties
+  amu-bindings
+  mpmm-bindings
diff --git a/docs/components/fconf/mpmm-bindings.rst b/docs/components/fconf/mpmm-bindings.rst
new file mode 100644
index 0000000..d3cc857
--- /dev/null
+++ b/docs/components/fconf/mpmm-bindings.rst
@@ -0,0 +1,48 @@
+Maximum Power Mitigation Mechanism (MPMM) Bindings
+==================================================
+
+|MPMM| support cannot be determined at runtime by the firmware. Instead, these
+DTB bindings allow the platform to communicate per-core support for |MPMM| via
+the ``HW_CONFIG`` device tree blob.
+
+Bindings
+^^^^^^^^
+
+.. contents::
+    :local:
+
+``/cpus/cpus/cpu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+The ``cpu`` node has been augmented to allow the platform to indicate support
+for |MPMM| on a given core.
+
++-------------------+-------+-------------+------------------------------------+
+| Property name     | Usage | Value type  | Description                        |
++===================+=======+=============+====================================+
+| ``supports-mpmm`` | O     | ``<empty>`` | If present, indicates that |MPMM|  |
+|                   |       |             | is available on this core.         |
++-------------------+-------+-------------+------------------------------------+
+
+Example
+^^^^^^^
+
+An example system offering two cores, one with support for |MPMM| and one
+without, can be described as follows:
+
+.. code-block::
+
+    cpus {
+        #address-cells = <2>;
+        #size-cells = <0>;
+
+        cpu0@00000 {
+            ...
+
+            supports-mpmm;
+        };
+
+        cpu1@00100 {
+            ...
+        };
+    }
diff --git a/docs/components/index.rst b/docs/components/index.rst
index f349d8d..754526d 100644
--- a/docs/components/index.rst
+++ b/docs/components/index.rst
@@ -7,12 +7,14 @@
    :numbered:
 
    spd/index
+   activity-monitors
    arm-sip-service
    debugfs-design
    exception-handling
    fconf/index
    firmware-update
    measured_boot/index
+   mpmm
    platform-interrupt-controller-API
    ras
    romlib-design
diff --git a/docs/components/mpmm.rst b/docs/components/mpmm.rst
new file mode 100644
index 0000000..1b1c6d8
--- /dev/null
+++ b/docs/components/mpmm.rst
@@ -0,0 +1,30 @@
+Maximum Power Mitigation Mechanism (MPMM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+|MPMM| is an optional microarchitectural power management mechanism supported by
+some Arm Armv9-A cores, beginning with the Cortex-X2, Cortex-A710 and
+Cortex-A510 cores. This mechanism detects and limits high-activity events to
+assist in |SoC| processor power domain dynamic power budgeting and limit the
+triggering of whole-rail (i.e. clock chopping) responses to overcurrent
+conditions.
+
+|MPMM| is enabled on a per-core basis by the EL3 runtime firmware. The presence
+of |MPMM| cannot be determined at runtime by the firmware, and therefore the
+platform must expose this information through one of two possible mechanisms:
+
+- |FCONF|, controlled by the ``ENABLE_MPMM_FCONF`` build option.
+- A platform implementation of the ``plat_mpmm_topology`` function (the
+  default).
+
+See :ref:`Maximum Power Mitigation Mechanism (MPMM) Bindings` for documentation
+on the |FCONF| device tree bindings.
+
+.. warning::
+
+    |MPMM| exposes gear metrics through the auxiliary |AMU| counters. An
+    external power controller can use these metrics to budget SoC power by
+    limiting the number of cores that can execute higher-activity workloads or
+    switching to a different DVFS operating point. When this is the case, the
+    |AMU| counters that make up the |MPMM| gears must be enabled by the EL3
+    runtime firmware - please see :ref:`Activity Monitor Auxiliary Counters` for
+    documentation on enabling auxiliary |AMU| counters.
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index c12e73f..ef500ff 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -2616,8 +2616,6 @@
    ``CTX_INCLUDE_PAUTH_REGS`` to 1. This enables pointer authentication in BL1,
    BL2, BL31, and the TSP if it is used.
 
-   These options are experimental features.
-
    Note that Pointer Authentication is enabled for Non-secure world irrespective
    of the value of these build flags if the CPU supports it.
 
@@ -2629,8 +2627,7 @@
 ~~~~~~~~~
 
 -  Branch Target Identification feature is selected by ``BRANCH_PROTECTION``
-   option set to 1. This option defaults to 0 and this is an experimental
-   feature.
+   option set to 1. This option defaults to 0.
 
 -  Memory Tagging Extension feature is unconditionally enabled for both worlds
    (at EL0 and S-EL0) if it is only supported at EL0. If instead it is
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
index 96cf24c..46177d7 100644
--- a/docs/design/trusted-board-boot.rst
+++ b/docs/design/trusted-board-boot.rst
@@ -239,9 +239,6 @@
 R060_TBBR_FUNCTION as specified in the `Trusted Board Boot Requirements (TBBR)`_
 document.
 
-Note that due to security considerations and complexity of this feature, it is
-marked as experimental.
-
 Firmware Encryption Tool
 ------------------------
 
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 1259881..04e3c0b 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -120,7 +120,7 @@
    |   4   |     bti      |   N   |  Y  |
    +-------+--------------+-------+-----+
 
-   This option defaults to 0 and this is an experimental feature.
+   This option defaults to 0.
    Note that Pointer Authentication is enabled for Non-secure world
    irrespective of the value of this option if the CPU supports it.
 
@@ -181,7 +181,7 @@
 -  ``CTX_INCLUDE_PAUTH_REGS``: Boolean option that, when set to 1, enables
    Pointer Authentication for Secure world. This will cause the ARMv8.3-PAuth
    registers to be included when saving and restoring the CPU context as
-   part of world switch. Default value is 0 and this is an experimental feature.
+   part of world switch. Default value is 0.
    Note that Pointer Authentication is enabled for Non-secure world irrespective
    of the value of this flag if the CPU supports it.
 
@@ -192,7 +192,7 @@
    authenticated decryption algorithm to be used to decrypt firmware/s during
    boot. It accepts 2 values: ``aes_gcm`` and ``none``. The default value of
    this flag is ``none`` to disable firmware decryption which is an optional
-   feature as per TBBR. Also, it is an experimental feature.
+   feature as per TBBR.
 
 -  ``DISABLE_BIN_GENERATION``: Boolean option to disable the generation
    of the binary image. If set to 1, then only the ELF image is built.
@@ -220,6 +220,14 @@
    v8.2 implementations also implement an AMU and this option can be used to
    enable this feature on those systems as well. Default is 0.
 
+-  ``ENABLE_AMU_AUXILIARY_COUNTERS``: Enables support for AMU auxiliary counters
+   (also known as group 1 counters). These are implementation-defined counters,
+   and as such require additional platform configuration. Default is 0.
+
+-  ``ENABLE_AMU_FCONF``: Enables configuration of the AMU through FCONF, which
+   allows platforms with auxiliary counters to describe them via the
+   ``HW_CONFIG`` device tree blob. Default is 0.
+
 -  ``ENABLE_ASSERTIONS``: This option controls whether or not calls to ``assert()``
    are compiled out. For debug builds, this option defaults to 1, and calls to
    ``assert()`` are left in place. For release builds, this option defaults to 0
@@ -257,6 +265,16 @@
    partitioning in EL3, however. Platform initialisation code should configure
    and use partitions in EL3 as required. This option defaults to ``0``.
 
+-  ``ENABLE_MPMM``: Boolean option to enable support for the Maximum Power
+   Mitigation Mechanism supported by certain Arm cores, which allows the SoC
+   firmware to detect and limit high activity events to assist in SoC processor
+   power domain dynamic power budgeting and limit the triggering of whole-rail
+   (i.e. clock chopping) responses to overcurrent conditions. Defaults to ``0``.
+
+-  ``ENABLE_MPMM_FCONF``: Enables configuration of MPMM through FCONF, which
+   allows platforms with cores supporting MPMM to describe them via the
+   ``HW_CONFIG`` device tree blob. Default is 0.
+
 -  ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE)
    support within generic code in TF-A. This option is currently only supported
    in BL2_AT_EL3, BL31, and BL32 (TSP) for AARCH64 binaries, and in BL32
@@ -312,20 +330,18 @@
    component of the option ``-fstack-protector-$ENABLE_STACK_PROTECTOR``.
 
 -  ``ENCRYPT_BL31``: Binary flag to enable encryption of BL31 firmware. This
-   flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
-   experimental.
+   flag depends on ``DECRYPTION_SUPPORT`` build flag.
 
 -  ``ENCRYPT_BL32``: Binary flag to enable encryption of Secure BL32 payload.
-   This flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
-   experimental.
+   This flag depends on ``DECRYPTION_SUPPORT`` build flag.
 
 -  ``ENC_KEY``: A 32-byte (256-bit) symmetric key in hex string format. It could
    either be SSK or BSSK depending on ``FW_ENC_STATUS`` flag. This value depends
-   on ``DECRYPTION_SUPPORT`` build flag which is marked as experimental.
+   on ``DECRYPTION_SUPPORT`` build flag.
 
 -  ``ENC_NONCE``: A 12-byte (96-bit) encryption nonce or Initialization Vector
    (IV) in hex string format. This value depends on ``DECRYPTION_SUPPORT``
-   build flag which is marked as experimental.
+   build flag.
 
 -  ``ERROR_DEPRECATED``: This option decides whether to treat the usage of
    deprecated platform APIs, helper functions or drivers within Trusted
@@ -364,8 +380,7 @@
      1: Encryption is done with Binding Secret Symmetric Key (BSSK) which is
         unique per device.
 
-   This flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
-   experimental.
+   This flag depends on ``DECRYPTION_SUPPORT`` build flag.
 
 -  ``GENERATE_COT``: Boolean flag used to build and execute the ``cert_create``
    tool to create certificates as per the Chain of Trust described in
@@ -484,8 +499,7 @@
    in order to provide trust that the code taking the measurements and recording
    them has not been tampered with.
 
-   This option defaults to 0 and is an experimental feature in the stage of
-   development.
+   This option defaults to 0.
 
 -  ``NON_TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It
    specifies the file that contains the Non-Trusted World private key in PEM
@@ -695,26 +709,25 @@
 -  ``ARM_IO_IN_DTB``: This flag determines whether to use IO based on the
    firmware configuration framework. This will move the io_policies into a
    configuration device tree, instead of static structure in the code base.
-   This is currently an experimental feature.
 
 -  ``COT_DESC_IN_DTB``: This flag determines whether to create COT descriptors
    at runtime using fconf. If this flag is enabled, COT descriptors are
    statically captured in tb_fw_config file in the form of device tree nodes
    and properties. Currently, COT descriptors used by BL2 are moved to the
    device tree and COT descriptors used by BL1 are retained in the code
-   base statically. This is currently an experimental feature.
+   base statically.
 
 -  ``SDEI_IN_FCONF``: This flag determines whether to configure SDEI setup in
    runtime using firmware configuration framework. The platform specific SDEI
    shared and private events configuration is retrieved from device tree rather
-   than static C structures at compile time. This is currently an experimental
-   feature and is only supported if SDEI_SUPPORT build flag is enabled.
+   than static C structures at compile time. This is only supported if
+   SDEI_SUPPORT build flag is enabled.
 
 -  ``SEC_INT_DESC_IN_FCONF``: This flag determines whether to configure Group 0
    and Group1 secure interrupts using the firmware configuration framework. The
    platform specific secure interrupt property descriptor is retrieved from
    device tree in runtime rather than depending on static C structure at compile
-   time. This is currently an experimental feature.
+   time.
 
 -  ``USE_ROMLIB``: This flag determines whether library at ROM will be used.
    This feature creates a library of functions to be placed in ROM and thus
@@ -918,4 +931,3 @@
 
 .. _DEN0115: https://developer.arm.com/docs/den0115/latest
 .. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
-
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index 6569a47..92ff39f 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -562,15 +562,6 @@
    doesn't print anything to the console. If ``PLAT_LOG_LEVEL_ASSERT`` isn't
    defined, it defaults to ``LOG_LEVEL``.
 
-If the platform port uses the Activity Monitor Unit, the following constant
-may be defined:
-
--  **PLAT_AMU_GROUP1_COUNTERS_MASK**
-   This mask reflects the set of group counters that should be enabled.  The
-   maximum number of group 1 counters supported by AMUv1 is 16 so the mask
-   can be at most 0xffff. If the platform does not define this mask, no group 1
-   counters are enabled.
-
 File : plat_macros.S [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -891,8 +882,7 @@
 
 On success the function should return 0 and a negative error code otherwise.
 
-Note that this API depends on ``DECRYPTION_SUPPORT`` build flag which is
-marked as experimental.
+Note that this API depends on ``DECRYPTION_SUPPORT`` build flag.
 
 Function : plat_fwu_set_images_source() [when PSA_FWU_SUPPORT == 1]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
index 24ac830..af15146 100644
--- a/docs/global_substitutions.txt
+++ b/docs/global_substitutions.txt
@@ -1,5 +1,7 @@
 .. |AArch32| replace:: :term:`AArch32`
 .. |AArch64| replace:: :term:`AArch64`
+.. |AMU| replace:: :term:`AMU`
+.. |AMUs| replace:: :term:`AMUs <AMU>`
 .. |API| replace:: :term:`API`
 .. |BTI| replace:: :term:`BTI`
 .. |CoT| replace:: :term:`CoT`
@@ -23,6 +25,7 @@
 .. |Linaro| replace:: :term:`Linaro`
 .. |MMU| replace:: :term:`MMU`
 .. |MPAM| replace:: :term:`MPAM`
+.. |MPMM| replace:: :term:`MPMM`
 .. |MPIDR| replace:: :term:`MPIDR`
 .. |MTE| replace:: :term:`MTE`
 .. |OEN| replace:: :term:`OEN`
diff --git a/docs/glossary.rst b/docs/glossary.rst
index f4912f5..aeeb133 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -15,6 +15,10 @@
    AArch64
       64-bit execution state of the ARMv8 ISA
 
+   AMU
+      Activity Monitor Unit, a hardware monitoring unit introduced by FEAT_AMUv1
+      that exposes CPU core runtime metrics as a set of counter registers.
+
    API
       Application Programming Interface
 
@@ -88,6 +92,10 @@
    MPAM
       Memory Partitioning And Monitoring. An optional Armv8.4 extension.
 
+   MPMM
+     Maximum Power Mitigation Mechanism, an optional power management mechanism
+     supported by some Arm Armv9-A cores.
+
    MPIDR
       Multiprocessor Affinity Register
 
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
index 17f7a86..af302c6 100644
--- a/docs/plat/stm32mp1.rst
+++ b/docs/plat/stm32mp1.rst
@@ -181,6 +181,7 @@
 .. code:: bash
 
     make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+        AARCH32_SP=optee \
         DTB_FILE_NAME=stm32mp157c-ev1.dtb \
         BL33=<u-boot_directory>/u-boot-nodtb.bin \
         BL33_CFG=<u-boot_directory>/u-boot.dtb \
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
index aeb7eda..5de2604 100644
--- a/drivers/arm/css/scp/css_pm_scmi.c
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -357,7 +357,7 @@
 	unsigned int composite_id, idx;
 
 	for (idx = 0; idx < PLAT_ARM_SCMI_CHANNEL_COUNT; idx++) {
-		INFO("Initializing driver on Channel %d\n", idx);
+		INFO("Initializing SCMI driver on channel %d\n", idx);
 
 		scmi_channels[idx].info = plat_css_get_scmi_info(idx);
 		scmi_channels[idx].lock = ARM_SCMI_LOCK_GET_INSTANCE;
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index fd3d8c2..5f42ad9 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -18,8 +18,6 @@
 #include "../common/gic_common_private.h"
 #include "gic600_multichip_private.h"
 
-#warning "GIC-600 Multichip driver is currently experimental and the API may change in future."
-
 /*******************************************************************************
  * GIC-600 multichip operation related helper functions
  ******************************************************************************/
@@ -212,8 +210,6 @@
 
 	gic600_multichip_validate_data(multichip_data);
 
-	INFO("GIC-600 Multichip driver is experimental\n");
-
 	/*
 	 * Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
 	 * that GIC-600 Multichip configuration is done first.
diff --git a/drivers/auth/cryptocell/713/cryptocell_crypto.c b/drivers/auth/cryptocell/713/cryptocell_crypto.c
index 5f390a2..077317e 100644
--- a/drivers/auth/cryptocell/713/cryptocell_crypto.c
+++ b/drivers/auth/cryptocell/713/cryptocell_crypto.c
@@ -13,6 +13,7 @@
 #include <drivers/auth/crypto_mod.h>
 
 #include <mbedtls/oid.h>
+#include <mbedtls/x509.h>
 
 #define LIB_NAME		"CryptoCell 713 SBROM"
 #define RSA_SALT_LEN		32
diff --git a/drivers/nxp/sfp/fuse_prov.c b/drivers/nxp/sfp/fuse_prov.c
index 4d30f5f..165474f 100644
--- a/drivers/nxp/sfp/fuse_prov.c
+++ b/drivers/nxp/sfp/fuse_prov.c
@@ -326,7 +326,7 @@
 		      struct sfp_ccsr_regs_t *sfp_ccsr_regs)
 {
 	int ret;
-	uint32_t mask;
+	uint32_t mask = 0;
 
 #ifdef NXP_SFP_VER_3_4
 	if (((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) {
diff --git a/drivers/renesas/common/io/io_rcar.c b/drivers/renesas/common/io/io_rcar.c
index 17d7aaa..45ef386 100644
--- a/drivers/renesas/common/io/io_rcar.c
+++ b/drivers/renesas/common/io/io_rcar.c
@@ -380,7 +380,7 @@
 
 static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
 {
-	uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {0UL};
+	static uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {0UL};
 	uintptr_t handle;
 	ssize_t offset;
 	uint32_t i;
@@ -423,15 +423,17 @@
 		WARN("Firmware Image Package header failed to seek\n");
 		goto error;
 	}
-#if RCAR_BL2_DCACHE == 1
-	inv_dcache_range((uint64_t) header, sizeof(header));
-#endif
+
 	rc = io_read(handle, (uintptr_t) &header, sizeof(header), &cnt);
 	if (rc != IO_SUCCESS) {
 		WARN("Firmware Image Package header failed to read\n");
 		goto error;
 	}
 
+#if RCAR_BL2_DCACHE == 1
+	inv_dcache_range((uint64_t) header, sizeof(header));
+#endif
+
 	rcar_image_number = header[0];
 	for (i = 0; i < rcar_image_number + 2; i++) {
 		rcar_image_header[i] = header[i * 2 + 1];
@@ -440,6 +442,7 @@
 
 	if (rcar_image_number == 0 || rcar_image_number > RCAR_MAX_BL3X_IMAGE) {
 		WARN("Firmware Image Package header check failed.\n");
+		rc = IO_FAIL;
 		goto error;
 	}
 
@@ -448,10 +451,7 @@
 		WARN("Firmware Image Package header failed to seek cert\n");
 		goto error;
 	}
-#if RCAR_BL2_DCACHE == 1
-	inv_dcache_range(RCAR_SDRAM_certESS,
-			 RCAR_CERT_SIZE * (2 + rcar_image_number));
-#endif
+
 	rc = io_read(handle, RCAR_SDRAM_certESS,
 		     RCAR_CERT_SIZE * (2 + rcar_image_number), &cnt);
 	if (rc != IO_SUCCESS) {
@@ -459,6 +459,11 @@
 		goto error;
 	}
 
+#if RCAR_BL2_DCACHE == 1
+	inv_dcache_range(RCAR_SDRAM_certESS,
+			 RCAR_CERT_SIZE * (2 + rcar_image_number));
+#endif
+
 	rcar_cert_load = RCAR_CERT_LOAD;
 error:
 
diff --git a/drivers/renesas/common/pwrc/pwrc.c b/drivers/renesas/common/pwrc/pwrc.c
index 4ebf049..4e175eb 100644
--- a/drivers/renesas/common/pwrc/pwrc.c
+++ b/drivers/renesas/common/pwrc/pwrc.c
@@ -776,14 +776,14 @@
 	memcpy((void *)sram.base, code.base, code.len);
 	flush_dcache_range((uint64_t) sram.base, code.len);
 
+	attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
+	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
+	assert(ret == 0);
+
 	/* Invalidate instruction cache */
 	plat_invalidate_icache();
 	dsb();
 	isb();
-
-	attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
-	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
-	assert(ret == 0);
 }
 
 uint32_t rcar_pwrc_get_cluster(void)
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 6dbf372..ae42e32 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -34,6 +34,9 @@
 {
 	unsigned int data;
 
+	if (base == 0 || cmd == NULL)
+		return -EINVAL;
+
 	data = mmio_read_32(base + HCS);
 	if ((data & HCS_UCRDY) == 0)
 		return -EBUSY;
@@ -54,9 +57,13 @@
 {
 	uintptr_t base;
 	unsigned int data;
-	int retries;
+	int result, retries;
+	uic_cmd_t cmd;
 
-	assert((ufs_params.reg_base != 0) && (val != NULL));
+	assert(ufs_params.reg_base != 0);
+
+	if (val == NULL)
+		return -EINVAL;
 
 	base = ufs_params.reg_base;
 	for (retries = 0; retries < 100; retries++) {
@@ -68,19 +75,20 @@
 	if (retries >= 100)
 		return -EBUSY;
 
-	mmio_write_32(base + IS, ~0);
-	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
-	mmio_write_32(base + UCMDARG2, 0);
-	mmio_write_32(base + UCMDARG3, 0);
-	mmio_write_32(base + UICCMD, DME_GET);
-	do {
+	cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+	cmd.arg2 = 0;
+	cmd.arg3 = 0;
+	cmd.op = DME_GET;
+	for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+		result = ufshc_send_uic_cmd(base, &cmd);
+		if (result == 0)
+			break;
 		data = mmio_read_32(base + IS);
 		if (data & UFS_INT_UE)
 			return -EINVAL;
-	} while ((data & UFS_INT_UCCS) == 0);
-	mmio_write_32(base + IS, UFS_INT_UCCS);
-	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
-	assert(data == 0);
+	}
+	if (retries >= UFS_UIC_COMMAND_RETRIES)
+		return -EIO;
 
 	*val = mmio_read_32(base + UCMDARG3);
 	return 0;
@@ -90,58 +98,101 @@
 {
 	uintptr_t base;
 	unsigned int data;
+	int result, retries;
+	uic_cmd_t cmd;
 
 	assert((ufs_params.reg_base != 0));
 
 	base = ufs_params.reg_base;
-	data = mmio_read_32(base + HCS);
-	if ((data & HCS_UCRDY) == 0)
-		return -EBUSY;
-	mmio_write_32(base + IS, ~0);
-	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
-	mmio_write_32(base + UCMDARG2, 0);
-	mmio_write_32(base + UCMDARG3, val);
-	mmio_write_32(base + UICCMD, DME_SET);
-	do {
+	cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+	cmd.arg2 = 0;
+	cmd.arg3 = val;
+	cmd.op = DME_SET;
+
+	for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+		result = ufshc_send_uic_cmd(base, &cmd);
+		if (result == 0)
+			break;
 		data = mmio_read_32(base + IS);
 		if (data & UFS_INT_UE)
 			return -EINVAL;
-	} while ((data & UFS_INT_UCCS) == 0);
-	mmio_write_32(base + IS, UFS_INT_UCCS);
-	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
-	assert(data == 0);
+	}
+	if (retries >= UFS_UIC_COMMAND_RETRIES)
+		return -EIO;
+
 	return 0;
 }
 
-static void ufshc_reset(uintptr_t base)
+static int ufshc_hce_enable(uintptr_t base)
 {
 	unsigned int data;
+	int retries;
 
 	/* Enable Host Controller */
 	mmio_write_32(base + HCE, HCE_ENABLE);
+
 	/* Wait until basic initialization sequence completed */
-	do {
+	for (retries = 0; retries < HCE_ENABLE_INNER_RETRIES; ++retries) {
 		data = mmio_read_32(base + HCE);
-	} while ((data & HCE_ENABLE) == 0);
+		if (data & HCE_ENABLE) {
+			break;
+		}
+		udelay(HCE_ENABLE_TIMEOUT_US);
+	}
+	if (retries >= HCE_ENABLE_INNER_RETRIES) {
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int ufshc_reset(uintptr_t base)
+{
+	unsigned int data;
+	int retries, result;
+
+	for (retries = 0; retries < HCE_ENABLE_OUTER_RETRIES; ++retries) {
+		result = ufshc_hce_enable(base);
+		if (result == 0) {
+			break;
+		}
+	}
+	if (retries >= HCE_ENABLE_OUTER_RETRIES) {
+		return -EIO;
+	}
 
 	/* Enable Interrupts */
 	data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
 	       UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
 	mmio_write_32(base + IE, data);
+
+	return 0;
+}
+
+static int ufshc_dme_link_startup(uintptr_t base)
+{
+	uic_cmd_t cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op = DME_LINKSTARTUP;
+	return ufshc_send_uic_cmd(base, &cmd);
 }
 
 static int ufshc_link_startup(uintptr_t base)
 {
-	uic_cmd_t cmd;
 	int data, result;
 	int retries;
 
-	for (retries = 10; retries > 0; retries--) {
-		memset(&cmd, 0, sizeof(cmd));
-		cmd.op = DME_LINKSTARTUP;
-		result = ufshc_send_uic_cmd(base, &cmd);
-		if (result != 0)
+	for (retries = DME_LINKSTARTUP_RETRIES; retries > 0; retries--) {
+		result = ufshc_dme_link_startup(base);
+		if (result != 0) {
+			/* Reset controller before trying again */
+			result = ufshc_reset(base);
+			if (result != 0) {
+				return result;
+			}
 			continue;
+		}
 		while ((mmio_read_32(base + HCS) & HCS_DP) == 0)
 			;
 		data = mmio_read_32(base + IS);
@@ -772,7 +823,8 @@
 		assert((ops != NULL) && (ops->phy_init != NULL) &&
 		       (ops->phy_set_pwr_mode != NULL));
 
-		ufshc_reset(ufs_params.reg_base);
+		result = ufshc_reset(ufs_params.reg_base);
+		assert(result == 0);
 		ops->phy_init(&ufs_params);
 		result = ufshc_link_startup(ufs_params.reg_base);
 		assert(result == 0);
diff --git a/fdts/stm32mp15-bl2.dtsi b/fdts/stm32mp15-bl2.dtsi
index da95b25..074414b 100644
--- a/fdts/stm32mp15-bl2.dtsi
+++ b/fdts/stm32mp15-bl2.dtsi
@@ -4,6 +4,12 @@
  */
 
 / {
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+	aliases {
+		/delete-property/ mmc0;
+	};
+#endif
+
 	cpus {
 		/delete-node/ cpu@1;
 	};
@@ -13,9 +19,25 @@
 	soc {
 		/delete-node/ timer@40006000;
 		/delete-node/ timer@44006000;
+#if !STM32MP_USB_PROGRAMMER
+		/delete-node/ usb-otg@49000000;
+#endif
 		/delete-node/ pwr_mcu@50001014;
 		/delete-node/ cryp@54001000;
 		/delete-node/ rng@54003000;
+#if !STM32MP_RAW_NAND
+		/delete-node/ memory-controller@58002000;
+#endif
+#if !STM32MP_SPI_NAND && !STM32MP_SPI_NOR
+		/delete-node/ spi@58003000;
+#endif
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+		/delete-node/ mmc@58005000;
+		/delete-node/ mmc@58007000;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+		/delete-node/ usbphyc@5a006000;
+#endif
 		/delete-node/ spi@5c001000;
 		/delete-node/ rtc@5c004000;
 		/delete-node/ etzpc@5c007000;
@@ -24,7 +46,25 @@
 		/delete-node/ tamp@5c00a000;
 
 		pin-controller@50002000 {
-			/delete-node/ rtc-out2-rmp-pins-0;
+#if !STM32MP_RAW_NAND
+			/delete-node/ fmc-0;
+#endif
+#if !STM32MP_SPI_NAND && !STM32MP_SPI_NOR
+			/delete-node/ qspi-clk-0;
+			/delete-node/ qspi-bk1-0;
+			/delete-node/ qspi-bk2-0;
+#endif
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+			/delete-node/ sdmmc1-b4-0;
+			/delete-node/ sdmmc1-dir-0;
+			/delete-node/ sdmmc2-b4-0;
+			/delete-node/ sdmmc2-b4-1;
+			/delete-node/ sdmmc2-d47-0;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+			/delete-node/ usbotg_hs-0;
+			/delete-node/ usbotg-fs-dp-dm-0;
+#endif
 		};
 	};
 
diff --git a/fdts/stm32mp15-bl32.dtsi b/fdts/stm32mp15-bl32.dtsi
index f005d56..ca4bb3e 100644
--- a/fdts/stm32mp15-bl32.dtsi
+++ b/fdts/stm32mp15-bl32.dtsi
@@ -20,8 +20,8 @@
 		/delete-node/ hash@54002000;
 		/delete-node/ memory-controller@58002000;
 		/delete-node/ spi@58003000;
-		/delete-node/ sdmmc@58005000;
-		/delete-node/ sdmmc@58007000;
+		/delete-node/ mmc@58005000;
+		/delete-node/ mmc@58007000;
 		/delete-node/ usbphyc@5a006000;
 		/delete-node/ spi@5c001000;
 		/delete-node/ stgen@5c008000;
@@ -37,6 +37,8 @@
 			/delete-node/ sdmmc2-b4-0;
 			/delete-node/ sdmmc2-b4-1;
 			/delete-node/ sdmmc2-d47-0;
+			/delete-node/ sdmmc2-d47-1;
+			/delete-node/ sdmmc2-d47-3;
 			/delete-node/ usbotg_hs-0;
 			/delete-node/ usbotg-fs-dp-dm-0;
 		};
diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi
index 4825691..e5efd92 100644
--- a/fdts/stm32mp15-ddr.dtsi
+++ b/fdts/stm32mp15-ddr.dtsi
@@ -1,153 +1,127 @@
 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
 /*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved
  */
 
-/ {
-	soc {
-		ddr: ddr@5a003000{
+&ddr {
+	st,mem-name = DDR_MEM_NAME;
+	st,mem-speed = <DDR_MEM_SPEED>;
+	st,mem-size = <DDR_MEM_SIZE>;
 
-			compatible = "st,stm32mp1-ddr";
+	st,ctl-reg = <
+		DDR_MSTR
+		DDR_MRCTRL0
+		DDR_MRCTRL1
+		DDR_DERATEEN
+		DDR_DERATEINT
+		DDR_PWRCTL
+		DDR_PWRTMG
+		DDR_HWLPCTL
+		DDR_RFSHCTL0
+		DDR_RFSHCTL3
+		DDR_CRCPARCTL0
+		DDR_ZQCTL0
+		DDR_DFITMG0
+		DDR_DFITMG1
+		DDR_DFILPCFG0
+		DDR_DFIUPD0
+		DDR_DFIUPD1
+		DDR_DFIUPD2
+		DDR_DFIPHYMSTR
+		DDR_ODTMAP
+		DDR_DBG0
+		DDR_DBG1
+		DDR_DBGCMD
+		DDR_POISONCFG
+		DDR_PCCFG
+	>;
 
-			reg = <0x5A003000 0x550
-			       0x5A004000 0x234>;
+	st,ctl-timing = <
+		DDR_RFSHTMG
+		DDR_DRAMTMG0
+		DDR_DRAMTMG1
+		DDR_DRAMTMG2
+		DDR_DRAMTMG3
+		DDR_DRAMTMG4
+		DDR_DRAMTMG5
+		DDR_DRAMTMG6
+		DDR_DRAMTMG7
+		DDR_DRAMTMG8
+		DDR_DRAMTMG14
+		DDR_ODTCFG
+	>;
 
-			clocks = <&rcc AXIDCG>,
-				 <&rcc DDRC1>,
-				 <&rcc DDRC2>,
-				 <&rcc DDRPHYC>,
-				 <&rcc DDRCAPB>,
-				 <&rcc DDRPHYCAPB>;
+	st,ctl-map = <
+		DDR_ADDRMAP1
+		DDR_ADDRMAP2
+		DDR_ADDRMAP3
+		DDR_ADDRMAP4
+		DDR_ADDRMAP5
+		DDR_ADDRMAP6
+		DDR_ADDRMAP9
+		DDR_ADDRMAP10
+		DDR_ADDRMAP11
+	>;
 
-			clock-names = "axidcg",
-				      "ddrc1",
-				      "ddrc2",
-				      "ddrphyc",
-				      "ddrcapb",
-				      "ddrphycapb";
+	st,ctl-perf = <
+		DDR_SCHED
+		DDR_SCHED1
+		DDR_PERFHPR1
+		DDR_PERFLPR1
+		DDR_PERFWR1
+		DDR_PCFGR_0
+		DDR_PCFGW_0
+		DDR_PCFGQOS0_0
+		DDR_PCFGQOS1_0
+		DDR_PCFGWQOS0_0
+		DDR_PCFGWQOS1_0
+		DDR_PCFGR_1
+		DDR_PCFGW_1
+		DDR_PCFGQOS0_1
+		DDR_PCFGQOS1_1
+		DDR_PCFGWQOS0_1
+		DDR_PCFGWQOS1_1
+	>;
 
-			st,mem-name = DDR_MEM_NAME;
-			st,mem-speed = <DDR_MEM_SPEED>;
-			st,mem-size = <DDR_MEM_SIZE>;
+	st,phy-reg = <
+		DDR_PGCR
+		DDR_ACIOCR
+		DDR_DXCCR
+		DDR_DSGCR
+		DDR_DCR
+		DDR_ODTCR
+		DDR_ZQ0CR1
+		DDR_DX0GCR
+		DDR_DX1GCR
+		DDR_DX2GCR
+		DDR_DX3GCR
+	>;
 
-			st,ctl-reg = <
-				DDR_MSTR
-				DDR_MRCTRL0
-				DDR_MRCTRL1
-				DDR_DERATEEN
-				DDR_DERATEINT
-				DDR_PWRCTL
-				DDR_PWRTMG
-				DDR_HWLPCTL
-				DDR_RFSHCTL0
-				DDR_RFSHCTL3
-				DDR_CRCPARCTL0
-				DDR_ZQCTL0
-				DDR_DFITMG0
-				DDR_DFITMG1
-				DDR_DFILPCFG0
-				DDR_DFIUPD0
-				DDR_DFIUPD1
-				DDR_DFIUPD2
-				DDR_DFIPHYMSTR
-				DDR_ODTMAP
-				DDR_DBG0
-				DDR_DBG1
-				DDR_DBGCMD
-				DDR_POISONCFG
-				DDR_PCCFG
-			>;
+	st,phy-timing = <
+		DDR_PTR0
+		DDR_PTR1
+		DDR_PTR2
+		DDR_DTPR0
+		DDR_DTPR1
+		DDR_DTPR2
+		DDR_MR0
+		DDR_MR1
+		DDR_MR2
+		DDR_MR3
+	>;
 
-			st,ctl-timing = <
-				DDR_RFSHTMG
-				DDR_DRAMTMG0
-				DDR_DRAMTMG1
-				DDR_DRAMTMG2
-				DDR_DRAMTMG3
-				DDR_DRAMTMG4
-				DDR_DRAMTMG5
-				DDR_DRAMTMG6
-				DDR_DRAMTMG7
-				DDR_DRAMTMG8
-				DDR_DRAMTMG14
-				DDR_ODTCFG
-			>;
-
-			st,ctl-map = <
-				DDR_ADDRMAP1
-				DDR_ADDRMAP2
-				DDR_ADDRMAP3
-				DDR_ADDRMAP4
-				DDR_ADDRMAP5
-				DDR_ADDRMAP6
-				DDR_ADDRMAP9
-				DDR_ADDRMAP10
-				DDR_ADDRMAP11
-			>;
-
-			st,ctl-perf = <
-				DDR_SCHED
-				DDR_SCHED1
-				DDR_PERFHPR1
-				DDR_PERFLPR1
-				DDR_PERFWR1
-				DDR_PCFGR_0
-				DDR_PCFGW_0
-				DDR_PCFGQOS0_0
-				DDR_PCFGQOS1_0
-				DDR_PCFGWQOS0_0
-				DDR_PCFGWQOS1_0
-				DDR_PCFGR_1
-				DDR_PCFGW_1
-				DDR_PCFGQOS0_1
-				DDR_PCFGQOS1_1
-				DDR_PCFGWQOS0_1
-				DDR_PCFGWQOS1_1
-			>;
-
-			st,phy-reg = <
-				DDR_PGCR
-				DDR_ACIOCR
-				DDR_DXCCR
-				DDR_DSGCR
-				DDR_DCR
-				DDR_ODTCR
-				DDR_ZQ0CR1
-				DDR_DX0GCR
-				DDR_DX1GCR
-				DDR_DX2GCR
-				DDR_DX3GCR
-			>;
-
-			st,phy-timing = <
-				DDR_PTR0
-				DDR_PTR1
-				DDR_PTR2
-				DDR_DTPR0
-				DDR_DTPR1
-				DDR_DTPR2
-				DDR_MR0
-				DDR_MR1
-				DDR_MR2
-				DDR_MR3
-			>;
-
-			st,phy-cal = <
-				DDR_DX0DLLCR
-				DDR_DX0DQTR
-				DDR_DX0DQSTR
-				DDR_DX1DLLCR
-				DDR_DX1DQTR
-				DDR_DX1DQSTR
-				DDR_DX2DLLCR
-				DDR_DX2DQTR
-				DDR_DX2DQSTR
-				DDR_DX3DLLCR
-				DDR_DX3DQTR
-				DDR_DX3DQSTR
-			>;
-
-			status = "okay";
-		};
-	};
+	st,phy-cal = <
+		DDR_DX0DLLCR
+		DDR_DX0DQTR
+		DDR_DX0DQSTR
+		DDR_DX1DLLCR
+		DDR_DX1DQTR
+		DDR_DX1DQSTR
+		DDR_DX2DLLCR
+		DDR_DX2DQTR
+		DDR_DX2DQSTR
+		DDR_DX3DLLCR
+		DDR_DX3DQTR
+		DDR_DX3DQSTR
+	>;
 };
diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
index c0fc1f7..6ca6293 100644
--- a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
+++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
@@ -15,7 +15,7 @@
  * Save Date: 2020.02.20, save Time: 18:45:20
  */
 
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 533000Khz"
+#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 533000kHz"
 #define DDR_MEM_SPEED	533000
 #define DDR_MEM_SIZE	0x20000000
 
diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
index fc226d2..548f69a 100644
--- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
+++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
@@ -15,7 +15,7 @@
  * Save Date: 2020.02.20, save Time: 18:49:33
  */
 
-#define DDR_MEM_NAME	"DDR3-DDR3L 32bits 533000Khz"
+#define DDR_MEM_NAME	"DDR3-DDR3L 32bits 533000kHz"
 #define DDR_MEM_SPEED	533000
 #define DDR_MEM_SIZE	0x40000000
 
diff --git a/fdts/stm32mp15-pinctrl.dtsi b/fdts/stm32mp15-pinctrl.dtsi
index 058cde2..e8e6b9f 100644
--- a/fdts/stm32mp15-pinctrl.dtsi
+++ b/fdts/stm32mp15-pinctrl.dtsi
@@ -86,12 +86,6 @@
 		};
 	};
 
-	rtc_out2_rmp_pins_a: rtc-out2-rmp-pins-0 {
-		pins {
-			pinmux = <STM32_PINMUX('I', 8, ANALOG)>; /* RTC_OUT2_RMP */
-		};
-	};
-
 	sdmmc1_b4_pins_a: sdmmc1-b4-0 {
 		pins1 {
 			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
@@ -176,6 +170,18 @@
 		};
 	};
 
+	sdmmc2_d47_pins_b: sdmmc2-d47-1 {
+		pins {
+			pinmux = <STM32_PINMUX('A', 8, AF9)>,  /* SDMMC2_D4 */
+				 <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+				 <STM32_PINMUX('C', 6, AF10)>, /* SDMMC2_D6 */
+				 <STM32_PINMUX('C', 7, AF10)>; /* SDMMC2_D7 */
+			slew-rate = <1>;
+			drive-push-pull;
+			bias-disable;
+		};
+	};
+
 	sdmmc2_d47_pins_d: sdmmc2-d47-3 {
 		pins {
 			pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
@@ -213,34 +219,90 @@
 
 	uart7_pins_a: uart7-0 {
 		pins1 {
-			pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART4_TX */
+			pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART7_TX */
 			bias-disable;
 			drive-push-pull;
 			slew-rate = <0>;
 		};
 		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF7)>, /* UART4_RX */
-				 <STM32_PINMUX('E', 10, AF7)>, /* UART4_CTS */
-				 <STM32_PINMUX('E', 9, AF7)>; /* UART4_RTS */
+			pinmux = <STM32_PINMUX('E', 7, AF7)>, /* UART7_RX */
+				 <STM32_PINMUX('E', 10, AF7)>, /* UART7_CTS */
+				 <STM32_PINMUX('E', 9, AF7)>; /* UART7_RTS */
 			bias-disable;
 		};
 	};
 
 	uart7_pins_b: uart7-1 {
 		pins1 {
-			pinmux = <STM32_PINMUX('E', 8, AF7)>; /* USART7_TX */
+			pinmux = <STM32_PINMUX('F', 7, AF7)>; /* UART7_TX */
 			bias-disable;
 			drive-push-pull;
 			slew-rate = <0>;
 		};
 		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
+			pinmux = <STM32_PINMUX('F', 6, AF7)>; /* UART7_RX */
+			bias-disable;
+		};
+	};
+
+	uart7_pins_c: uart7-2 {
+		pins1 {
+			pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART7_TX */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('E', 7, AF7)>; /* UART7_RX */
+			bias-disable;
+		};
+	};
+
+	uart8_pins_a: uart8-0 {
+		pins1 {
+			pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
 			bias-disable;
 		};
 	};
 
 	usart2_pins_a: usart2-0 {
 		pins1 {
+			pinmux = <STM32_PINMUX('F', 5, AF7)>, /* USART2_TX */
+				 <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('D', 6, AF7)>, /* USART2_RX */
+				 <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS_NSS */
+			bias-disable;
+		};
+	};
+
+	usart2_pins_b: usart2-1 {
+		pins1 {
+			pinmux = <STM32_PINMUX('F', 5, AF7)>, /* USART2_TX */
+				 <STM32_PINMUX('A', 1, AF7)>; /* USART2_RTS */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('F', 4, AF7)>, /* USART2_RX */
+				 <STM32_PINMUX('E', 15, AF7)>; /* USART2_CTS_NSS */
+			bias-disable;
+		};
+	};
+
+	usart2_pins_c: usart2-2 {
+		pins1 {
 			pinmux = <STM32_PINMUX('D', 5, AF7)>, /* USART2_TX */
 				 <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
 			bias-disable;
@@ -256,15 +318,13 @@
 
 	usart3_pins_a: usart3-0 {
 		pins1 {
-			pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
-				 <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+			pinmux = <STM32_PINMUX('B', 10, AF7)>; /* USART3_TX */
 			bias-disable;
 			drive-push-pull;
 			slew-rate = <0>;
 		};
 		pins2 {
-			pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
-				 <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
+			pinmux = <STM32_PINMUX('B', 12, AF8)>; /* USART3_RX */
 			bias-disable;
 		};
 	};
@@ -279,12 +339,27 @@
 		};
 		pins2 {
 			pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+				 <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
+			bias-disable;
+		};
+	};
+
+	usart3_pins_c: usart3-2 {
+		pins1 {
+			pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+				 <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
 				 <STM32_PINMUX('B', 13, AF7)>; /* USART3_CTS_NSS */
 			bias-disable;
 		};
 	};
 
-	usbotg_hs_pins_a: usbotg_hs-0 {
+	usbotg_hs_pins_a: usbotg-hs-0 {
 		pins {
 			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */
 		};
diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi
index c350c66..3beabbb 100644
--- a/fdts/stm32mp151.dtsi
+++ b/fdts/stm32mp151.dtsi
@@ -174,7 +174,7 @@
 		};
 
 		usbotg_hs: usb-otg@49000000 {
-			compatible = "st,stm32mp1-hsotg", "snps,dwc2";
+			compatible = "st,stm32mp15-hsotg", "snps,dwc2";
 			reg = <0x49000000 0x10000>;
 			clocks = <&rcc USBO_K>;
 			clock-names = "otg";
@@ -319,7 +319,7 @@
 			status = "disabled";
 		};
 
-		sdmmc1: sdmmc@58005000 {
+		sdmmc1: mmc@58005000 {
 			compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
 			arm,primecell-periphid = <0x00253180>;
 			reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
@@ -334,7 +334,7 @@
 			status = "disabled";
 		};
 
-		sdmmc2: sdmmc@58007000 {
+		sdmmc2: mmc@58007000 {
 			compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
 			arm,primecell-periphid = <0x00253180>;
 			reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
@@ -358,6 +358,24 @@
 			status = "disabled";
 		};
 
+		ddr: ddr@5a003000{
+			compatible = "st,stm32mp1-ddr";
+			reg = <0x5A003000 0x550 0x5A004000 0x234>;
+			clocks = <&rcc AXIDCG>,
+				 <&rcc DDRC1>,
+				 <&rcc DDRC2>,
+				 <&rcc DDRPHYC>,
+				 <&rcc DDRCAPB>,
+				 <&rcc DDRPHYCAPB>;
+			clock-names = "axidcg",
+				      "ddrc1",
+				      "ddrc2",
+				      "ddrphyc",
+				      "ddrcapb",
+				      "ddrphycapb";
+			status = "okay";
+		};
+
 		usbphyc: usbphyc@5a006000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -434,7 +452,7 @@
 			status = "disabled";
 		};
 
-		bsec: nvmem@5c005000 {
+		bsec: efuse@5c005000 {
 			compatible = "st,stm32mp15-bsec";
 			reg = <0x5c005000 0x400>;
 			#address-cells = <1>;
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
index a6b98b7..a09c66a 100644
--- a/fdts/stm32mp157c-ed1.dts
+++ b/fdts/stm32mp157c-ed1.dts
@@ -20,7 +20,6 @@
 		stdout-path = "serial0:115200n8";
 	};
 
-
 	memory@c0000000 {
 		device_type = "memory";
 		reg = <0xC0000000 0x40000000>;
@@ -52,7 +51,7 @@
 };
 
 &cryp1 {
-	status="okay";
+	status = "okay";
 };
 
 &hash1 {
@@ -233,7 +232,7 @@
 		CLK_CKPER_HSE
 		CLK_FMC_ACLK
 		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
+		CLK_ETH_PLL4P
 		CLK_SDMMC12_PLL4P
 		CLK_DSI_DSIPLL
 		CLK_STGEN_HSE
@@ -269,25 +268,33 @@
 
 	/* VCO = 1300.0 MHz => P = 650 (CPU) */
 	pll1: st,pll@0 {
-		cfg = < 2 80 0 0 0 PQR(1,0,0) >;
-		frac = < 0x800 >;
+		compatible = "st,stm32mp1-pll";
+		reg = <0>;
+		cfg = <2 80 0 0 0 PQR(1,0,0)>;
+		frac = <0x800>;
 	};
 
 	/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
 	pll2: st,pll@1 {
-		cfg = < 2 65 1 0 0 PQR(1,1,1) >;
-		frac = < 0x1400 >;
+		compatible = "st,stm32mp1-pll";
+		reg = <1>;
+		cfg = <2 65 1 0 0 PQR(1,1,1)>;
+		frac = <0x1400>;
 	};
 
 	/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
 	pll3: st,pll@2 {
-		cfg = < 1 33 1 16 36 PQR(1,1,1) >;
-		frac = < 0x1a04 >;
+		compatible = "st,stm32mp1-pll";
+		reg = <2>;
+		cfg = <1 33 1 16 36 PQR(1,1,1)>;
+		frac = <0x1a04>;
 	};
 
 	/* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
 	pll4: st,pll@3 {
-		cfg = < 3 98 5 7 7 PQR(1,1,1) >;
+		compatible = "st,stm32mp1-pll";
+		reg = <3>;
+		cfg = <3 98 5 7 7 PQR(1,1,1)>;
 	};
 };
 
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
index c5d12e3..4937514 100644
--- a/fdts/stm32mp157c-ev1.dts
+++ b/fdts/stm32mp157c-ev1.dts
@@ -57,6 +57,7 @@
 
 &usart3 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&usart3_pins_a>;
+	pinctrl-0 = <&usart3_pins_b>;
+	uart-has-rtscts;
 	status = "disabled";
 };
diff --git a/fdts/stm32mp157c-lxa-mc1.dts b/fdts/stm32mp157c-lxa-mc1.dts
index 7b8e481..31f1382 100644
--- a/fdts/stm32mp157c-lxa-mc1.dts
+++ b/fdts/stm32mp157c-lxa-mc1.dts
@@ -75,7 +75,7 @@
 
 &sdmmc2 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc2_b4_pins_a &mc1_sdmmc2_d47_pins_b>;
+	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_b>;
 	bus-width = <8>;
 	no-1-8-v;
 	no-sd;
@@ -91,17 +91,3 @@
 	pinctrl-0 = <&uart4_pins_a>;
 	status = "okay";
 };
-
-&pinctrl {
-	mc1_sdmmc2_d47_pins_b: mc1-sdmmc2-d47-1 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 8, AF9)>,  /* SDMMC2_D4 */
-				 <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
-				 <STM32_PINMUX('C', 6, AF10)>, /* SDMMC2_D6 */
-				 <STM32_PINMUX('C', 7, AF10)>; /* SDMMC2_D7 */
-			slew-rate = <1>;
-			drive-push-pull;
-			bias-disable;
-		};
-	};
-};
diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi
index 52b914b..69b4828 100644
--- a/fdts/stm32mp15xx-dkx.dtsi
+++ b/fdts/stm32mp15xx-dkx.dtsi
@@ -141,7 +141,6 @@
 				regulator-name = "vdd_usb";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
 			};
 
 			vdda: ldo5 {
@@ -223,7 +222,7 @@
 		CLK_CKPER_HSE
 		CLK_FMC_ACLK
 		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
+		CLK_ETH_PLL4P
 		CLK_SDMMC12_PLL4P
 		CLK_DSI_DSIPLL
 		CLK_STGEN_HSE
@@ -319,13 +318,13 @@
 
 &uart7 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&uart7_pins_b>;
+	pinctrl-0 = <&uart7_pins_c>;
 	status = "disabled";
 };
 
 &usart3 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&usart3_pins_b>;
+	pinctrl-0 = <&usart3_pins_c>;
 	uart-has-rtscts;
 	status = "disabled";
 };
diff --git a/fdts/stm32mp15xxaa-pinctrl.dtsi b/fdts/stm32mp15xxaa-pinctrl.dtsi
index 64e566b..04f7a43 100644
--- a/fdts/stm32mp15xxaa-pinctrl.dtsi
+++ b/fdts/stm32mp15xxaa-pinctrl.dtsi
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
  * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
 &pinctrl {
diff --git a/fdts/stm32mp15xxab-pinctrl.dtsi b/fdts/stm32mp15xxab-pinctrl.dtsi
index d29af89..328dad1 100644
--- a/fdts/stm32mp15xxab-pinctrl.dtsi
+++ b/fdts/stm32mp15xxab-pinctrl.dtsi
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
  * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
 &pinctrl {
diff --git a/fdts/stm32mp15xxac-pinctrl.dtsi b/fdts/stm32mp15xxac-pinctrl.dtsi
index 5d8199f..7eaa245 100644
--- a/fdts/stm32mp15xxac-pinctrl.dtsi
+++ b/fdts/stm32mp15xxac-pinctrl.dtsi
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
  * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
 &pinctrl {
diff --git a/fdts/stm32mp15xxad-pinctrl.dtsi b/fdts/stm32mp15xxad-pinctrl.dtsi
index 023f540..b63e207 100644
--- a/fdts/stm32mp15xxad-pinctrl.dtsi
+++ b/fdts/stm32mp15xxad-pinctrl.dtsi
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
  * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
 &pinctrl {
diff --git a/fdts/tc.dts b/fdts/tc.dts
index f66d556..13c9e16 100644
--- a/fdts/tc.dts
+++ b/fdts/tc.dts
@@ -79,6 +79,31 @@
 			};
 		};
 
+		amus {
+			amu: amu-0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mpmm_gear0: counter@0 {
+					reg = <0>;
+
+					enable-at-el3;
+				};
+
+				mpmm_gear1: counter@1 {
+					reg = <1>;
+
+					enable-at-el3;
+				};
+
+				mpmm_gear2: counter@2 {
+					reg = <2>;
+
+					enable-at-el3;
+				};
+			};
+		};
+
 		CPU0:cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,armv8";
@@ -87,6 +112,8 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <406>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU1:cpu@100 {
@@ -97,6 +124,8 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <406>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU2:cpu@200 {
@@ -107,6 +136,8 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <406>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU3:cpu@300 {
@@ -117,6 +148,8 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <406>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU4:cpu@400 {
@@ -127,6 +160,8 @@
 			clocks = <&scmi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <912>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU5:cpu@500 {
@@ -137,6 +172,8 @@
 			clocks = <&scmi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <912>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU6:cpu@600 {
@@ -147,6 +184,8 @@
 			clocks = <&scmi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <912>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 		CPU7:cpu@700 {
@@ -157,15 +196,12 @@
 			clocks = <&scmi_dvfs 2>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <1024>;
+			amu = <&amu>;
+			supports-mpmm;
 		};
 
 	};
 
-	memory@80000000 {
-		device_type = "memory";
-		reg = <0x0 0x80000000 0x0 0x7d000000>;
-	};
-
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
index 7221b62..a1bd942 100644
--- a/include/arch/aarch32/arch.h
+++ b/include/arch/aarch32/arch.h
@@ -253,7 +253,8 @@
 /* HCPTR definitions */
 #define HCPTR_RES1		((U(1) << 13) | (U(1) << 12) | U(0x3ff))
 #define TCPAC_BIT		(U(1) << 31)
-#define TAM_BIT			(U(1) << 30)
+#define TAM_SHIFT		U(30)
+#define TAM_BIT			(U(1) << TAM_SHIFT)
 #define TTA_BIT			(U(1) << 20)
 #define TCP11_BIT		(U(1) << 11)
 #define TCP10_BIT		(U(1) << 10)
@@ -727,8 +728,25 @@
 #define AMEVTYPER1E	p15, 0, c13, c15, 6
 #define AMEVTYPER1F	p15, 0, c13, c15, 7
 
+/* AMCNTENSET0 definitions */
+#define AMCNTENSET0_Pn_SHIFT	U(0)
+#define AMCNTENSET0_Pn_MASK	U(0xffff)
+
+/* AMCNTENSET1 definitions */
+#define AMCNTENSET1_Pn_SHIFT	U(0)
+#define AMCNTENSET1_Pn_MASK	U(0xffff)
+
+/* AMCNTENCLR0 definitions */
+#define AMCNTENCLR0_Pn_SHIFT	U(0)
+#define AMCNTENCLR0_Pn_MASK	U(0xffff)
+
+/* AMCNTENCLR1 definitions */
+#define AMCNTENCLR1_Pn_SHIFT	U(0)
+#define AMCNTENCLR1_Pn_MASK	U(0xffff)
+
 /* AMCR definitions */
-#define AMCR_CG1RZ_BIT		(ULL(1) << 17)
+#define AMCR_CG1RZ_SHIFT	U(17)
+#define AMCR_CG1RZ_BIT		(ULL(1) << AMCR_CG1RZ_SHIFT)
 
 /* AMCFGR definitions */
 #define AMCFGR_NCG_SHIFT	U(28)
@@ -737,6 +755,8 @@
 #define AMCFGR_N_MASK		U(0xff)
 
 /* AMCGCR definitions */
+#define AMCGCR_CG0NC_SHIFT	U(0)
+#define AMCGCR_CG0NC_MASK	U(0xff)
 #define AMCGCR_CG1NC_SHIFT	U(8)
 #define AMCGCR_CG1NC_MASK	U(0xff)
 
diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S
index 65f9a8e..ad2a039 100644
--- a/include/arch/aarch32/el3_common_macros.S
+++ b/include/arch/aarch32/el3_common_macros.S
@@ -380,10 +380,21 @@
 		 * includes the data and NOBITS sections. This is done to
 		 * safeguard against possible corruption of this memory by
 		 * dirty cache lines in a system cache as a result of use by
-		 * an earlier boot loader stage.
+		 * an earlier boot loader stage. If PIE is enabled however,
+		 * RO sections including the GOT may be modified during
+		 * pie fixup. Therefore, to be on the safe side, invalidate
+		 * the entire image region if PIE is enabled.
 		 * -----------------------------------------------------------------
 		 */
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+		ldr	r0, =__TEXT_START__
+#else
+		ldr	r0, =__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
 		ldr	r0, =__RW_START__
+#endif /* ENABLE_PIE */
 		ldr	r1, =__RW_END__
 		sub	r1, r1, r0
 		bl	inv_dcache_range
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 74bc8cb..5408acf 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -532,7 +532,8 @@
 
 /* HCR definitions */
 #define HCR_RESET_VAL		ULL(0x0)
-#define HCR_AMVOFFEN_BIT	(ULL(1) << 51)
+#define HCR_AMVOFFEN_SHIFT	U(51)
+#define HCR_AMVOFFEN_BIT	(ULL(1) << HCR_AMVOFFEN_SHIFT)
 #define HCR_TEA_BIT		(ULL(1) << 47)
 #define HCR_API_BIT		(ULL(1) << 41)
 #define HCR_APK_BIT		(ULL(1) << 40)
@@ -570,7 +571,8 @@
 
 /* CPTR_EL3 definitions */
 #define TCPAC_BIT		(U(1) << 31)
-#define TAM_BIT			(U(1) << 30)
+#define TAM_SHIFT		U(30)
+#define TAM_BIT			(U(1) << TAM_SHIFT)
 #define TTA_BIT			(U(1) << 20)
 #define TFP_BIT			(U(1) << 10)
 #define CPTR_EZ_BIT		(U(1) << 8)
@@ -579,7 +581,8 @@
 /* CPTR_EL2 definitions */
 #define CPTR_EL2_RES1		((U(1) << 13) | (U(1) << 12) | (U(0x3ff)))
 #define CPTR_EL2_TCPAC_BIT	(U(1) << 31)
-#define CPTR_EL2_TAM_BIT	(U(1) << 30)
+#define CPTR_EL2_TAM_SHIFT	U(30)
+#define CPTR_EL2_TAM_BIT	(U(1) << CPTR_EL2_TAM_SHIFT)
 #define CPTR_EL2_TTA_BIT	(U(1) << 20)
 #define CPTR_EL2_TFP_BIT	(U(1) << 10)
 #define CPTR_EL2_TZ_BIT		(U(1) << 8)
@@ -1043,6 +1046,22 @@
 #define AMEVTYPER1E_EL0		S3_3_C13_C15_6
 #define AMEVTYPER1F_EL0		S3_3_C13_C15_7
 
+/* AMCNTENSET0_EL0 definitions */
+#define AMCNTENSET0_EL0_Pn_SHIFT	U(0)
+#define AMCNTENSET0_EL0_Pn_MASK		ULL(0xffff)
+
+/* AMCNTENSET1_EL0 definitions */
+#define AMCNTENSET1_EL0_Pn_SHIFT	U(0)
+#define AMCNTENSET1_EL0_Pn_MASK		ULL(0xffff)
+
+/* AMCNTENCLR0_EL0 definitions */
+#define AMCNTENCLR0_EL0_Pn_SHIFT	U(0)
+#define AMCNTENCLR0_EL0_Pn_MASK		ULL(0xffff)
+
+/* AMCNTENCLR1_EL0 definitions */
+#define AMCNTENCLR1_EL0_Pn_SHIFT	U(0)
+#define AMCNTENCLR1_EL0_Pn_MASK		ULL(0xffff)
+
 /* AMCFGR_EL0 definitions */
 #define AMCFGR_EL0_NCG_SHIFT	U(28)
 #define AMCFGR_EL0_NCG_MASK	U(0xf)
@@ -1050,6 +1069,8 @@
 #define AMCFGR_EL0_N_MASK	U(0xff)
 
 /* AMCGCR_EL0 definitions */
+#define AMCGCR_EL0_CG0NC_SHIFT	U(0)
+#define AMCGCR_EL0_CG0NC_MASK	U(0xff)
 #define AMCGCR_EL0_CG1NC_SHIFT	U(8)
 #define AMCGCR_EL0_CG1NC_MASK	U(0xff)
 
@@ -1074,7 +1095,8 @@
 #define AMCG1IDR_VOFF_SHIFT	U(16)
 
 /* New bit added to AMCR_EL0 */
-#define AMCR_CG1RZ_BIT		(ULL(0x1) << 17)
+#define AMCR_CG1RZ_SHIFT	U(17)
+#define AMCR_CG1RZ_BIT		(ULL(0x1) << AMCR_CG1RZ_SHIFT)
 
 /*
  * Definitions for virtual offset registers for architected activity monitor
@@ -1194,4 +1216,16 @@
 #define DSU_CLUSTER_PWR_ON	1
 #define DSU_CLUSTER_PWR_MASK	U(1)
 
+/*******************************************************************************
+ * Definitions for CPU Power/Performance Management registers
+ ******************************************************************************/
+
+#define CPUPPMCR_EL3			S3_6_C15_C2_0
+#define CPUPPMCR_EL3_MPMMPINCTL_SHIFT	UINT64_C(0)
+#define CPUPPMCR_EL3_MPMMPINCTL_MASK	UINT64_C(0x1)
+
+#define CPUMPMMCR_EL3			S3_6_C15_C2_1
+#define CPUMPMMCR_EL3_MPMM_EN_SHIFT	UINT64_C(0)
+#define CPUMPMMCR_EL3_MPMM_EN_MASK	UINT64_C(0x1)
+
 #endif /* ARCH_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index cae05dc..37fa047 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -542,6 +542,10 @@
 /* DynamIQ Shared Unit power management */
 DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
 
+/* CPU Power/Performance Management registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpumpmmcr_el3, CPUMPMMCR_EL3)
+
 /* Armv9.2 RME Registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index 7d6a963..8e8d334 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -430,11 +430,24 @@
 		 * includes the data and NOBITS sections. This is done to
 		 * safeguard against possible corruption of this memory by
 		 * dirty cache lines in a system cache as a result of use by
-		 * an earlier boot loader stage.
+		 * an earlier boot loader stage. If PIE is enabled however,
+		 * RO sections including the GOT may be modified during
+                 * pie fixup. Therefore, to be on the safe side, invalidate
+		 * the entire image region if PIE is enabled.
 		 * -------------------------------------------------------------
 		 */
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+		adrp	x0, __TEXT_START__
+		add	x0, x0, :lo12:__TEXT_START__
+#else
+		adrp	x0, __RO_START__
+		add	x0, x0, :lo12:__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
 		adrp	x0, __RW_START__
 		add	x0, x0, :lo12:__RW_START__
+#endif /* ENABLE_PIE */
 		adrp	x1, __RW_END__
 		add	x1, x1, :lo12:__RW_END__
 		sub	x1, x1, x0
diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h
index 98e7a3e..9c7180c 100644
--- a/include/common/fdt_wrappers.h
+++ b/include/common/fdt_wrappers.h
@@ -41,6 +41,9 @@
 uint64_t fdtw_translate_address(const void *dtb, int bus_node,
 				uint64_t base_address);
 
+int fdtw_for_each_cpu(const void *fdt,
+		      int (*callback)(const void *dtb, int node, uintptr_t mpidr));
+
 static inline uint32_t fdt_blob_size(const void *dtb)
 {
 	const uint32_t *dtb_header = dtb;
diff --git a/include/drivers/arm/css/scmi.h b/include/drivers/arm/css/scmi.h
index adce7a6..9dd08e5 100644
--- a/include/drivers/arm/css/scmi.h
+++ b/include/drivers/arm/css/scmi.h
@@ -25,10 +25,16 @@
 #define MAKE_SCMI_VERSION(maj, min)	\
 			((((maj) & 0xffff) << 16) | ((min) & 0xffff))
 
-/* Macro to check if the driver is compatible with the SCMI version reported */
+/*
+ * Check that the driver's version is same or higher than the reported SCMI
+ * version. We accept lower major version numbers, as all affected protocols
+ * so far stay backwards compatible. This might need to be revisited in the
+ * future.
+ */
 #define is_scmi_version_compatible(drv, scmi)				\
+	((GET_SCMI_MAJOR_VER(drv) > GET_SCMI_MAJOR_VER(scmi)) ||	\
 	((GET_SCMI_MAJOR_VER(drv) == GET_SCMI_MAJOR_VER(scmi)) &&	\
-	(GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi)))
+	(GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi))))
 
 /* SCMI Protocol identifiers */
 #define SCMI_PWR_DMN_PROTO_ID			0x11
diff --git a/include/drivers/nxp/dcfg/scfg.h b/include/drivers/nxp/dcfg/scfg.h
index b6e3df5..ef6ed6b 100644
--- a/include/drivers/nxp/dcfg/scfg.h
+++ b/include/drivers/nxp/dcfg/scfg.h
@@ -44,7 +44,7 @@
 #define scfg_clrbits32(a, v)	mmio_clrbits_32((uintptr_t)(a), v)
 #define scfg_clrsetbits32(a, clear, set)	\
 				mmio_clrsetbits_32((uintptr_t)(a), clear, set)
-#elif defined(NXP_GUR_LE)
+#elif defined(NXP_SCFG_LE)
 #define scfg_in32(a)		mmio_read_32((uintptr_t)(a))
 #define scfg_out32(a, v)	mmio_write_32((uintptr_t)(a), v)
 #define scfg_setbits32(a, v)	mmio_setbits_32((uintptr_t)(a), v)
diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h
index 574c4ea..c074e85 100644
--- a/include/drivers/ufs.h
+++ b/include/drivers/ufs.h
@@ -254,6 +254,17 @@
 #define UFS_VENDOR_SKHYNIX		U(0x1AD)
 
 #define MAX_MODEL_LEN 16
+
+/* maximum number of retries for a general UIC command  */
+#define UFS_UIC_COMMAND_RETRIES		3
+
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES		10
+
+#define HCE_ENABLE_OUTER_RETRIES	3
+#define HCE_ENABLE_INNER_RETRIES	50
+#define HCE_ENABLE_TIMEOUT_US		100
+
 /**
  * ufs_dev_desc - ufs device details from the device descriptor
  * @wmanufacturerid: card details
diff --git a/include/lib/cpus/aarch64/cortex_demeter.h b/include/lib/cpus/aarch64/cortex_hunter.h
similarity index 65%
rename from include/lib/cpus/aarch64/cortex_demeter.h
rename to include/lib/cpus/aarch64/cortex_hunter.h
index 9dd0987..8b59fd9 100644
--- a/include/lib/cpus/aarch64/cortex_demeter.h
+++ b/include/lib/cpus/aarch64/cortex_hunter.h
@@ -4,20 +4,20 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef CORTEX_DEMETER_H
-#define CORTEX_DEMETER_H
+#ifndef CORTEX_HUNTER_H
+#define CORTEX_HUNTER_H
 
-#define CORTEX_DEMETER_MIDR				U(0x410FD4F0)
+#define CORTEX_HUNTER_MIDR					U(0x410FD810)
 
 /*******************************************************************************
  * CPU Extended Control register specific definitions
  ******************************************************************************/
-#define CORTEX_DEMETER_CPUECTLR_EL1			S3_0_C15_C1_4
+#define CORTEX_HUNTER_CPUECTLR_EL1				S3_0_C15_C1_4
 
 /*******************************************************************************
  * CPU Power Control register specific definitions
  ******************************************************************************/
-#define CORTEX_DEMETER_CPUPWRCTLR_EL1			S3_0_C15_C2_7
-#define CORTEX_DEMETER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	U(1)
+#define CORTEX_HUNTER_CPUPWRCTLR_EL1				S3_0_C15_C2_7
+#define CORTEX_HUNTER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
 
-#endif /* CORTEX_DEMETER_H */
+#endif /* CORTEX_HUNTER_H */
diff --git a/include/lib/cpus/aarch64/cortex_demeter.h b/include/lib/cpus/aarch64/neoverse_demeter.h
similarity index 64%
copy from include/lib/cpus/aarch64/cortex_demeter.h
copy to include/lib/cpus/aarch64/neoverse_demeter.h
index 9dd0987..230ed66 100644
--- a/include/lib/cpus/aarch64/cortex_demeter.h
+++ b/include/lib/cpus/aarch64/neoverse_demeter.h
@@ -4,20 +4,20 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef CORTEX_DEMETER_H
-#define CORTEX_DEMETER_H
+#ifndef NEOVERSE_DEMETER_H
+#define NEOVERSE_DEMETER_H
 
-#define CORTEX_DEMETER_MIDR				U(0x410FD4F0)
+#define NEOVERSE_DEMETER_MIDR				U(0x410FD4F0)
 
 /*******************************************************************************
  * CPU Extended Control register specific definitions
  ******************************************************************************/
-#define CORTEX_DEMETER_CPUECTLR_EL1			S3_0_C15_C1_4
+#define NEOVERSE_DEMETER_CPUECTLR_EL1			S3_0_C15_C1_4
 
 /*******************************************************************************
  * CPU Power Control register specific definitions
  ******************************************************************************/
-#define CORTEX_DEMETER_CPUPWRCTLR_EL1			S3_0_C15_C2_7
-#define CORTEX_DEMETER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	U(1)
+#define NEOVERSE_DEMETER_CPUPWRCTLR_EL1			S3_0_C15_C2_7
+#define NEOVERSE_DEMETER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	U(1)
 
-#endif /* CORTEX_DEMETER_H */
+#endif /* NEOVERSE_DEMETER_H */
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
index 3a254c9..6452f7e 100644
--- a/include/lib/extensions/amu.h
+++ b/include/lib/extensions/amu.h
@@ -10,105 +10,38 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include <lib/cassert.h>
-#include <lib/utils_def.h>
-
 #include <context.h>
+
 #include <platform_def.h>
 
-/* All group 0 counters */
-#define AMU_GROUP0_COUNTERS_MASK	U(0xf)
-#define AMU_GROUP0_NR_COUNTERS		U(4)
-
-#ifdef PLAT_AMU_GROUP1_COUNTERS_MASK
-#define AMU_GROUP1_COUNTERS_MASK	PLAT_AMU_GROUP1_COUNTERS_MASK
-#else
-#define AMU_GROUP1_COUNTERS_MASK	U(0)
-#endif
-
-/* Calculate number of group 1 counters */
-#if (AMU_GROUP1_COUNTERS_MASK	& (1 << 15))
-#define	AMU_GROUP1_NR_COUNTERS		16U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 14))
-#define	AMU_GROUP1_NR_COUNTERS		15U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 13))
-#define	AMU_GROUP1_NR_COUNTERS		14U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 12))
-#define	AMU_GROUP1_NR_COUNTERS		13U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 11))
-#define	AMU_GROUP1_NR_COUNTERS		12U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 10))
-#define	AMU_GROUP1_NR_COUNTERS		11U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 9))
-#define	AMU_GROUP1_NR_COUNTERS		10U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 8))
-#define	AMU_GROUP1_NR_COUNTERS		9U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 7))
-#define	AMU_GROUP1_NR_COUNTERS		8U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 6))
-#define	AMU_GROUP1_NR_COUNTERS		7U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 5))
-#define	AMU_GROUP1_NR_COUNTERS		6U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 4))
-#define	AMU_GROUP1_NR_COUNTERS		5U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 3))
-#define	AMU_GROUP1_NR_COUNTERS		4U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 2))
-#define	AMU_GROUP1_NR_COUNTERS		3U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 1))
-#define	AMU_GROUP1_NR_COUNTERS		2U
-#elif (AMU_GROUP1_COUNTERS_MASK	& (1 << 0))
-#define	AMU_GROUP1_NR_COUNTERS		1U
-#else
-#define	AMU_GROUP1_NR_COUNTERS		0U
-#endif
-
-CASSERT(AMU_GROUP1_COUNTERS_MASK <= 0xffff, invalid_amu_group1_counters_mask);
-
-struct amu_ctx {
-	uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS];
-#if __aarch64__
-	/* Architected event counter 1 does not have an offset register. */
-	uint64_t group0_voffsets[AMU_GROUP0_NR_COUNTERS-1];
-#endif
-
-#if AMU_GROUP1_NR_COUNTERS
-	uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS];
-#if __aarch64__
-	uint64_t group1_voffsets[AMU_GROUP1_NR_COUNTERS];
-#endif
-#endif
-};
-
-unsigned int amu_get_version(void);
 #if __aarch64__
 void amu_enable(bool el2_unused, cpu_context_t *ctx);
 #else
 void amu_enable(bool el2_unused);
 #endif
 
-/* Group 0 configuration helpers */
-uint64_t amu_group0_cnt_read(unsigned int idx);
-void amu_group0_cnt_write(unsigned int idx, uint64_t val);
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/*
+ * AMU data for a single core.
+ */
+struct amu_core {
+	uint16_t enable; /* Mask of auxiliary counters to enable */
+};
 
-#if __aarch64__
-uint64_t amu_group0_voffset_read(unsigned int idx);
-void amu_group0_voffset_write(unsigned int idx, uint64_t val);
-#endif
+/*
+ * Topological platform data specific to the AMU.
+ */
+struct amu_topology {
+	struct amu_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
+};
 
-#if AMU_GROUP1_NR_COUNTERS
-bool amu_group1_supported(void);
-
-/* Group 1 configuration helpers */
-uint64_t amu_group1_cnt_read(unsigned int idx);
-void amu_group1_cnt_write(unsigned int idx, uint64_t val);
-void amu_group1_set_evtype(unsigned int idx, unsigned int val);
-
-#if __aarch64__
-uint64_t amu_group1_voffset_read(unsigned int idx);
-void amu_group1_voffset_write(unsigned int idx, uint64_t val);
-#endif
-
-#endif
+#if !ENABLE_AMU_FCONF
+/*
+ * Retrieve the platform's AMU topology. A `NULL` return value is treated as a
+ * non-fatal error, in which case no auxiliary counters will be enabled.
+ */
+const struct amu_topology *plat_amu_topology(void);
+#endif /* ENABLE_AMU_FCONF */
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
 
 #endif /* AMU_H */
diff --git a/include/lib/fconf/fconf_amu_getter.h b/include/lib/fconf/fconf_amu_getter.h
new file mode 100644
index 0000000..2faee73
--- /dev/null
+++ b/include/lib/fconf/fconf_amu_getter.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_AMU_GETTER_H
+#define FCONF_AMU_GETTER_H
+
+#include <lib/extensions/amu.h>
+
+#define amu__config_getter(id)	fconf_amu_config.id
+
+struct fconf_amu_config {
+	const struct amu_topology *topology;
+};
+
+extern struct fconf_amu_config fconf_amu_config;
+
+#endif /* FCONF_AMU_GETTER_H */
diff --git a/include/lib/fconf/fconf_mpmm_getter.h b/include/lib/fconf/fconf_mpmm_getter.h
new file mode 100644
index 0000000..50d991a
--- /dev/null
+++ b/include/lib/fconf/fconf_mpmm_getter.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_MPMM_GETTER_H
+#define FCONF_MPMM_GETTER_H
+
+#include <lib/mpmm/mpmm.h>
+
+#define mpmm__config_getter(id)	fconf_mpmm_config.id
+
+struct fconf_mpmm_config {
+	const struct mpmm_topology *topology;
+};
+
+extern struct fconf_mpmm_config fconf_mpmm_config;
+
+#endif /* FCONF_MPMM_GETTER_H */
diff --git a/include/lib/mpmm/mpmm.h b/include/lib/mpmm/mpmm.h
new file mode 100644
index 0000000..955c530
--- /dev/null
+++ b/include/lib/mpmm/mpmm.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MPMM_H
+#define MPMM_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+/*
+ * Enable the Maximum Power Mitigation Mechanism.
+ *
+ * This function will enable MPMM for the current core. The AMU counters
+ * representing the MPMM gears must have been configured and enabled prior to
+ * calling this function.
+ */
+void mpmm_enable(void);
+
+/*
+ * MPMM core data.
+ *
+ * This structure represents per-core data retrieved from the hardware
+ * configuration device tree.
+ */
+struct mpmm_core {
+	/*
+	 * Whether MPMM is supported.
+	 *
+	 * Cores with support for MPMM offer one or more auxiliary AMU counters
+	 * representing MPMM gears.
+	 */
+	bool supported;
+};
+
+/*
+ * MPMM topology.
+ *
+ * This topology structure describes the system-wide representation of the
+ * information retrieved from the hardware configuration device tree.
+ */
+struct mpmm_topology {
+	struct mpmm_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
+};
+
+#if !ENABLE_MPMM_FCONF
+/*
+ * Retrieve the platform's MPMM topology. A `NULL` return value is treated as a
+ * non-fatal error, in which case MPMM will not be enabled for any core.
+ */
+const struct mpmm_topology *plat_mpmm_topology(void);
+#endif /* ENABLE_MPMM_FCONF */
+
+#endif /* MPMM_H */
diff --git a/lib/cpus/aarch64/cortex_demeter.S b/lib/cpus/aarch64/cortex_demeter.S
deleted file mode 100644
index 9ad8b86..0000000
--- a/lib/cpus/aarch64/cortex_demeter.S
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <asm_macros.S>
-#include <common/bl_common.h>
-#include <cortex_demeter.h>
-#include <cpu_macros.S>
-#include <plat_macros.S>
-
-/* Hardware handled coherency */
-#if HW_ASSISTED_COHERENCY == 0
-#error "Cortex Demeter must be compiled with HW_ASSISTED_COHERENCY enabled"
-#endif
-
-/* 64-bit only core */
-#if CTX_INCLUDE_AARCH32_REGS == 1
-#error "Cortex Demeter supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
-#endif
-
-	/* ----------------------------------------------------
-	 * HW will do the cache maintenance while powering down
-	 * ----------------------------------------------------
-	 */
-func cortex_demeter_core_pwr_dwn
-	/* ---------------------------------------------------
-	 * Enable CPU power down bit in power control register
-	 * ---------------------------------------------------
-	 */
-	mrs	x0, CORTEX_DEMETER_CPUPWRCTLR_EL1
-	orr	x0, x0, #CORTEX_DEMETER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
-	msr	CORTEX_DEMETER_CPUPWRCTLR_EL1, x0
-	isb
-	ret
-endfunc cortex_demeter_core_pwr_dwn
-
-#if REPORT_ERRATA
-/*
- * Errata printing function for Cortex Demeter. Must follow AAPCS.
- */
-func cortex_demeter_errata_report
-	ret
-endfunc cortex_demeter_errata_report
-#endif
-
-func cortex_demeter_reset_func
-	/* Disable speculative loads */
-	msr	SSBS, xzr
-	isb
-	ret
-endfunc cortex_demeter_reset_func
-
-	/* ---------------------------------------------
-	 * This function provides Cortex Demeter-
-	 * specific register information for crash
-	 * reporting. It needs to return with x6
-	 * pointing to a list of register names in ascii
-	 * and x8 - x15 having values of registers to be
-	 * reported.
-	 * ---------------------------------------------
-	 */
-.section .rodata.cortex_demeter_regs, "aS"
-cortex_demeter_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
-
-func cortex_demeter_cpu_reg_dump
-	adr	x6, cortex_demeter_regs
-	mrs	x8, CORTEX_DEMETER_CPUECTLR_EL1
-	ret
-endfunc cortex_demeter_cpu_reg_dump
-
-declare_cpu_ops cortex_demeter, CORTEX_DEMETER_MIDR, \
-	cortex_demeter_reset_func, \
-	cortex_demeter_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_hunter.S b/lib/cpus/aarch64/cortex_hunter.S
new file mode 100644
index 0000000..2ab4296
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_hunter.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_hunter.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex Hunter must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex Hunter supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+func cortex_hunter_reset_func
+	/* Disable speculative loads */
+	msr	SSBS, xzr
+	isb
+	ret
+endfunc cortex_hunter_reset_func
+
+	/* ----------------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ----------------------------------------------------
+	 */
+func cortex_hunter_core_pwr_dwn
+	/* ---------------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------------
+	 */
+	mrs	x0, CORTEX_HUNTER_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_HUNTER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	CORTEX_HUNTER_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_hunter_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex Hunter. Must follow AAPCS.
+ */
+func cortex_hunter_errata_report
+	ret
+endfunc cortex_hunter_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides Cortex Hunter-specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_hunter_regs, "aS"
+cortex_hunter_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_hunter_cpu_reg_dump
+	adr	x6, cortex_hunter_regs
+	mrs	x8, CORTEX_HUNTER_CPUECTLR_EL1
+	ret
+endfunc cortex_hunter_cpu_reg_dump
+
+declare_cpu_ops cortex_hunter, CORTEX_HUNTER_MIDR, \
+	cortex_hunter_reset_func, \
+	cortex_hunter_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_demeter.S b/lib/cpus/aarch64/neoverse_demeter.S
new file mode 100644
index 0000000..f43c18b
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_demeter.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_demeter.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse Demeter must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse Demeter supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+	/* ----------------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ----------------------------------------------------
+	 */
+func neoverse_demeter_core_pwr_dwn
+	/* ---------------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------------
+	 */
+	mrs	x0, NEOVERSE_DEMETER_CPUPWRCTLR_EL1
+	orr	x0, x0, #NEOVERSE_DEMETER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	NEOVERSE_DEMETER_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc neoverse_demeter_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Neoverse Demeter. Must follow AAPCS.
+ */
+func neoverse_demeter_errata_report
+	ret
+endfunc neoverse_demeter_errata_report
+#endif
+
+func neoverse_demeter_reset_func
+	/* Disable speculative loads */
+	msr	SSBS, xzr
+	isb
+	ret
+endfunc neoverse_demeter_reset_func
+
+	/* ---------------------------------------------
+	 * This function provides Neoverse Demeter-
+	 * specific register information for crash
+	 * reporting. It needs to return with x6
+	 * pointing to a list of register names in ascii
+	 * and x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.neoverse_demeter_regs, "aS"
+neoverse_demeter_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func neoverse_demeter_cpu_reg_dump
+	adr	x6, neoverse_demeter_regs
+	mrs	x8, NEOVERSE_DEMETER_CPUECTLR_EL1
+	ret
+endfunc neoverse_demeter_cpu_reg_dump
+
+declare_cpu_ops neoverse_demeter, NEOVERSE_DEMETER_MIDR, \
+	neoverse_demeter_reset_func, \
+	neoverse_demeter_core_pwr_dwn
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index 5d1e3c5..93b2744 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,7 +19,7 @@
 # define BL_STRING	"BL1"
 #elif defined(__aarch64__) && defined(IMAGE_BL31)
 # define BL_STRING	"BL31"
-#elif !defined(__arch64__) && defined(IMAGE_BL32)
+#elif !defined(__aarch64__) && defined(IMAGE_BL32)
 # define BL_STRING	"BL32"
 #elif defined(IMAGE_BL2) && BL2_AT_EL3
 # define BL_STRING "BL2"
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
index ed56ddd..57b1158 100644
--- a/lib/extensions/amu/aarch32/amu.c
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -5,95 +5,224 @@
  */
 
 #include <assert.h>
+#include <cdefs.h>
 #include <stdbool.h>
 
+#include "../amu_private.h"
 #include <arch.h>
 #include <arch_helpers.h>
-
+#include <common/debug.h>
 #include <lib/el3_runtime/pubsub_events.h>
 #include <lib/extensions/amu.h>
-#include <lib/extensions/amu_private.h>
 
 #include <plat/common/platform.h>
 
-static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
+struct amu_ctx {
+	uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
+#endif
 
-/*
- * Get AMU version value from pfr0.
- * Return values
- *   ID_PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4)
- *   ID_PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6)
- *   ID_PFR0_AMU_NOT_SUPPORTED: not supported
- */
-unsigned int amu_get_version(void)
+	uint16_t group0_enable;
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint16_t group1_enable;
+#endif
+};
+
+static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
+
+CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
+	amu_ctx_group0_enable_cannot_represent_all_group0_counters);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
+	amu_ctx_group1_enable_cannot_represent_all_group1_counters);
+#endif
+
+static inline __unused uint32_t read_id_pfr0_amu(void)
 {
-	return (unsigned int)(read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
+	return (read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
 		ID_PFR0_AMU_MASK;
 }
 
-#if AMU_GROUP1_NR_COUNTERS
-/* Check if group 1 counters is implemented */
-bool amu_group1_supported(void)
+static inline __unused void write_hcptr_tam(uint32_t value)
 {
-	uint32_t features = read_amcfgr() >> AMCFGR_NCG_SHIFT;
+	write_hcptr((read_hcptr() & ~TAM_BIT) |
+		((value << TAM_SHIFT) & TAM_BIT));
+}
 
-	return (features & AMCFGR_NCG_MASK) == 1U;
+static inline __unused void write_amcr_cg1rz(uint32_t value)
+{
+	write_amcr((read_amcr() & ~AMCR_CG1RZ_BIT) |
+		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
+}
+
+static inline __unused uint32_t read_amcfgr_ncg(void)
+{
+	return (read_amcfgr() >> AMCFGR_NCG_SHIFT) &
+		AMCFGR_NCG_MASK;
+}
+
+static inline __unused uint32_t read_amcgcr_cg0nc(void)
+{
+	return (read_amcgcr() >> AMCGCR_CG0NC_SHIFT) &
+		AMCGCR_CG0NC_MASK;
+}
+
+static inline __unused uint32_t read_amcgcr_cg1nc(void)
+{
+	return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
+		AMCGCR_CG1NC_MASK;
+}
+
+static inline __unused uint32_t read_amcntenset0_px(void)
+{
+	return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) &
+		AMCNTENSET0_Pn_MASK;
+}
+
+static inline __unused uint32_t read_amcntenset1_px(void)
+{
+	return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) &
+		AMCNTENSET1_Pn_MASK;
+}
+
+static inline __unused void write_amcntenset0_px(uint32_t px)
+{
+	uint32_t value = read_amcntenset0();
+
+	value &= ~AMCNTENSET0_Pn_MASK;
+	value |= (px << AMCNTENSET0_Pn_SHIFT) &
+		AMCNTENSET0_Pn_MASK;
+
+	write_amcntenset0(value);
+}
+
+static inline __unused void write_amcntenset1_px(uint32_t px)
+{
+	uint32_t value = read_amcntenset1();
+
+	value &= ~AMCNTENSET1_Pn_MASK;
+	value |= (px << AMCNTENSET1_Pn_SHIFT) &
+		AMCNTENSET1_Pn_MASK;
+
+	write_amcntenset1(value);
+}
+
+static inline __unused void write_amcntenclr0_px(uint32_t px)
+{
+	uint32_t value = read_amcntenclr0();
+
+	value &= ~AMCNTENCLR0_Pn_MASK;
+	value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK;
+
+	write_amcntenclr0(value);
+}
+
+static inline __unused void write_amcntenclr1_px(uint32_t px)
+{
+	uint32_t value = read_amcntenclr1();
+
+	value &= ~AMCNTENCLR1_Pn_MASK;
+	value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK;
+
+	write_amcntenclr1(value);
+}
+
+static __unused bool amu_supported(void)
+{
+	return read_id_pfr0_amu() >= ID_PFR0_AMU_V1;
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+static __unused bool amu_group1_supported(void)
+{
+	return read_amcfgr_ncg() > 0U;
 }
 #endif
 
 /*
- * Enable counters. This function is meant to be invoked
- * by the context management library before exiting from EL3.
+ * Enable counters. This function is meant to be invoked by the context
+ * management library before exiting from EL3.
  */
 void amu_enable(bool el2_unused)
 {
-	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
+	uint32_t id_pfr0_amu;		/* AMU version */
+
+	uint32_t amcfgr_ncg;		/* Number of counter groups */
+	uint32_t amcgcr_cg0nc;		/* Number of group 0 counters */
+
+	uint32_t amcntenset0_px = 0x0;	/* Group 0 enable mask */
+	uint32_t amcntenset1_px = 0x0;	/* Group 1 enable mask */
+
+	id_pfr0_amu = read_id_pfr0_amu();
+	if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+		/*
+		 * If the AMU is unsupported, nothing needs to be done.
+		 */
+
 		return;
 	}
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Check and set presence of group 1 counters */
-	if (!amu_group1_supported()) {
-		ERROR("AMU Counter Group 1 is not implemented\n");
-		panic();
-	}
-
-	/* Check number of group 1 counters */
-	uint32_t cnt_num = (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
-				AMCGCR_CG1NC_MASK;
-	VERBOSE("%s%u. %s%u\n",
-		"Number of AMU Group 1 Counters ", cnt_num,
-		"Requested number ", AMU_GROUP1_NR_COUNTERS);
-
-	if (cnt_num < AMU_GROUP1_NR_COUNTERS) {
-		ERROR("%s%u is less than %s%u\n",
-		"Number of AMU Group 1 Counters ", cnt_num,
-		"Requested number ", AMU_GROUP1_NR_COUNTERS);
-		panic();
-	}
-#endif
-
 	if (el2_unused) {
-		uint64_t v;
 		/*
-		 * Non-secure access from EL0 or EL1 to the Activity Monitor
-		 * registers do not trap to EL2.
+		 * HCPTR.TAM: Set to zero so any accesses to the Activity
+		 * Monitor registers do not trap to EL2.
 		 */
-		v = read_hcptr();
-		v &= ~TAM_BIT;
-		write_hcptr(v);
+		write_hcptr_tam(0U);
 	}
 
-	/* Enable group 0 counters */
-	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
+	/*
+	 * Retrieve the number of architected counters. All of these counters
+	 * are enabled by default.
+	 */
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Enable group 1 counters */
-	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
+	amcgcr_cg0nc = read_amcgcr_cg0nc();
+	amcntenset0_px = (UINT32_C(1) << (amcgcr_cg0nc)) - 1U;
+
+	assert(amcgcr_cg0nc <= AMU_AMCGCR_CG0NC_MAX);
+
+	/*
+	 * The platform may opt to enable specific auxiliary counters. This can
+	 * be done via the common FCONF getter, or via the platform-implemented
+	 * function.
+	 */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	const struct amu_topology *topology;
+
+#if ENABLE_AMU_FCONF
+	topology = FCONF_GET_PROPERTY(amu, config, topology);
+#else
+	topology = plat_amu_topology();
+#endif /* ENABLE_AMU_FCONF */
+
+	if (topology != NULL) {
+		unsigned int core_pos = plat_my_core_pos();
+
+		amcntenset1_el0_px = topology->cores[core_pos].enable;
+	} else {
+		ERROR("AMU: failed to generate AMU topology\n");
+	}
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+
+	/*
+	 * Enable the requested counters.
+	 */
+
+	write_amcntenset0_px(amcntenset0_px);
+
+	amcfgr_ncg = read_amcfgr_ncg();
+	if (amcfgr_ncg > 0U) {
+		write_amcntenset1_px(amcntenset1_px);
+
+#if !ENABLE_AMU_AUXILIARY_COUNTERS
+		VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
 #endif
+	}
 
 	/* Initialize FEAT_AMUv1p1 features if present. */
-	if (amu_get_version() < ID_PFR0_AMU_V1P1) {
+	if (id_pfr0_amu < ID_PFR0_AMU_V1P1) {
 		return;
 	}
 
@@ -106,154 +235,183 @@
 	 * mapped view are unaffected.
 	 */
 	VERBOSE("AMU group 1 counter access restricted.\n");
-	write_amcr(read_amcr() | AMCR_CG1RZ_BIT);
+	write_amcr_cg1rz(1U);
 #else
-	write_amcr(read_amcr() & ~AMCR_CG1RZ_BIT);
+	write_amcr_cg1rz(0U);
 #endif
 }
 
 /* Read the group 0 counter identified by the given `idx`. */
-uint64_t amu_group0_cnt_read(unsigned int idx)
+static uint64_t amu_group0_cnt_read(unsigned int idx)
 {
-	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_supported());
+	assert(idx < read_amcgcr_cg0nc());
 
 	return amu_group0_cnt_read_internal(idx);
 }
 
 /* Write the group 0 counter identified by the given `idx` with `val` */
-void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
+static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
 {
-	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_supported());
+	assert(idx < read_amcgcr_cg0nc());
 
 	amu_group0_cnt_write_internal(idx, val);
 	isb();
 }
 
-#if AMU_GROUP1_NR_COUNTERS
+#if ENABLE_AMU_AUXILIARY_COUNTERS
 /* Read the group 1 counter identified by the given `idx` */
-uint64_t amu_group1_cnt_read(unsigned  int idx)
+static uint64_t amu_group1_cnt_read(unsigned  int idx)
 {
-	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
+	assert(amu_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
+	assert(idx < read_amcgcr_cg1nc());
 
 	return amu_group1_cnt_read_internal(idx);
 }
 
 /* Write the group 1 counter identified by the given `idx` with `val` */
-void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
+static void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
 {
-	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
+	assert(amu_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
+	assert(idx < read_amcgcr_cg1nc());
 
 	amu_group1_cnt_write_internal(idx, val);
 	isb();
 }
-
-/*
- * Program the event type register for the given `idx` with
- * the event number `val`
- */
-void amu_group1_set_evtype(unsigned int idx, unsigned int val)
-{
-	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
-	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
-
-	amu_group1_set_evtype_internal(idx, val);
-	isb();
-}
-#endif	/* AMU_GROUP1_NR_COUNTERS */
+#endif
 
 static void *amu_context_save(const void *arg)
 {
-	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
-	unsigned int i;
+	uint32_t i;
 
-	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
-		return (void *)-1;
+	unsigned int core_pos;
+	struct amu_ctx *ctx;
+
+	uint32_t id_pfr0_amu;	/* AMU version */
+	uint32_t amcgcr_cg0nc;	/* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint32_t amcfgr_ncg;	/* Number of counter groups */
+	uint32_t amcgcr_cg1nc;	/* Number of group 1 counters */
+#endif
+
+	id_pfr0_amu = read_id_pfr0_amu();
+	if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+		return (void *)0;
 	}
 
-#if AMU_GROUP1_NR_COUNTERS
-	if (!amu_group1_supported()) {
-		return (void *)-1;
-	}
-#endif
-	/* Assert that group 0/1 counter configuration is what we expect */
-	assert(read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK);
+	core_pos = plat_my_core_pos();
+	ctx = &amu_ctxs_[core_pos];
 
-#if AMU_GROUP1_NR_COUNTERS
-	assert(read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK);
+	amcgcr_cg0nc = read_amcgcr_cg0nc();
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	amcfgr_ncg = read_amcfgr_ncg();
+	amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
 #endif
+
 	/*
-	 * Disable group 0/1 counters to avoid other observers like SCP sampling
-	 * counter values from the future via the memory mapped view.
+	 * Disable all AMU counters.
 	 */
-	write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK);
 
-#if AMU_GROUP1_NR_COUNTERS
-	write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK);
+	ctx->group0_enable = read_amcntenset0_px();
+	write_amcntenclr0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	if (amcfgr_ncg > 0U) {
+		ctx->group1_enable = read_amcntenset1_px();
+		write_amcntenclr1_px(ctx->group1_enable);
+	}
 #endif
-	isb();
 
-	/* Save all group 0 counters */
-	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
+	/*
+	 * Save the counters to the local context.
+	 */
+
+	isb(); /* Ensure counters have been stopped */
+
+	for (i = 0U; i < amcgcr_cg0nc; i++) {
 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
 	}
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Save group 1 counters */
-	for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-		if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
-			ctx->group1_cnts[i] = amu_group1_cnt_read(i);
-		}
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	for (i = 0U; i < amcgcr_cg1nc; i++) {
+		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
 	}
 #endif
+
 	return (void *)0;
 }
 
 static void *amu_context_restore(const void *arg)
 {
-	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
-	unsigned int i;
+	uint32_t i;
 
-	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
-		return (void *)-1;
-	}
+	unsigned int core_pos;
+	struct amu_ctx *ctx;
 
-#if AMU_GROUP1_NR_COUNTERS
-	if (!amu_group1_supported()) {
-		return (void *)-1;
-	}
-#endif
-	/* Counters were disabled in `amu_context_save()` */
-	assert(read_amcntenset0_el0() == 0U);
+	uint32_t id_pfr0_amu;	/* AMU version */
 
-#if AMU_GROUP1_NR_COUNTERS
-	assert(read_amcntenset1_el0() == 0U);
+	uint32_t amcfgr_ncg;	/* Number of counter groups */
+	uint32_t amcgcr_cg0nc;	/* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint32_t amcgcr_cg1nc;	/* Number of group 1 counters */
 #endif
 
-	/* Restore all group 0 counters */
-	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
+	id_pfr0_amu = read_id_pfr0_amu();
+	if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+		return (void *)0;
+	}
+
+	core_pos = plat_my_core_pos();
+	ctx = &amu_ctxs_[core_pos];
+
+	amcfgr_ncg = read_amcfgr_ncg();
+	amcgcr_cg0nc = read_amcgcr_cg0nc();
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
+#endif
+
+	/*
+	 * Sanity check that all counters were disabled when the context was
+	 * previously saved.
+	 */
+
+	assert(read_amcntenset0_px() == 0U);
+
+	if (amcfgr_ncg > 0U) {
+		assert(read_amcntenset1_px() == 0U);
+	}
+
+	/*
+	 * Restore the counter values from the local context.
+	 */
+
+	for (i = 0U; i < amcgcr_cg0nc; i++) {
 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
 	}
 
-	/* Restore group 0 counter configuration */
-	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
-
-#if AMU_GROUP1_NR_COUNTERS
-	/* Restore group 1 counters */
-	for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-		if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
-			amu_group1_cnt_write(i, ctx->group1_cnts[i]);
-		}
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	for (i = 0U; i < amcgcr_cg1nc; i++) {
+		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
 	}
+#endif
 
-	/* Restore group 1 counter configuration */
-	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
+	/*
+	 * Re-enable counters that were disabled during context save.
+	 */
+
+	write_amcntenset0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	if (amcfgr_ncg > 0U) {
+		write_amcntenset1_px(ctx->group1_enable);
+	}
 #endif
 
 	return (void *)0;
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
index d387341..8ac7678 100644
--- a/lib/extensions/amu/aarch32/amu_helpers.S
+++ b/lib/extensions/amu/aarch32/amu_helpers.S
@@ -84,6 +84,7 @@
 	bx		lr
 endfunc amu_group0_cnt_write_internal
 
+#if ENABLE_AMU_AUXILIARY_COUNTERS
 /*
  * uint64_t amu_group1_cnt_read_internal(int idx);
  *
@@ -267,3 +268,4 @@
 	stcopr	r1, AMEVTYPER1F /* index 15 */
 	bx	lr
 endfunc amu_group1_set_evtype_internal
+#endif
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
index 295c0d5..35efd21 100644
--- a/lib/extensions/amu/aarch64/amu.c
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -5,86 +5,218 @@
  */
 
 #include <assert.h>
+#include <cdefs.h>
 #include <stdbool.h>
 
+#include "../amu_private.h"
 #include <arch.h>
 #include <arch_features.h>
 #include <arch_helpers.h>
-
+#include <common/debug.h>
 #include <lib/el3_runtime/pubsub_events.h>
 #include <lib/extensions/amu.h>
-#include <lib/extensions/amu_private.h>
 
 #include <plat/common/platform.h>
 
-static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
+#if ENABLE_AMU_FCONF
+#	include <lib/fconf/fconf.h>
+#	include <lib/fconf/fconf_amu_getter.h>
+#endif
 
-/*
- * Get AMU version value from aa64pfr0.
- * Return values
- *   ID_AA64PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4)
- *   ID_AA64PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6)
- *   ID_AA64PFR0_AMU_NOT_SUPPORTED: not supported
- */
-unsigned int amu_get_version(void)
+#if ENABLE_MPMM
+#	include <lib/mpmm/mpmm.h>
+#endif
+
+struct amu_ctx {
+	uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
+#endif
+
+	/* Architected event counter 1 does not have an offset register */
+	uint64_t group0_voffsets[AMU_GROUP0_MAX_COUNTERS - 1U];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint64_t group1_voffsets[AMU_GROUP1_MAX_COUNTERS];
+#endif
+
+	uint16_t group0_enable;
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint16_t group1_enable;
+#endif
+};
+
+static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
+
+CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
+	amu_ctx_group0_enable_cannot_represent_all_group0_counters);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
+	amu_ctx_group1_enable_cannot_represent_all_group1_counters);
+#endif
+
+static inline __unused uint64_t read_id_aa64pfr0_el1_amu(void)
 {
-	return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+	return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
 		ID_AA64PFR0_AMU_MASK;
 }
 
-#if AMU_GROUP1_NR_COUNTERS
-/* Check if group 1 counters is implemented */
-bool amu_group1_supported(void)
+static inline __unused uint64_t read_hcr_el2_amvoffen(void)
 {
-	uint64_t features = read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT;
+	return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >>
+		HCR_AMVOFFEN_SHIFT;
+}
 
-	return (features & AMCFGR_EL0_NCG_MASK) == 1U;
+static inline __unused void write_cptr_el2_tam(uint64_t value)
+{
+	write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) |
+		((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT));
+}
+
+static inline __unused void write_cptr_el3_tam(cpu_context_t *ctx, uint64_t tam)
+{
+	uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3);
+
+	value &= ~TAM_BIT;
+	value |= (tam << TAM_SHIFT) & TAM_BIT;
+
+	write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, value);
+}
+
+static inline __unused void write_hcr_el2_amvoffen(uint64_t value)
+{
+	write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) |
+		((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT));
+}
+
+static inline __unused void write_amcr_el0_cg1rz(uint64_t value)
+{
+	write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) |
+		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
+}
+
+static inline __unused uint64_t read_amcfgr_el0_ncg(void)
+{
+	return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) &
+		AMCFGR_EL0_NCG_MASK;
+}
+
+static inline __unused uint64_t read_amcgcr_el0_cg0nc(void)
+{
+	return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) &
+		AMCGCR_EL0_CG0NC_MASK;
+}
+
+static inline __unused uint64_t read_amcg1idr_el0_voff(void)
+{
+	return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
+		AMCG1IDR_VOFF_MASK;
+}
+
+static inline __unused uint64_t read_amcgcr_el0_cg1nc(void)
+{
+	return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
+		AMCGCR_EL0_CG1NC_MASK;
+}
+
+static inline __unused uint64_t read_amcntenset0_el0_px(void)
+{
+	return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) &
+		AMCNTENSET0_EL0_Pn_MASK;
+}
+
+static inline __unused uint64_t read_amcntenset1_el0_px(void)
+{
+	return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) &
+		AMCNTENSET1_EL0_Pn_MASK;
+}
+
+static inline __unused void write_amcntenset0_el0_px(uint64_t px)
+{
+	uint64_t value = read_amcntenset0_el0();
+
+	value &= ~AMCNTENSET0_EL0_Pn_MASK;
+	value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK;
+
+	write_amcntenset0_el0(value);
+}
+
+static inline __unused void write_amcntenset1_el0_px(uint64_t px)
+{
+	uint64_t value = read_amcntenset1_el0();
+
+	value &= ~AMCNTENSET1_EL0_Pn_MASK;
+	value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK;
+
+	write_amcntenset1_el0(value);
+}
+
+static inline __unused void write_amcntenclr0_el0_px(uint64_t px)
+{
+	uint64_t value = read_amcntenclr0_el0();
+
+	value &= ~AMCNTENCLR0_EL0_Pn_MASK;
+	value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK;
+
+	write_amcntenclr0_el0(value);
+}
+
+static inline __unused void write_amcntenclr1_el0_px(uint64_t px)
+{
+	uint64_t value = read_amcntenclr1_el0();
+
+	value &= ~AMCNTENCLR1_EL0_Pn_MASK;
+	value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK;
+
+	write_amcntenclr1_el0(value);
+}
+
+static __unused bool amu_supported(void)
+{
+	return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1;
+}
+
+static __unused bool amu_v1p1_supported(void)
+{
+	return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1;
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+static __unused bool amu_group1_supported(void)
+{
+	return read_amcfgr_el0_ncg() > 0U;
 }
 #endif
 
 /*
- * Enable counters. This function is meant to be invoked
- * by the context management library before exiting from EL3.
+ * Enable counters. This function is meant to be invoked by the context
+ * management library before exiting from EL3.
  */
 void amu_enable(bool el2_unused, cpu_context_t *ctx)
 {
-	uint64_t v;
-	unsigned int amu_version = amu_get_version();
+	uint64_t id_aa64pfr0_el1_amu;		/* AMU version */
 
-	if (amu_version == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+	uint64_t amcfgr_el0_ncg;		/* Number of counter groups */
+	uint64_t amcgcr_el0_cg0nc;		/* Number of group 0 counters */
+
+	uint64_t amcntenset0_el0_px = 0x0;	/* Group 0 enable mask */
+	uint64_t amcntenset1_el0_px = 0x0;	/* Group 1 enable mask */
+
+	id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+	if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+		/*
+		 * If the AMU is unsupported, nothing needs to be done.
+		 */
+
 		return;
 	}
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Check and set presence of group 1 counters */
-	if (!amu_group1_supported()) {
-		ERROR("AMU Counter Group 1 is not implemented\n");
-		panic();
-	}
-
-	/* Check number of group 1 counters */
-	uint64_t cnt_num = (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
-				AMCGCR_EL0_CG1NC_MASK;
-	VERBOSE("%s%llu. %s%u\n",
-		"Number of AMU Group 1 Counters ", cnt_num,
-		"Requested number ", AMU_GROUP1_NR_COUNTERS);
-
-	if (cnt_num < AMU_GROUP1_NR_COUNTERS) {
-		ERROR("%s%llu is less than %s%u\n",
-		"Number of AMU Group 1 Counters ", cnt_num,
-		"Requested number ", AMU_GROUP1_NR_COUNTERS);
-		panic();
-	}
-#endif
-
 	if (el2_unused) {
 		/*
-		 * CPTR_EL2.TAM: Set to zero so any accesses to
-		 * the Activity Monitor registers do not trap to EL2.
+		 * CPTR_EL2.TAM: Set to zero so any accesses to the Activity
+		 * Monitor registers do not trap to EL2.
 		 */
-		v = read_cptr_el2();
-		v &= ~CPTR_EL2_TAM_BIT;
-		write_cptr_el2(v);
+		write_cptr_el2_tam(0U);
 	}
 
 	/*
@@ -92,72 +224,141 @@
 	 * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to
 	 * the Activity Monitor registers do not trap to EL3.
 	 */
-	v = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3);
-	v &= ~TAM_BIT;
-	write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, v);
+	write_cptr_el3_tam(ctx, 0U);
 
-	/* Enable group 0 counters */
-	write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK);
+	/*
+	 * Retrieve the number of architected counters. All of these counters
+	 * are enabled by default.
+	 */
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Enable group 1 counters */
-	write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK);
+	amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+	amcntenset0_el0_px = (UINT64_C(1) << (amcgcr_el0_cg0nc)) - 1U;
+
+	assert(amcgcr_el0_cg0nc <= AMU_AMCGCR_CG0NC_MAX);
+
+	/*
+	 * The platform may opt to enable specific auxiliary counters. This can
+	 * be done via the common FCONF getter, or via the platform-implemented
+	 * function.
+	 */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	const struct amu_topology *topology;
+
+#if ENABLE_AMU_FCONF
+	topology = FCONF_GET_PROPERTY(amu, config, topology);
+#else
+	topology = plat_amu_topology();
+#endif /* ENABLE_AMU_FCONF */
+
+	if (topology != NULL) {
+		unsigned int core_pos = plat_my_core_pos();
+
+		amcntenset1_el0_px = topology->cores[core_pos].enable;
+	} else {
+		ERROR("AMU: failed to generate AMU topology\n");
+	}
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+
+	/*
+	 * Enable the requested counters.
+	 */
+
+	write_amcntenset0_el0_px(amcntenset0_el0_px);
+
+	amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+	if (amcfgr_el0_ncg > 0U) {
+		write_amcntenset1_el0_px(amcntenset1_el0_px);
+
+#if !ENABLE_AMU_AUXILIARY_COUNTERS
+		VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
 #endif
+	}
 
 	/* Initialize FEAT_AMUv1p1 features if present. */
-	if (amu_version < ID_AA64PFR0_AMU_V1P1) {
-		return;
-	}
-
-	if (el2_unused) {
-		/* Make sure virtual offsets are disabled if EL2 not used. */
-		write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT);
-	}
+	if (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) {
+		if (el2_unused) {
+			/*
+			 * Make sure virtual offsets are disabled if EL2 not
+			 * used.
+			 */
+			write_hcr_el2_amvoffen(0U);
+		}
 
 #if AMU_RESTRICT_COUNTERS
-	/*
-	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
-	 * counters at all but the highest implemented EL.  This is controlled
-	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
-	 * register reads at lower ELs return zero.  Reads from the memory
-	 * mapped view are unaffected.
-	 */
-	VERBOSE("AMU group 1 counter access restricted.\n");
-	write_amcr_el0(read_amcr_el0() | AMCR_CG1RZ_BIT);
+		/*
+		 * FEAT_AMUv1p1 adds a register field to restrict access to
+		 * group 1 counters at all but the highest implemented EL. This
+		 * is controlled with the `AMU_RESTRICT_COUNTERS` compile time
+		 * flag, when set, system register reads at lower ELs return
+		 * zero. Reads from the memory mapped view are unaffected.
+		 */
+		VERBOSE("AMU group 1 counter access restricted.\n");
+		write_amcr_el0_cg1rz(1U);
 #else
-	write_amcr_el0(read_amcr_el0() & ~AMCR_CG1RZ_BIT);
+		write_amcr_el0_cg1rz(0U);
+#endif
+	}
+
+#if ENABLE_MPMM
+	mpmm_enable();
 #endif
 }
 
 /* Read the group 0 counter identified by the given `idx`. */
-uint64_t amu_group0_cnt_read(unsigned int idx)
+static uint64_t amu_group0_cnt_read(unsigned int idx)
 {
-	assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_supported());
+	assert(idx < read_amcgcr_el0_cg0nc());
 
 	return amu_group0_cnt_read_internal(idx);
 }
 
 /* Write the group 0 counter identified by the given `idx` with `val` */
-void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
+static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
 {
-	assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_supported());
+	assert(idx < read_amcgcr_el0_cg0nc());
 
 	amu_group0_cnt_write_internal(idx, val);
 	isb();
 }
 
 /*
+ * Unlike with auxiliary counters, we cannot detect at runtime whether an
+ * architected counter supports a virtual offset. These are instead fixed
+ * according to FEAT_AMUv1p1, but this switch will need to be updated if later
+ * revisions of FEAT_AMU add additional architected counters.
+ */
+static bool amu_group0_voffset_supported(uint64_t idx)
+{
+	switch (idx) {
+	case 0U:
+	case 2U:
+	case 3U:
+		return true;
+
+	case 1U:
+		return false;
+
+	default:
+		ERROR("AMU: can't set up virtual offset for unknown "
+		      "architected counter %llu!\n", idx);
+
+		panic();
+	}
+}
+
+/*
  * Read the group 0 offset register for a given index. Index must be 0, 2,
  * or 3, the register for 1 does not exist.
  *
  * Using this function requires FEAT_AMUv1p1 support.
  */
-uint64_t amu_group0_voffset_read(unsigned int idx)
+static uint64_t amu_group0_voffset_read(unsigned int idx)
 {
-	assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_v1p1_supported());
+	assert(idx < read_amcgcr_el0_cg0nc());
 	assert(idx != 1U);
 
 	return amu_group0_voffset_read_internal(idx);
@@ -169,33 +370,33 @@
  *
  * Using this function requires FEAT_AMUv1p1 support.
  */
-void amu_group0_voffset_write(unsigned int idx, uint64_t val)
+static void amu_group0_voffset_write(unsigned int idx, uint64_t val)
 {
-	assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1);
-	assert(idx < AMU_GROUP0_NR_COUNTERS);
+	assert(amu_v1p1_supported());
+	assert(idx < read_amcgcr_el0_cg0nc());
 	assert(idx != 1U);
 
 	amu_group0_voffset_write_internal(idx, val);
 	isb();
 }
 
-#if AMU_GROUP1_NR_COUNTERS
+#if ENABLE_AMU_AUXILIARY_COUNTERS
 /* Read the group 1 counter identified by the given `idx` */
-uint64_t amu_group1_cnt_read(unsigned int idx)
+static uint64_t amu_group1_cnt_read(unsigned int idx)
 {
-	assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED);
+	assert(amu_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
+	assert(idx < read_amcgcr_el0_cg1nc());
 
 	return amu_group1_cnt_read_internal(idx);
 }
 
 /* Write the group 1 counter identified by the given `idx` with `val` */
-void amu_group1_cnt_write(unsigned int idx, uint64_t val)
+static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
 {
-	assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED);
+	assert(amu_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
+	assert(idx < read_amcgcr_el0_cg1nc());
 
 	amu_group1_cnt_write_internal(idx, val);
 	isb();
@@ -206,13 +407,12 @@
  *
  * Using this function requires FEAT_AMUv1p1 support.
  */
-uint64_t amu_group1_voffset_read(unsigned int idx)
+static uint64_t amu_group1_voffset_read(unsigned int idx)
 {
-	assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1);
+	assert(amu_v1p1_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
-	assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
-		(1ULL << idx)) != 0ULL);
+	assert(idx < read_amcgcr_el0_cg1nc());
+	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
 
 	return amu_group1_voffset_read_internal(idx);
 }
@@ -222,167 +422,211 @@
  *
  * Using this function requires FEAT_AMUv1p1 support.
  */
-void amu_group1_voffset_write(unsigned int idx, uint64_t val)
+static void amu_group1_voffset_write(unsigned int idx, uint64_t val)
 {
-	assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1);
+	assert(amu_v1p1_supported());
 	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
-	assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
-		(1ULL << idx)) != 0ULL);
+	assert(idx < read_amcgcr_el0_cg1nc());
+	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
 
 	amu_group1_voffset_write_internal(idx, val);
 	isb();
 }
-
-/*
- * Program the event type register for the given `idx` with
- * the event number `val`
- */
-void amu_group1_set_evtype(unsigned int idx, unsigned int val)
-{
-	assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED);
-	assert(amu_group1_supported());
-	assert(idx < AMU_GROUP1_NR_COUNTERS);
-
-	amu_group1_set_evtype_internal(idx, val);
-	isb();
-}
-#endif	/* AMU_GROUP1_NR_COUNTERS */
+#endif
 
 static void *amu_context_save(const void *arg)
 {
-	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
-	unsigned int i;
+	uint64_t i, j;
 
-	if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
-		return (void *)-1;
+	unsigned int core_pos;
+	struct amu_ctx *ctx;
+
+	uint64_t id_aa64pfr0_el1_amu;	/* AMU version */
+	uint64_t hcr_el2_amvoffen;	/* AMU virtual offsets enabled */
+	uint64_t amcgcr_el0_cg0nc;	/* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint64_t amcg1idr_el0_voff;	/* Auxiliary counters with virtual offsets */
+	uint64_t amcfgr_el0_ncg;	/* Number of counter groups */
+	uint64_t amcgcr_el0_cg1nc;	/* Number of group 1 counters */
+#endif
+
+	id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+	if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+		return (void *)0;
 	}
 
-#if AMU_GROUP1_NR_COUNTERS
-	if (!amu_group1_supported()) {
-		return (void *)-1;
-	}
-#endif
-	/* Assert that group 0/1 counter configuration is what we expect */
-	assert(read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK);
+	core_pos = plat_my_core_pos();
+	ctx = &amu_ctxs_[core_pos];
 
-#if AMU_GROUP1_NR_COUNTERS
-	assert(read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK);
+	amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+	hcr_el2_amvoffen = (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) ?
+		read_hcr_el2_amvoffen() : 0U;
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+	amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
+	amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
 #endif
+
 	/*
-	 * Disable group 0/1 counters to avoid other observers like SCP sampling
-	 * counter values from the future via the memory mapped view.
+	 * Disable all AMU counters.
 	 */
-	write_amcntenclr0_el0(AMU_GROUP0_COUNTERS_MASK);
 
-#if AMU_GROUP1_NR_COUNTERS
-	write_amcntenclr1_el0(AMU_GROUP1_COUNTERS_MASK);
+	ctx->group0_enable = read_amcntenset0_el0_px();
+	write_amcntenclr0_el0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	if (amcfgr_el0_ncg > 0U) {
+		ctx->group1_enable = read_amcntenset1_el0_px();
+		write_amcntenclr1_el0_px(ctx->group1_enable);
+	}
 #endif
-	isb();
 
-	/* Save all group 0 counters */
-	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
+	/*
+	 * Save the counters to the local context.
+	 */
+
+	isb(); /* Ensure counters have been stopped */
+
+	for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
 	}
 
-	/* Save group 0 virtual offsets if supported and enabled. */
-	if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) &&
-			((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) {
-		/* Not using a loop because count is fixed and index 1 DNE. */
-		ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U);
-		ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U);
-		ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U);
-	}
-
-#if AMU_GROUP1_NR_COUNTERS
-	/* Save group 1 counters */
-	for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-		if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
-			ctx->group1_cnts[i] = amu_group1_cnt_read(i);
-		}
-	}
-
-	/* Save group 1 virtual offsets if supported and enabled. */
-	if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) &&
-			((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) {
-		u_register_t amcg1idr = read_amcg1idr_el0() >>
-			AMCG1IDR_VOFF_SHIFT;
-		amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK;
-
-		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-			if (((amcg1idr >> i) & 1ULL) != 0ULL) {
-				ctx->group1_voffsets[i] =
-					amu_group1_voffset_read(i);
-			}
-		}
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
+		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
 	}
 #endif
+
+	/*
+	 * Save virtual offsets for counters that offer them.
+	 */
+
+	if (hcr_el2_amvoffen != 0U) {
+		for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
+			if (!amu_group0_voffset_supported(i)) {
+				continue; /* No virtual offset */
+			}
+
+			ctx->group0_voffsets[j++] = amu_group0_voffset_read(i);
+		}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+		for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
+			if ((amcg1idr_el0_voff >> i) & 1U) {
+				continue; /* No virtual offset */
+			}
+
+			ctx->group1_voffsets[j++] = amu_group1_voffset_read(i);
+		}
+#endif
+	}
+
 	return (void *)0;
 }
 
 static void *amu_context_restore(const void *arg)
 {
-	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
-	unsigned int i;
+	uint64_t i, j;
 
-	if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
-		return (void *)-1;
-	}
+	unsigned int core_pos;
+	struct amu_ctx *ctx;
 
-#if AMU_GROUP1_NR_COUNTERS
-	if (!amu_group1_supported()) {
-		return (void *)-1;
-	}
-#endif
-	/* Counters were disabled in `amu_context_save()` */
-	assert(read_amcntenset0_el0() == 0U);
+	uint64_t id_aa64pfr0_el1_amu;	/* AMU version */
 
-#if AMU_GROUP1_NR_COUNTERS
-	assert(read_amcntenset1_el0() == 0U);
+	uint64_t hcr_el2_amvoffen;	/* AMU virtual offsets enabled */
+
+	uint64_t amcfgr_el0_ncg;	/* Number of counter groups */
+	uint64_t amcgcr_el0_cg0nc;	/* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	uint64_t amcgcr_el0_cg1nc;	/* Number of group 1 counters */
+	uint64_t amcg1idr_el0_voff;	/* Auxiliary counters with virtual offsets */
 #endif
 
-	/* Restore all group 0 counters */
-	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
+	id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+	if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+		return (void *)0;
+	}
+
+	core_pos = plat_my_core_pos();
+	ctx = &amu_ctxs_[core_pos];
+
+	amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+	amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+
+	hcr_el2_amvoffen = (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) ?
+		read_hcr_el2_amvoffen() : 0U;
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
+	amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
+#endif
+
+	/*
+	 * Sanity check that all counters were disabled when the context was
+	 * previously saved.
+	 */
+
+	assert(read_amcntenset0_el0_px() == 0U);
+
+	if (amcfgr_el0_ncg > 0U) {
+		assert(read_amcntenset1_el0_px() == 0U);
+	}
+
+	/*
+	 * Restore the counter values from the local context.
+	 */
+
+	for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
 	}
 
-	/* Restore group 0 virtual offsets if supported and enabled. */
-	if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) &&
-			((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) {
-		/* Not using a loop because count is fixed and index 1 DNE. */
-		amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]);
-		amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]);
-		amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]);
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
+		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
 	}
+#endif
 
-	/* Restore group 0 counter configuration */
-	write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK);
+	/*
+	 * Restore virtual offsets for counters that offer them.
+	 */
 
-#if AMU_GROUP1_NR_COUNTERS
-	/* Restore group 1 counters */
-	for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-		if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
-			amu_group1_cnt_write(i, ctx->group1_cnts[i]);
-		}
-	}
-
-	/* Restore group 1 virtual offsets if supported and enabled. */
-	if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) &&
-			((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) {
-		u_register_t amcg1idr = read_amcg1idr_el0() >>
-			AMCG1IDR_VOFF_SHIFT;
-		amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK;
-
-		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
-			if (((amcg1idr >> i) & 1ULL) != 0ULL) {
-				amu_group1_voffset_write(i,
-					ctx->group1_voffsets[i]);
+	if (hcr_el2_amvoffen != 0U) {
+		for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
+			if (!amu_group0_voffset_supported(i)) {
+				continue; /* No virtual offset */
 			}
+
+			amu_group0_voffset_write(i, ctx->group0_voffsets[j++]);
 		}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+		for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
+			if ((amcg1idr_el0_voff >> i) & 1U) {
+				continue; /* No virtual offset */
+			}
+
+			amu_group1_voffset_write(i, ctx->group1_voffsets[j++]);
+		}
+#endif
 	}
 
-	/* Restore group 1 counter configuration */
-	write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK);
+	/*
+	 * Re-enable counters that were disabled during context save.
+	 */
+
+	write_amcntenset0_el0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	if (amcfgr_el0_ncg > 0) {
+		write_amcntenset1_el0_px(ctx->group1_enable);
+	}
+#endif
+
+#if ENABLE_MPMM
+	mpmm_enable();
 #endif
 
 	return (void *)0;
diff --git a/lib/extensions/amu/aarch64/amu_helpers.S b/lib/extensions/amu/aarch64/amu_helpers.S
index 9989abd..0f6d799 100644
--- a/lib/extensions/amu/aarch64/amu_helpers.S
+++ b/lib/extensions/amu/aarch64/amu_helpers.S
@@ -83,6 +83,7 @@
 	write	AMEVCNTR03_EL0		/* index 3 */
 endfunc amu_group0_cnt_write_internal
 
+#if ENABLE_AMU_AUXILIARY_COUNTERS
 /*
  * uint64_t amu_group1_cnt_read_internal(int idx);
  *
@@ -217,6 +218,7 @@
 	write	AMEVTYPER1E_EL0		/* index 14 */
 	write	AMEVTYPER1F_EL0		/* index 15 */
 endfunc amu_group1_set_evtype_internal
+#endif
 
 /*
  * Accessor functions for virtual offset registers added with FEAT_AMUv1p1
@@ -297,6 +299,7 @@
 	write	AMEVCNTVOFF03_EL2	/* index 3 */
 endfunc amu_group0_voffset_write_internal
 
+#if ENABLE_AMU_AUXILIARY_COUNTERS
 /*
  * uint64_t amu_group1_voffset_read_internal(int idx);
  *
@@ -383,3 +386,4 @@
 	write	AMEVCNTVOFF1E_EL2	/* index 14 */
 	write	AMEVCNTVOFF1F_EL2	/* index 15 */
 endfunc amu_group1_voffset_write_internal
+#endif
diff --git a/lib/extensions/amu/amu.mk b/lib/extensions/amu/amu.mk
new file mode 100644
index 0000000..0d203cb
--- /dev/null
+++ b/lib/extensions/amu/amu.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/fconf/fconf.mk
+
+AMU_SOURCES	:=	lib/extensions/amu/${ARCH}/amu.c \
+			lib/extensions/amu/${ARCH}/amu_helpers.S
+
+ifneq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
+        ifeq (${ENABLE_AMU},0)
+                $(error AMU auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) requires AMU support (`ENABLE_AMU`))
+        endif
+endif
+
+ifneq (${ENABLE_AMU_FCONF},0)
+        ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
+                $(error AMU FCONF support (`ENABLE_AMU_FCONF`) is not necessary when auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) is disabled)
+        endif
+
+        AMU_SOURCES	+=	${FCONF_AMU_SOURCES}
+endif
diff --git a/lib/extensions/amu/amu_fconf.c b/lib/extensions/amu/amu_fconf.c
new file mode 100644
index 0000000..c7fb803
--- /dev/null
+++ b/lib/extensions/amu/amu_fconf.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "amu_private.h"
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/extensions/amu.h>
+#include <lib/fconf/fconf.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+
+static bool amu_topology_populated_ ; /* Whether the topology is valid */
+static struct amu_fconf_topology amu_topology_; /* Populated topology cache */
+
+const struct amu_fconf_topology *amu_topology(void)
+{
+	if (!amu_topology_populated_) {
+		return NULL;
+	}
+
+	return &amu_topology_;
+}
+
+/*
+ * Populate the core-specific AMU structure with information retrieved from a
+ * device tree.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int amu_fconf_populate_cpu_amu(const void *fdt, int parent,
+				      struct amu_fconf_core *amu)
+{
+	int ret = 0;
+	int node = 0;
+
+	fdt_for_each_subnode(node, fdt, parent) {
+		const char *name;
+		const char *value;
+		int len;
+
+		uintptr_t idx = 0U;
+
+		name = fdt_get_name(fdt, node, &len);
+		if (strncmp(name, "counter@", 8) != 0) {
+			continue;
+		}
+
+		ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL);
+		if (ret < 0) {
+			break;
+		}
+
+		value = fdt_getprop(fdt, node, "enable-at-el3", &len);
+		if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) {
+			break;
+		}
+
+		if (len != -FDT_ERR_NOTFOUND) {
+			amu->enable |= (1 << idx);
+		}
+	}
+
+	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
+		return node;
+	}
+
+	return ret;
+}
+
+/*
+ * Within a `cpu` node, attempt to dereference the `amu` property, and populate
+ * the AMU information for the core.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int amu_fconf_populate_cpu(const void *fdt, int node, uintptr_t mpidr)
+{
+	int ret;
+	int idx;
+
+	uint32_t amu_phandle;
+	struct amu_fconf_core *amu;
+
+	ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle);
+	if (ret < 0) {
+		if (ret == -FDT_ERR_NOTFOUND) {
+			ret = 0;
+		}
+
+		return ret;
+	}
+
+	node = fdt_node_offset_by_phandle(fdt, amu_phandle);
+	if (node < 0) {
+		return node;
+	}
+
+	idx = plat_core_pos_by_mpidr(mpidr);
+	amu = &amu_topology_.cores[idx];
+
+	return amu_fconf_populate_cpu_amu(fdt, node, amu);
+}
+
+/*
+ * For every CPU node (`/cpus/cpu@n`) in an FDT, executes a callback passing a
+ * pointer to the FDT and the offset of the CPU node. If the return value of the
+ * callback is negative, it is treated as an error and the loop is aborted. In
+ * this situation, the value of the callback is returned from the function.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int amu_fconf_foreach_cpu(const void *fdt,
+				 int (*callback)(const void *, int, uintptr_t))
+{
+	int ret = 0;
+	int parent, node = 0;
+
+	parent = fdt_path_offset(fdt, "/cpus");
+	if (parent < 0) {
+		if (parent == -FDT_ERR_NOTFOUND) {
+			parent = 0;
+		}
+
+		return parent;
+	}
+
+	fdt_for_each_subnode(node, fdt, parent) {
+		const char *name;
+		int len;
+
+		uintptr_t mpidr = 0U;
+
+		name = fdt_get_name(fdt, node, &len);
+		if (strncmp(name, "cpu@", 4) != 0) {
+			continue;
+		}
+
+		ret = fdt_get_reg_props_by_index(fdt, node, 0, &mpidr, NULL);
+		if (ret < 0) {
+			break;
+		}
+
+		ret = callback(fdt, node, mpidr);
+		if (ret < 0) {
+			break;
+		}
+	}
+
+	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
+		return node;
+	}
+
+	return ret;
+}
+
+/*
+ * Populates the global `amu_topology` structure based on what's described by
+ * the hardware configuration device tree blob.
+ *
+ * The device tree is expected to provide an `amu` property for each `cpu` node,
+ * like so:
+ *
+ *     cpu@0 {
+ *         amu = <&cpu0_amu>;
+ *     };
+ *
+ *     amus {
+ *         cpu0_amu: amu-0 {
+ *             counters {
+ *                 #address-cells = <2>;
+ *                 #size-cells = <0>;
+ *
+ *                 counter@x,y {
+ *                     reg = <x y>; // Group x, counter y
+ *                 };
+ *             };
+ *         };
+ *     };
+ */
+static int amu_fconf_populate(uintptr_t config)
+{
+	int ret = amu_fconf_foreach_cpu(
+		(const void *)config, amu_fconf_populate_cpu);
+	if (ret < 0) {
+		ERROR("AMU-FCONF: Failed to configure AMU: %d\n", ret);
+	} else {
+		amu_topology_populated_ = true;
+	}
+
+	return ret;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, amu_fconf_populate);
diff --git a/include/lib/extensions/amu_private.h b/lib/extensions/amu/amu_private.h
similarity index 78%
rename from include/lib/extensions/amu_private.h
rename to lib/extensions/amu/amu_private.h
index 3b4b47c..eb7ff0e 100644
--- a/include/lib/extensions/amu_private.h
+++ b/lib/extensions/amu/amu_private.h
@@ -9,6 +9,17 @@
 
 #include <stdint.h>
 
+#include <lib/cassert.h>
+#include <lib/extensions/amu.h>
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define AMU_GROUP0_MAX_COUNTERS		U(16)
+#define AMU_GROUP1_MAX_COUNTERS		U(16)
+
+#define AMU_AMCGCR_CG0NC_MAX		U(16)
+
 uint64_t amu_group0_cnt_read_internal(unsigned int idx);
 void amu_group0_cnt_write_internal(unsigned int idx, uint64_t val);
 
diff --git a/lib/fconf/fconf.mk b/lib/fconf/fconf.mk
index b01dc6f..fb88910 100644
--- a/lib/fconf/fconf.mk
+++ b/lib/fconf/fconf.mk
@@ -1,12 +1,19 @@
 #
-# Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+# Copyright (c) 2019-2021, ARM Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
-# Add Firmware Configuration files
-FCONF_SOURCES		:=	lib/fconf/fconf.c
-FCONF_DYN_SOURCES	:=	lib/fconf/fconf_dyn_cfg_getter.c
+include common/fdt_wrappers.mk
 
-BL1_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
-BL2_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+FCONF_SOURCES		:=	lib/fconf/fconf.c
+FCONF_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
+FCONF_DYN_SOURCES	:=	lib/fconf/fconf_dyn_cfg_getter.c
+FCONF_DYN_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
+
+FCONF_AMU_SOURCES	:=	lib/fconf/fconf_amu_getter.c
+FCONF_AMU_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
+
+FCONF_MPMM_SOURCES	:=	lib/fconf/fconf_mpmm_getter.c
+FCONF_MPMM_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
diff --git a/lib/fconf/fconf_amu_getter.c b/lib/fconf/fconf_amu_getter.c
new file mode 100644
index 0000000..eff309c
--- /dev/null
+++ b/lib/fconf/fconf_amu_getter.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_amu_getter.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+
+struct fconf_amu_config fconf_amu_config;
+static struct amu_topology fconf_amu_topology_;
+
+/*
+ * Populate the core-specific AMU structure with information retrieved from a
+ * device tree.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_amu_cpu_amu(const void *fdt, int parent,
+				      struct amu_core *amu)
+{
+	int ret = 0;
+	int node = 0;
+
+	fdt_for_each_subnode(node, fdt, parent) {
+		const char *name;
+		const char *value;
+		int len;
+
+		uintptr_t idx = 0U;
+
+		name = fdt_get_name(fdt, node, &len);
+		if (strncmp(name, "counter@", 8) != 0) {
+			continue;
+		}
+
+		ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL);
+		if (ret < 0) {
+			break;
+		}
+
+		value = fdt_getprop(fdt, node, "enable-at-el3", &len);
+		if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) {
+			break;
+		}
+
+		if (len != -FDT_ERR_NOTFOUND) {
+			amu->enable |= (1 << idx);
+		}
+	}
+
+	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
+		return node;
+	}
+
+	return ret;
+}
+
+/*
+ * Within a `cpu` node, attempt to dereference the `amu` property, and populate
+ * the AMU information for the core.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_amu_cpu(const void *fdt, int node, uintptr_t mpidr)
+{
+	int ret;
+	int idx;
+
+	uint32_t amu_phandle;
+	struct amu_core *amu;
+
+	ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle);
+	if (ret < 0) {
+		if (ret == -FDT_ERR_NOTFOUND) {
+			ret = 0;
+		}
+
+		return ret;
+	}
+
+	node = fdt_node_offset_by_phandle(fdt, amu_phandle);
+	if (node < 0) {
+		return node;
+	}
+
+	idx = plat_core_pos_by_mpidr(mpidr);
+	if (idx < 0) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	amu = &fconf_amu_topology_.cores[idx];
+
+	return fconf_populate_amu_cpu_amu(fdt, node, amu);
+}
+
+/*
+ * Populates the global `amu_topology` structure based on what's described by
+ * the hardware configuration device tree blob.
+ *
+ * The device tree is expected to provide an `amu` property for each `cpu` node,
+ * like so:
+ *
+ *     cpu@0 {
+ *         amu = <&cpu0_amu>;
+ *     };
+ *
+ *     amus {
+ *         cpu0_amu: amu-0 {
+ *             counters {
+ *                 #address-cells = <2>;
+ *                 #size-cells = <0>;
+ *
+ *                 counter@x,y {
+ *                     reg = <x y>; // Group x, counter y
+ *                 };
+ *             };
+ *         };
+ *     };
+ */
+static int fconf_populate_amu(uintptr_t config)
+{
+	int ret = fdtw_for_each_cpu(
+		(const void *)config, fconf_populate_amu_cpu);
+	if (ret == 0) {
+		fconf_amu_config.topology = &fconf_amu_topology_;
+	} else {
+		ERROR("FCONF: failed to parse AMU information: %d\n", ret);
+	}
+
+	return ret;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, fconf_populate_amu);
diff --git a/lib/fconf/fconf_mpmm_getter.c b/lib/fconf/fconf_mpmm_getter.c
new file mode 100644
index 0000000..02a566d
--- /dev/null
+++ b/lib/fconf/fconf_mpmm_getter.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_mpmm_getter.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+
+struct fconf_mpmm_config fconf_mpmm_config;
+static struct mpmm_topology fconf_mpmm_topology;
+
+/*
+ * Within a `cpu` node, determine support for MPMM via the `supports-mpmm`
+ * property.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_mpmm_cpu(const void *fdt, int off, uintptr_t mpidr)
+{
+	int ret, len;
+
+	int core_pos;
+	struct mpmm_core *core;
+
+	core_pos = plat_core_pos_by_mpidr(mpidr);
+	if (core_pos < 0) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	core = &fconf_mpmm_topology.cores[core_pos];
+
+	fdt_getprop(fdt, off, "supports-mpmm", &len);
+	if (len >= 0) {
+		core->supported = true;
+		ret = 0;
+	} else {
+		core->supported = false;
+		ret = len;
+	}
+
+	return ret;
+}
+
+/*
+ * Populates the global `fconf_mpmm_config` structure based on what's described
+ * by the hardware configuration device tree blob.
+ *
+ * The device tree is expected to provide a `supports-mpmm` property for each
+ * `cpu` node, like so:
+ *
+ *     cpu@0 {
+ *       supports-mpmm;
+ *     };
+ *
+ * This property indicates whether the core implements MPMM, as we cannot detect
+ * support for it dynamically.
+ */
+static int fconf_populate_mpmm(uintptr_t config)
+{
+	int ret = fdtw_for_each_cpu(
+		(const void *)config, fconf_populate_mpmm_cpu);
+	if (ret == 0) {
+		fconf_mpmm_config.topology = &fconf_mpmm_topology;
+	} else {
+		ERROR("FCONF: failed to configure MPMM: %d\n", ret);
+	}
+
+	return ret;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, mpmm, fconf_populate_mpmm);
diff --git a/lib/mpmm/mpmm.c b/lib/mpmm/mpmm.c
new file mode 100644
index 0000000..a66f2aa
--- /dev/null
+++ b/lib/mpmm/mpmm.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mpmm/mpmm.h>
+
+#include <plat/common/platform.h>
+
+#if ENABLE_MPMM_FCONF
+#	include <lib/fconf/fconf.h>
+#	include <lib/fconf/fconf_mpmm_getter.h>
+#endif
+
+static uint64_t read_cpuppmcr_el3_mpmmpinctl(void)
+{
+	return (read_cpuppmcr_el3() >> CPUPPMCR_EL3_MPMMPINCTL_SHIFT) &
+		CPUPPMCR_EL3_MPMMPINCTL_MASK;
+}
+
+static void write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en)
+{
+	uint64_t value = read_cpumpmmcr_el3();
+
+	value &= ~(CPUMPMMCR_EL3_MPMM_EN_MASK << CPUMPMMCR_EL3_MPMM_EN_SHIFT);
+	value |= (mpmm_en & CPUMPMMCR_EL3_MPMM_EN_MASK) <<
+		CPUMPMMCR_EL3_MPMM_EN_SHIFT;
+
+	write_cpumpmmcr_el3(value);
+}
+
+static bool mpmm_supported(void)
+{
+	bool supported = false;
+	const struct mpmm_topology *topology;
+
+#if ENABLE_MPMM_FCONF
+	topology = FCONF_GET_PROPERTY(mpmm, config, topology);
+#else
+	topology = plat_mpmm_topology();
+#endif /* ENABLE_MPMM_FCONF */
+
+	/*
+	 * For the current core firstly try to find out if the platform
+	 * configuration has claimed support for MPMM, then make sure that MPMM
+	 * is controllable through the system registers.
+	 */
+
+	if (topology != NULL) {
+		unsigned int core_pos = plat_my_core_pos();
+
+		supported = topology->cores[core_pos].supported &&
+			(read_cpuppmcr_el3_mpmmpinctl() == 0U);
+	} else {
+		ERROR("MPMM: failed to generate MPMM topology\n");
+	}
+
+	return supported;
+}
+
+void mpmm_enable(void)
+{
+	bool supported = mpmm_supported();
+
+	if (supported) {
+		write_cpumpmmcr_el3_mpmm_en(1U);
+	}
+}
diff --git a/lib/mpmm/mpmm.mk b/lib/mpmm/mpmm.mk
new file mode 100644
index 0000000..826f925
--- /dev/null
+++ b/lib/mpmm/mpmm.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/extensions/amu/amu.mk
+include lib/fconf/fconf.mk
+
+ifneq (${ENABLE_MPMM},0)
+        ifneq ($(ARCH),aarch64)
+                $(error MPMM support (`ENABLE_MPMM`) can only be enabled in AArch64 images (`ARCH`))
+        endif
+
+        ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0) # For MPMM gear AMU counters
+                $(error MPMM support (`ENABLE_MPM`) requires auxiliary AMU counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`))
+        endif
+endif
+
+MPMM_SOURCES	:=	lib/mpmm/mpmm.c
+MPMM_SOURCES	+=	${AMU_SOURCES}
+
+ifneq (${ENABLE_MPMM_FCONF},0)
+        ifeq (${ENABLE_MPMM},0)
+                $(error MPMM FCONF support (`ENABLE_MPMM_FCONF`) requires MPMM support (`ENABLE_MPMM`))
+        endif
+
+        MPMM_SOURCES	+= ${FCONF_MPMM_SOURCES}
+endif
diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c
index d090b38..72979cd 100644
--- a/lib/optee/optee_utils.c
+++ b/lib/optee/optee_utils.c
@@ -82,11 +82,14 @@
 	init_size = image->size;
 
 	/*
-	 * -1 indicates loader decided address; take our pre-mapped area
-	 * for current image since arm-tf could not allocate memory dynamically
+	 * image->load_addr_hi & image->load_addr_lo set to UINT32_MAX indicate
+	 * loader decided address; take our pre-mapped area for current image
+	 * since arm-tf could not allocate memory dynamically
 	 */
-	if (init_load_addr == -1)
+	if ((image->load_addr_hi == UINT32_MAX) &&
+	    (image->load_addr_lo == UINT32_MAX)) {
 		init_load_addr = image_info->image_base;
+	}
 
 	/* Check that the default end address doesn't overflow */
 	if (check_uptr_overflow(image_info->image_base,
@@ -138,7 +141,8 @@
 
 {
 	optee_header_t *header;
-	int num, ret;
+	uint32_t num;
+	int ret;
 
 	assert(header_ep);
 	header = (optee_header_t *)header_ep->pc;
@@ -181,7 +185,7 @@
 	}
 
 	/* Parse OPTEE image */
-	for (num = 0; num < header->nb_images; num++) {
+	for (num = 0U; num < header->nb_images; num++) {
 		if (header->optee_image_list[num].image_id ==
 				OPTEE_PAGER_IMAGE_ID) {
 			ret = parse_optee_image(pager_image_info,
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 9c37d63..3cb4f7e 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -250,7 +250,8 @@
 		psci_caps |=  define_psci_cap(PSCI_CPU_ON_AARCH64);
 	if ((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
 	    (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)) {
-		psci_caps |=  define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
+		if (psci_plat_pm_ops->validate_power_state != NULL)
+			psci_caps |=  define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
 		if (psci_plat_pm_ops->get_sys_suspend_power_state != NULL)
 			psci_caps |=  define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64);
 	}
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 819c536..45f5fa8 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -96,6 +96,12 @@
 # Build option to enable MPAM for lower ELs
 ENABLE_MPAM_FOR_LOWER_ELS	:= 0
 
+# Enable the Maximum Power Mitigation Mechanism on supporting cores.
+ENABLE_MPMM			:= 0
+
+# Enable MPMM configuration via FCONF.
+ENABLE_MPMM_FCONF		:= 0
+
 # Flag to Enable Position Independant support (PIE)
 ENABLE_PIE			:= 0
 
@@ -306,6 +312,8 @@
 CTX_INCLUDE_MTE_REGS		:= 0
 
 ENABLE_AMU			:= 0
+ENABLE_AMU_AUXILIARY_COUNTERS	:= 0
+ENABLE_AMU_FCONF		:= 0
 AMU_RESTRICT_COUNTERS		:= 0
 
 # By default, enable Scalable Vector Extension if implemented only for Non-secure
diff --git a/plat/arm/board/a5ds/platform.mk b/plat/arm/board/a5ds/platform.mk
index 8b0dc5c..4f87306 100644
--- a/plat/arm/board/a5ds/platform.mk
+++ b/plat/arm/board/a5ds/platform.mk
@@ -1,18 +1,23 @@
 #
-# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 # Firmware Configuration Framework sources
+include common/fdt_wrappers.mk
 include lib/fconf/fconf.mk
 
+BL1_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
 # Add `libfdt` and Arm common helpers required for Dynamic Config
 include lib/libfdt/libfdt.mk
 
 DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
-				plat/arm/common/arm_dyn_cfg_helpers.c	\
-				common/fdt_wrappers.c
+				plat/arm/common/arm_dyn_cfg_helpers.c
+
+DYN_CFG_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
 
 # Include GICv2 driver files
 include drivers/arm/gic/v2/gicv2.mk
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
index 901fabf..084532c 100644
--- a/plat/arm/board/arm_fpga/platform.mk
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -4,6 +4,7 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
 include lib/libfdt/libfdt.mk
 
 RESET_TO_BL31 := 1
@@ -104,8 +105,7 @@
 
 PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/arm_fpga/${ARCH}/fpga_helpers.S
 
-BL31_SOURCES		+=	common/fdt_wrappers.c				\
-				common/fdt_fixup.c				\
+BL31_SOURCES		+=	common/fdt_fixup.c				\
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
 				drivers/arm/pl011/${ARCH}/pl011_console.S	\
@@ -117,6 +117,8 @@
 				${FPGA_CPU_LIBS}				\
 				${FPGA_GIC_SOURCES}
 
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 $(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,bl31))
 $(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,bl31))
 $(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,bl31))
diff --git a/plat/arm/board/fvp/fdts/fvp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
index cad888f..c26b519 100644
--- a/plat/arm/board/fvp/fdts/fvp_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2021, ARM Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -45,12 +45,10 @@
 		};
 #endif
 
-#if !defined(SPD_spmd)
 		nt_fw-config {
 			load-address = <0x0 0x80000000>;
 			max-size = <0x200>;
 			id = <NT_FW_CONFIG_ID>;
 		};
-#endif
 	};
 };
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 70b1051..0d2c319 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -4,6 +4,8 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 # Use the GICv3 driver on the FVP by default
 FVP_USE_GIC_DRIVER	:= FVP_GICV3
 
@@ -130,16 +132,17 @@
 					lib/cpus/aarch64/neoverse_n2.S		\
 					lib/cpus/aarch64/neoverse_e1.S		\
 					lib/cpus/aarch64/neoverse_v1.S		\
+					lib/cpus/aarch64/neoverse_demeter.S	\
 					lib/cpus/aarch64/cortex_a78_ae.S	\
 					lib/cpus/aarch64/cortex_a510.S		\
 					lib/cpus/aarch64/cortex_a710.S	\
 					lib/cpus/aarch64/cortex_makalu.S	\
 					lib/cpus/aarch64/cortex_makalu_elp_arm.S \
-					lib/cpus/aarch64/cortex_demeter.S	\
 					lib/cpus/aarch64/cortex_a65.S		\
 					lib/cpus/aarch64/cortex_a65ae.S		\
 					lib/cpus/aarch64/cortex_a78c.S		\
-					lib/cpus/aarch64/cortex_hayes.S
+					lib/cpus/aarch64/cortex_hayes.S		\
+					lib/cpus/aarch64/cortex_hunter.S
 	endif
 	# AArch64/AArch32 cores
 	FVP_CPU_LIBS	+=	lib/cpus/aarch64/cortex_a55.S		\
@@ -227,11 +230,12 @@
 # Support for fconf in BL31
 # Added separately from the above list for better readability
 ifeq ($(filter 1,${BL2_AT_EL3} ${RESET_TO_BL31}),)
-BL31_SOURCES		+=	common/fdt_wrappers.c				\
-				lib/fconf/fconf.c				\
+BL31_SOURCES		+=	lib/fconf/fconf.c				\
 				lib/fconf/fconf_dyn_cfg_getter.c		\
 				plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
 
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 ifeq (${SEC_INT_DESC_IN_FCONF},1)
 BL31_SOURCES		+=	plat/arm/common/fconf/fconf_sec_intr_config.c
 endif
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
index 64cb7ad..0d8cca5 100644
--- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -1,9 +1,11 @@
 #
-# Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 # SP_MIN source files specific to FVP platform
 BL32_SOURCES		+=	drivers/arm/fvp/fvp_pwrc.c			\
 				drivers/cfi/v2m/v2m_flash.c			\
@@ -22,10 +24,11 @@
 # Support for fconf in SP_MIN(BL32)
 # Added separately from the above list for better readability
 ifeq ($(filter 1,${BL2_AT_EL3} ${RESET_TO_SP_MIN}),)
-BL32_SOURCES		+=	common/fdt_wrappers.c				\
-				lib/fconf/fconf.c				\
+BL32_SOURCES		+=	lib/fconf/fconf.c				\
 				plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
 
+BL32_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 ifeq (${SEC_INT_DESC_IN_FCONF},1)
 BL32_SOURCES		+=	plat/arm/common/fconf/fconf_sec_intr_config.c
 endif
diff --git a/plat/arm/board/fvp_ve/platform.mk b/plat/arm/board/fvp_ve/platform.mk
index ac45d57..f7eace8 100644
--- a/plat/arm/board/fvp_ve/platform.mk
+++ b/plat/arm/board/fvp_ve/platform.mk
@@ -1,9 +1,11 @@
 #
-# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 ifdef ARM_CORTEX_A5
 # Use the SP804 timer instead of the generic one
 USE_SP804_TIMER	:= 1
@@ -125,10 +127,13 @@
 # Firmware Configuration Framework sources
 include lib/fconf/fconf.mk
 
+BL1_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
 # Add `libfdt` and Arm common helpers required for Dynamic Config
 include lib/libfdt/libfdt.mk
 
 DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
-				plat/arm/common/arm_dyn_cfg_helpers.c	\
-				common/fdt_wrappers.c
+				plat/arm/common/arm_dyn_cfg_helpers.c
 
+DYN_CFG_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 92fbf35..2c84eb3 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -4,6 +4,8 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 # Include GICv2 driver files
 include drivers/arm/gic/v2/gicv2.mk
 
@@ -83,7 +85,6 @@
 				lib/cpus/aarch64/cortex_a57.S		\
 				lib/cpus/aarch64/cortex_a72.S		\
 				lib/utils/mem_region.c			\
-				common/fdt_wrappers.c			\
 				lib/fconf/fconf.c			\
 				lib/fconf/fconf_dyn_cfg_getter.c	\
 				plat/arm/board/juno/juno_bl31_setup.c	\
@@ -94,6 +95,8 @@
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
 
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
 BL1_SOURCES		+=	drivers/arm/css/sds/sds.c
 endif
diff --git a/plat/arm/board/tc/include/platform_def.h b/plat/arm/board/tc/include/platform_def.h
index ccabced..745d91c 100644
--- a/plat/arm/board/tc/include/platform_def.h
+++ b/plat/arm/board/tc/include/platform_def.h
@@ -185,6 +185,7 @@
 
 #define PLAT_ARM_DRAM2_BASE		ULL(0x8080000000)
 #define PLAT_ARM_DRAM2_SIZE		ULL(0x180000000)
+#define PLAT_ARM_DRAM2_END		(PLAT_ARM_DRAM2_BASE + PLAT_ARM_DRAM2_SIZE - 1ULL)
 
 #define PLAT_ARM_G1S_IRQ_PROPS(grp)	CSS_G1S_IRQ_PROPS(grp)
 #define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
@@ -260,13 +261,15 @@
 /*
  * The first region below, TC_TZC_DRAM1_BASE (0xfd000000) to
  * ARM_SCP_TZC_DRAM1_END (0xffffffff) will mark the last 48 MB of DRAM as
- * secure. The second region gives non secure access to rest of DRAM.
+ * secure. The second and third regions gives non secure access to rest of DRAM.
  */
-#define TC_TZC_REGIONS_DEF						\
-	{TC_TZC_DRAM1_BASE, ARM_SCP_TZC_DRAM1_END,			\
-		TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS},		\
-	{TC_NS_DRAM1_BASE, TC_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
-		PLAT_ARM_TZC_NS_DEV_ACCESS}
+#define TC_TZC_REGIONS_DEF	\
+	{TC_TZC_DRAM1_BASE, ARM_SCP_TZC_DRAM1_END,	\
+		TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS},	\
+	{TC_NS_DRAM1_BASE, TC_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS,	\
+		PLAT_ARM_TZC_NS_DEV_ACCESS},	\
+	{PLAT_ARM_DRAM2_BASE, PLAT_ARM_DRAM2_END,	\
+		ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}
 
 /* virtual address used by dynamic mem_protect for chunk_base */
 #define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 7ebf639..8765fa2 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -3,6 +3,8 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 ifeq ($(filter ${TARGET_PLATFORM}, 0 1),)
         $(error TARGET_PLATFORM must be 0 or 1)
 endif
@@ -91,13 +93,14 @@
 				${ENT_GIC_SOURCES}			\
 				${TC_BASE}/tc_bl31_setup.c	\
 				${TC_BASE}/tc_topology.c	\
-				common/fdt_wrappers.c			\
 				lib/fconf/fconf.c			\
 				lib/fconf/fconf_dyn_cfg_getter.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
 				lib/utils/mem_region.c			\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 # Add the FDT_SOURCES and options for Dynamic Config
 FDT_SOURCES		+=	${TC_BASE}/fdts/${PLAT}_fw_config.dts	\
 				${TC_BASE}/fdts/${PLAT}_tb_fw_config.dts
@@ -137,6 +140,11 @@
 override ENABLE_SPE_FOR_LOWER_ELS	:= 0
 
 override ENABLE_AMU := 1
+override ENABLE_AMU_AUXILIARY_COUNTERS := 1
+override ENABLE_AMU_FCONF := 1
+
+override ENABLE_MPMM := 1
+override ENABLE_MPMM_FCONF := 1
 
 include plat/arm/common/arm_common.mk
 include plat/arm/css/common/css_common.mk
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 6472590..a6f7df5 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -218,6 +218,10 @@
 	 * Linux kernel tree, Linux expects the physical address of the device
 	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
 	 * must be 0.
+	 * Repurpose the option to load Hafnium hypervisor in the normal world.
+	 * It expects its manifest address in x0. This is essentially the linux
+	 * dts (passed to the primary VM) by adding 'hypervisor' and chosen
+	 * nodes specifying the Hypervisor configuration.
 	 */
 #if RESET_TO_BL31
 	bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE;
@@ -228,14 +232,6 @@
 	bl33_image_ep_info.args.arg2 = 0U;
 	bl33_image_ep_info.args.arg3 = 0U;
 # endif
-
-#if defined(SPD_spmd)
-	/*
-	 * Hafnium in normal world expects its manifest address in x0, In CI
-	 * configuration manifest is preloaded at 0x80000000(start of DRAM).
-	 */
-	bl33_image_ep_info.args.arg0 = (u_register_t)ARM_DRAM1_BASE;
-#endif
 }
 
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index a20e258..78efb0f 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -4,6 +4,8 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 ifeq (${ARCH}, aarch64)
   # On ARM standard platorms, the TSP can execute from Trusted SRAM, Trusted
   # DRAM (if available) or the TZC secured area of DRAM.
@@ -256,14 +258,18 @@
 # Firmware Configuration Framework sources
 include lib/fconf/fconf.mk
 
+BL1_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES		+=	${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
 # Add `libfdt` and Arm common helpers required for Dynamic Config
 include lib/libfdt/libfdt.mk
 
 DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
 				plat/arm/common/arm_dyn_cfg_helpers.c	\
-				common/fdt_wrappers.c			\
 				common/uuid.c
 
+DYN_CFG_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 BL1_SOURCES		+=	${DYN_CFG_SOURCES}
 BL2_SOURCES		+=	${DYN_CFG_SOURCES}
 
@@ -343,10 +349,10 @@
 
 ifeq (${SPD},spmd)
 BL31_SOURCES		+=	plat/common/plat_spmd_manifest.c	\
-				common/fdt_wrappers.c			\
 				common/uuid.c				\
 				${LIBFDT_SRCS}
 
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
 endif
 
 ifneq (${TRUSTED_BOARD_BOOT},0)
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/css/sgi/include/sgi_base_platform_def.h
index d795f25..c9c8c04 100644
--- a/plat/arm/css/sgi/include/sgi_base_platform_def.h
+++ b/plat/arm/css/sgi/include/sgi_base_platform_def.h
@@ -89,7 +89,7 @@
  *
  */
 #if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE		(0x1D000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+# define PLAT_ARM_MAX_BL2_SIZE		(0x20000 + ((CSS_SGI_CHIP_COUNT - 1) * \
 							0x2000))
 #else
 # define PLAT_ARM_MAX_BL2_SIZE		(0x14000 + ((CSS_SGI_CHIP_COUNT - 1) * \
diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h
index e86938b..6709678 100644
--- a/plat/imx/imx8m/imx8mm/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mm/include/platform_def.h
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <arch.h>
 #include <common/tbbr/tbbr_img_def.h>
 
 #define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk
index c3f78c5..d0e8688 100644
--- a/plat/marvell/armada/a3k/common/a3700_common.mk
+++ b/plat/marvell/armada/a3k/common/a3700_common.mk
@@ -144,7 +144,7 @@
 CRYPTOPP_INCDIR		?= $(CRYPTOPP_PATH)
 
 $(TBB): FORCE
-	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+#	Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(CRYPTOPP_LIBDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_LIBDIR. Please set CRYPTOPP_PATH or CRYPTOPP_LIBDIR to point to the right directory"))
 	$(if $(CRYPTOPP_INCDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_INCDIR. Please set CRYPTOPP_PATH or CRYPTOPP_INCDIR to point to the right directory"))
 	$(if $(wildcard $(CRYPTOPP_LIBDIR)/*),,$(error "Either 'CRYPTOPP_PATH' or 'CRYPTOPP_LIB' was set to '$(CRYPTOPP_LIBDIR)', but '$(CRYPTOPP_LIBDIR)' does not exist"))
@@ -161,7 +161,7 @@
 	$(Q)cp -a $(WTMI_MULTI_IMG) $(BUILD_PLAT)/wtmi.bin
 
 $(TIMDDRTOOL): FORCE
-	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+#	Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for ddr tool requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
 	$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
 	$(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
diff --git a/plat/marvell/armada/a8k/common/ble/ble.mk b/plat/marvell/armada/a8k/common/ble/ble.mk
index e41ab3e..160e98f 100644
--- a/plat/marvell/armada/a8k/common/ble/ble.mk
+++ b/plat/marvell/armada/a8k/common/ble/ble.mk
@@ -28,7 +28,7 @@
 $(BLE_OBJS): $(MV_DDR_LIB)
 
 $(MV_DDR_LIB): FORCE
-	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+#	Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(value MV_DDR_PATH),,$(error "Platform '$(PLAT)' for BLE requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
 	$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
 	$(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c
index b40fa87..d018953 100644
--- a/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c
@@ -46,7 +46,6 @@
 	 R12_CCIF0_EVENT_B |				\
 	 R12_SSPM2SPM_WAKEUP_B |			\
 	 R12_SCP2SPM_WAKEUP_B |				\
-	 R12_ADSP2SPM_WAKEUP_B |			\
 	 R12_USBX_CDSC_B |				\
 	 R12_USBX_POWERDWN_B |				\
 	 R12_SYS_TIMER_EVENT_B |			\
diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk
index 339375f..7583833 100644
--- a/plat/nvidia/tegra/soc/t194/platform_t194.mk
+++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk
@@ -1,9 +1,11 @@
 #
-# Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 # platform configs
 ENABLE_CONSOLE_SPE			:= 1
 $(eval $(call add_define,ENABLE_CONSOLE_SPE))
@@ -74,10 +76,10 @@
 
 # SPM dispatcher
 ifeq (${SPD},spmd)
-# include device tree helper library
 include lib/libfdt/libfdt.mk
 # sources to support spmd
 BL31_SOURCES		+=	plat/common/plat_spmd_manifest.c	\
-				common/fdt_wrappers.c			\
 				${LIBFDT_SRCS}
+
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
 endif
diff --git a/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h b/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h
index 789b112..84f07e6 100644
--- a/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h
+++ b/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h
@@ -56,6 +56,11 @@
 #define RCPM_POWMGTCSR_OFFSET		0x130
 #define RCPM_IPPDEXPCR0_OFFSET		0x140
 #define RCPM_POWMGTCSR_LPM20_REQ	0x00100000
-#endif
+#endif /* NXP_RCPM_ADDR */
+
+#define DCFG_SBEESR2_ADDR		0x20140534
+#define DCFG_MBEESR2_ADDR		0x20140544
+/* SBEESR and MBEESR bit mask */
+#define OCRAM_EESR_MASK			0x00000060
 
 #endif	/*	SOC_DEFAULT_HELPER_MACROS_H	*/
diff --git a/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h b/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h
index 8de516e..1edd28d 100644
--- a/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h
+++ b/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h
@@ -79,4 +79,9 @@
 #define ENABLE_WUO			0x10
 #endif /* NXP_CCN_ADDR */
 
+#define DCFG_SBEESR2_ADDR		0x00100534
+#define DCFG_MBEESR2_ADDR		0x00100544
+/* SBEESR and MBEESR bit mask */
+#define OCRAM_EESR_MASK			0x00000008
+
 #endif	/*	SOC_DEFAULT_HELPER_MACROS_H	*/
diff --git a/plat/nxp/common/ocram/aarch64/ocram.S b/plat/nxp/common/ocram/aarch64/ocram.S
new file mode 100644
index 0000000..ec53341
--- /dev/null
+++ b/plat/nxp/common/ocram/aarch64/ocram.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+#include <soc_default_base_addr.h>
+#include <soc_default_helper_macros.h>
+
+.global ocram_init
+
+/*
+ * void ocram_init(uintptr_t start_addr, size_t size)
+ *
+ * This function will do OCRAM ECC.
+ * OCRAM is initialized with 64-bit writes and then a write
+ * performed to address 0x0010_0534 with the value 0x0000_0008.
+ *
+ * x0: start_addr
+ * x1: size in bytes
+ * Called from C
+ */
+
+func ocram_init
+	/* save the aarch32/64 non-volatile registers */
+	stp	x4,  x5,  [sp, #-16]!
+	stp	x6,  x7,  [sp, #-16]!
+	stp	x8,  x9,  [sp, #-16]!
+	stp	x10, x11, [sp, #-16]!
+	stp	x12, x13, [sp, #-16]!
+	stp	x18, x30, [sp, #-16]!
+
+	/* convert bytes to 64-byte chunks */
+	lsr	x1, x1, #6
+1:
+	/* for each location, read and write-back */
+	dc	ivac, x0
+	dsb	sy
+	ldp	x4, x5, [x0]
+	ldp	x6, x7, [x0, #16]
+	ldp	x8, x9, [x0, #32]
+	ldp	x10, x11, [x0, #48]
+	stp	x4, x5, [x0]
+	stp	x6, x7, [x0, #16]
+	stp	x8, x9, [x0, #32]
+	stp	x10, x11, [x0, #48]
+	dc	cvac, x0
+
+	sub	x1, x1, #1
+	cbz	x1, 2f
+	add	x0, x0, #64
+	b	1b
+2:
+	/* Clear OCRAM ECC status bit in SBEESR2 and MBEESR2 */
+	ldr	w1, =OCRAM_EESR_MASK
+	ldr	x0, =DCFG_SBEESR2_ADDR
+	str	w1, [x0]
+	ldr	x0, =DCFG_MBEESR2_ADDR
+	str	w1, [x0]
+
+	/* restore the aarch32/64 non-volatile registers */
+	ldp	x18, x30, [sp], #16
+	ldp	x12, x13, [sp], #16
+	ldp	x10, x11, [sp], #16
+	ldp	x8,  x9,  [sp], #16
+	ldp	x6,  x7,  [sp], #16
+	ldp	x4,  x5,  [sp], #16
+	ret
+endfunc ocram_init
diff --git a/plat/nxp/common/ocram/ocram.h b/plat/nxp/common/ocram/ocram.h
new file mode 100644
index 0000000..479de61
--- /dev/null
+++ b/plat/nxp/common/ocram/ocram.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef OCRAM_H
+#define OCRAM_H
+
+void ocram_init(uintptr_t start_addr, size_t size);
+
+#endif /* OCRAM_H */
diff --git a/plat/nxp/common/ocram/ocram.mk b/plat/nxp/common/ocram/ocram.mk
new file mode 100644
index 0000000..c77bd4a
--- /dev/null
+++ b/plat/nxp/common/ocram/ocram.mk
@@ -0,0 +1,14 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+PLAT_OCRAM_PATH		:= $(PLAT_COMMON_PATH)/ocram
+
+OCRAM_SOURCES		:= ${PLAT_OCRAM_PATH}/$(ARCH)/ocram.S
+
+BL2_SOURCES		+= ${OCRAM_SOURCES}
+
+PLAT_INCLUDES           += -I${PLAT_COMMON_PATH}/ocram
diff --git a/plat/nxp/common/plat_make_helper/soc_common_def.mk b/plat/nxp/common/plat_make_helper/soc_common_def.mk
index fdd7249..22cd39a 100644
--- a/plat/nxp/common/plat_make_helper/soc_common_def.mk
+++ b/plat/nxp/common/plat_make_helper/soc_common_def.mk
@@ -112,3 +112,8 @@
 ifneq (${PLAT_XLAT_TABLES_DYNAMIC},)
 $(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
 endif
+
+ifeq (${OCRAM_ECC_EN},yes)
+$(eval $(call add_define,CONFIG_OCRAM_ECC_EN))
+include ${PLAT_COMMON_PATH}/ocram/ocram.mk
+endif
diff --git a/plat/nxp/soc-ls1028a/soc.c b/plat/nxp/soc-ls1028a/soc.c
index 4f67154..edfd657 100644
--- a/plat/nxp/soc-ls1028a/soc.c
+++ b/plat/nxp/soc-ls1028a/soc.c
@@ -16,6 +16,9 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <ls_interconnect.h>
 #include <mmio.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <nxp_gpio.h>
+#endif
 #if TRUSTED_BOARD_BOOT
 #include <nxp_smmu.h>
 #endif
@@ -81,6 +84,15 @@
 }
 
 #ifdef IMAGE_BL2
+
+#ifdef POLICY_FUSE_PROVISION
+static gpio_init_info_t gpio_init_data = {
+	.gpio1_base_addr = NXP_GPIO1_ADDR,
+	.gpio2_base_addr = NXP_GPIO2_ADDR,
+	.gpio3_base_addr = NXP_GPIO3_ADDR,
+};
+#endif
+
 void soc_preload_setup(void)
 {
 }
diff --git a/plat/nxp/soc-ls1028a/soc.def b/plat/nxp/soc-ls1028a/soc.def
index e133982..c23c1bb 100644
--- a/plat/nxp/soc-ls1028a/soc.def
+++ b/plat/nxp/soc-ls1028a/soc.def
@@ -88,6 +88,8 @@
 NXP_ESDHC_ENDIANNESS	:=	LE
 NXP_QSPI_ENDIANNESS	:=	LE
 NXP_FSPI_ENDIANNESS	:=	LE
+NXP_SCFG_ENDIANNESS	:=	LE
+NXP_GPIO_ENDIANNESS	:=	LE
 
 NXP_SFP_VER		:=	3_4
 
diff --git a/plat/qemu/qemu_sbsa/platform.mk b/plat/qemu/qemu_sbsa/platform.mk
index 9fb30ad..5a6b1e1 100644
--- a/plat/qemu/qemu_sbsa/platform.mk
+++ b/plat/qemu/qemu_sbsa/platform.mk
@@ -1,9 +1,11 @@
 #
-# Copyright (c) 2019-2020, Linaro Limited and Contributors. All rights reserved.
+# Copyright (c) 2019-2021, Linaro Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+include common/fdt_wrappers.mk
+
 CRASH_REPORTING	:=	1
 
 include lib/libfdt/libfdt.mk
@@ -86,8 +88,10 @@
 				${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S	\
 				${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c	\
 				common/fdt_fixup.c				\
-				common/fdt_wrappers.c				\
 				${QEMU_GIC_SOURCES}
+
+BL31_SOURCES		+=	${FDT_WRAPPERS_SOURCES}
+
 ifeq (${SPM_MM},1)
 	BL31_SOURCES		+=	${PLAT_QEMU_COMMON_PATH}/qemu_spm.c
 endif
diff --git a/plat/qti/common/src/pm8998.c b/plat/qti/common/src/pm_ps_hold.c
similarity index 91%
rename from plat/qti/common/src/pm8998.c
rename to plat/qti/common/src/pm_ps_hold.c
index b189a8b..208345c 100644
--- a/plat/qti/common/src/pm8998.c
+++ b/plat/qti/common/src/pm_ps_hold.c
@@ -14,11 +14,9 @@
  * include other part numbers like PM6150.
  */
 
-#define PON_PS_HOLD_RESET_CTL		0x85a
 #define RESET_TYPE_WARM_RESET		1
 #define RESET_TYPE_SHUTDOWN		4
 
-#define PON_PS_HOLD_RESET_CTL2		0x85b
 #define S2_RESET_EN			BIT(7)
 
 static void configure_ps_hold(uint32_t reset_type)
diff --git a/plat/qti/sc7180/inc/platform_def.h b/plat/qti/sc7180/inc/platform_def.h
index b0798a6..e3dc811 100644
--- a/plat/qti/sc7180/inc/platform_def.h
+++ b/plat/qti/sc7180/inc/platform_def.h
@@ -190,5 +190,10 @@
 #define QTI_SOC_REVISION_REG			0x1FC8000
 #define QTI_SOC_REVISION_MASK			U(0xFFFF)
 /*----------------------------------------------------------------------------*/
+/* LC PON register offsets */
+/*----------------------------------------------------------------------------*/
+#define PON_PS_HOLD_RESET_CTL			0x85a
+#define PON_PS_HOLD_RESET_CTL2			0x85b
+/*----------------------------------------------------------------------------*/
 
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/sc7180/platform.mk b/plat/qti/sc7180/platform.mk
index ec560d0..141e2c3 100644
--- a/plat/qti/sc7180/platform.mk
+++ b/plat/qti/sc7180/platform.mk
@@ -51,7 +51,7 @@
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_silver.S	\
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_gold.S	\
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S	\
-				$(QTI_PLAT_PATH)/common/src/pm8998.c			\
+				$(QTI_PLAT_PATH)/common/src/pm_ps_hold.c			\
 				$(QTI_PLAT_PATH)/common/src/qti_stack_protector.c	\
 				$(QTI_PLAT_PATH)/common/src/qti_common.c		\
 				$(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c		\
diff --git a/plat/qti/sc7280/inc/platform_def.h b/plat/qti/sc7280/inc/platform_def.h
index 660cb33..da7eddc 100644
--- a/plat/qti/sc7280/inc/platform_def.h
+++ b/plat/qti/sc7280/inc/platform_def.h
@@ -190,5 +190,10 @@
 #define QTI_SOC_REVISION_REG			0x1FC8000
 #define QTI_SOC_REVISION_MASK			U(0xFFFF)
 /*----------------------------------------------------------------------------*/
+/* LC PON register offsets */
+/*----------------------------------------------------------------------------*/
+#define PON_PS_HOLD_RESET_CTL			0x852
+#define PON_PS_HOLD_RESET_CTL2			0x853
+/*----------------------------------------------------------------------------*/
 
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/sc7280/platform.mk b/plat/qti/sc7280/platform.mk
index 6e26781..bc2c221 100644
--- a/plat/qti/sc7280/platform.mk
+++ b/plat/qti/sc7280/platform.mk
@@ -51,7 +51,7 @@
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_silver.S	\
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_gold.S	\
 				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S	\
-				$(QTI_PLAT_PATH)/common/src/pm8998.c			\
+				$(QTI_PLAT_PATH)/common/src/pm_ps_hold.c			\
 				$(QTI_PLAT_PATH)/common/src/qti_stack_protector.c	\
 				$(QTI_PLAT_PATH)/common/src/qti_common.c		\
 				$(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c		\
diff --git a/plat/renesas/common/plat_pm.c b/plat/renesas/common/plat_pm.c
index 6a9ad45..1d4a7f6 100644
--- a/plat/renesas/common/plat_pm.c
+++ b/plat/renesas/common/plat_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -128,11 +128,6 @@
 
 		rcar_pwrc_clusteroff(mpidr);
 	}
-
-#if RCAR_SYSTEM_SUSPEND
-	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
-		rcar_pwrc_suspend_to_ram();
-#endif
 }
 
 static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
@@ -160,6 +155,18 @@
 	rcar_pwr_domain_on_finish(target_state);
 }
 
+static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+#if RCAR_SYSTEM_SUSPEND
+	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		rcar_pwrc_suspend_to_ram();
+#endif
+	wfi();
+
+	ERROR("RCAR Power Down: operation not handled.\n");
+	panic();
+}
+
 static void __dead2 rcar_system_off(void)
 {
 #if PMIC_ROHM_BD9571
@@ -292,6 +299,7 @@
 	.system_off			= rcar_system_off,
 	.system_reset			= rcar_system_reset,
 	.validate_power_state		= rcar_validate_power_state,
+	.pwr_domain_pwr_down_wfi	= rcar_pwr_domain_pwr_down_wfi,
 #if RCAR_SYSTEM_SUSPEND
 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
 #endif
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 28463f1..14f90d4 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -154,13 +154,15 @@
 PLAT_INCLUDES		:=	-Iplat/st/common/include/
 PLAT_INCLUDES		+=	-Iplat/st/stm32mp1/include/
 
+include common/fdt_wrappers.mk
 include lib/libfdt/libfdt.mk
 
-PLAT_BL_COMMON_SOURCES	:=	common/fdt_wrappers.c					\
-				common/uuid.c						\
+PLAT_BL_COMMON_SOURCES	:=	common/uuid.c						\
 				plat/st/common/stm32mp_common.c				\
 				plat/st/stm32mp1/stm32mp1_private.c
 
+PLAT_BL_COMMON_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
+
 PLAT_BL_COMMON_SOURCES	+=	drivers/st/uart/aarch32/stm32_console.S
 
 ifneq (${ENABLE_STACK_PROTECTOR},0)
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
index 5d176c2..399c2ec 100644
--- a/services/std_svc/sdei/sdei_intr_mgmt.c
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -531,7 +531,7 @@
 	if (is_event_shared(map))
 		sdei_map_unlock(map);
 
-	SDEI_LOG("ACK %llx, ev:%d ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num,
+	SDEI_LOG("ACK %llx, ev:0x%x ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num,
 			sec_state, read_spsr_el3(), read_elr_el3());
 
 	ctx = handle;
@@ -568,7 +568,7 @@
 	 * interrupt.
 	 */
 	if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) {
-		ERROR("Invalid SDEI mapping: ev=%u\n", map->ev_num);
+		ERROR("Invalid SDEI mapping: ev=0x%x\n", map->ev_num);
 		panic();
 	}
 	plat_ic_end_of_interrupt(intr_raw);
@@ -703,7 +703,7 @@
 	/* Having done sanity checks, pop dispatch */
 	(void) pop_dispatch();
 
-	SDEI_LOG("EOI:%lx, %d spsr:%lx elr:%lx\n", read_mpidr_el1(),
+	SDEI_LOG("EOI:%lx, 0x%x spsr:%lx elr:%lx\n", read_mpidr_el1(),
 			map->ev_num, read_spsr_el3(), read_elr_el3());
 
 	/*
diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c
index 5371df1..4ceaae8 100644
--- a/services/std_svc/sdei/sdei_main.c
+++ b/services/std_svc/sdei/sdei_main.c
@@ -966,7 +966,7 @@
 
 	case SDEI_EVENT_REGISTER:
 		x5 = SMC_GET_GP(ctx, CTX_GPREG_X5);
-		SDEI_LOG("> REG(n:%d e:%llx a:%llx f:%x m:%llx)\n", ev_num,
+		SDEI_LOG("> REG(n:0x%x e:%llx a:%llx f:%x m:%llx)\n", ev_num,
 				x2, x3, (int) x4, x5);
 		ret = sdei_event_register(ev_num, x2, x3, x4, x5);
 		SDEI_LOG("< REG:%lld\n", ret);
@@ -979,7 +979,7 @@
 		SMC_RET1(ctx, ret);
 
 	case SDEI_EVENT_DISABLE:
-		SDEI_LOG("> DISABLE(n:%d)\n", ev_num);
+		SDEI_LOG("> DISABLE(n:0x%x)\n", ev_num);
 		ret = sdei_event_disable(ev_num);
 		SDEI_LOG("< DISABLE:%lld\n", ret);
 		SMC_RET1(ctx, ret);
@@ -1013,19 +1013,19 @@
 		SMC_RET0(ctx);
 
 	case SDEI_EVENT_STATUS:
-		SDEI_LOG("> STAT(n:%d)\n", ev_num);
+		SDEI_LOG("> STAT(n:0x%x)\n", ev_num);
 		ret = sdei_event_status(ev_num);
 		SDEI_LOG("< STAT:%lld\n", ret);
 		SMC_RET1(ctx, ret);
 
 	case SDEI_EVENT_GET_INFO:
-		SDEI_LOG("> INFO(n:%d, %d)\n", ev_num, (int) x2);
+		SDEI_LOG("> INFO(n:0x%x, %d)\n", ev_num, (int) x2);
 		ret = sdei_event_get_info(ev_num, (int) x2);
 		SDEI_LOG("< INFO:%lld\n", ret);
 		SMC_RET1(ctx, ret);
 
 	case SDEI_EVENT_UNREGISTER:
-		SDEI_LOG("> UNREG(n:%d)\n", ev_num);
+		SDEI_LOG("> UNREG(n:0x%x)\n", ev_num);
 		ret = sdei_event_unregister(ev_num);
 		SDEI_LOG("< UNREG:%lld\n", ret);
 		SMC_RET1(ctx, ret);
@@ -1049,7 +1049,7 @@
 		SMC_RET1(ctx, ret);
 
 	case SDEI_INTERRUPT_RELEASE:
-		SDEI_LOG("> REL(%d)\n", ev_num);
+		SDEI_LOG("> REL(0x%x)\n", ev_num);
 		ret = sdei_interrupt_release(ev_num);
 		SDEI_LOG("< REL:%lld\n", ret);
 		SMC_RET1(ctx, ret);
@@ -1067,7 +1067,7 @@
 		SMC_RET1(ctx, ret);
 
 	case SDEI_EVENT_ROUTING_SET:
-		SDEI_LOG("> ROUTE_SET(n:%d f:%llx aff:%llx)\n", ev_num, x2, x3);
+		SDEI_LOG("> ROUTE_SET(n:0x%x f:%llx aff:%llx)\n", ev_num, x2, x3);
 		ret = sdei_event_routing_set(ev_num, x2, x3);
 		SDEI_LOG("< ROUTE_SET:%lld\n", ret);
 		SMC_RET1(ctx, ret);
@@ -1079,7 +1079,7 @@
 		SMC_RET1(ctx, ret);
 
 	case SDEI_EVENT_SIGNAL:
-		SDEI_LOG("> SIGNAL(e:%d t:%llx)\n", ev_num, x2);
+		SDEI_LOG("> SIGNAL(e:0x%x t:%llx)\n", ev_num, x2);
 		ret = sdei_signal(ev_num, x2);
 		SDEI_LOG("< SIGNAL:%lld\n", ret);
 		SMC_RET1(ctx, ret);