AArch64: Enable MPAM for lower ELs

Memory Partitioning And Monitoring is an Armv8.4 feature that enables
various memory system components and resources to define partitions.
Software running at various ELs can then assign themselves to the
desired partition to control their performance aspects.

With this patch, when ENABLE_MPAM_FOR_LOWER_ELS is set to 1, EL3 allows
lower ELs to access their own MPAM registers without trapping to EL3.
This patch however doesn't make use of partitioning in EL3; platform
initialisation code should configure and use partitions in EL3 if
required.

Change-Id: I5a55b6771ccaa0c1cffc05543d2116b60cbbcdcd
Co-authored-by: James Morse <james.morse@arm.com>
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index f389368..2812bda 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -12,6 +12,7 @@
 #include <context.h>
 #include <context_mgmt.h>
 #include <interrupt_mgmt.h>
+#include <mpam.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <pubsub_events.h>
@@ -244,6 +245,10 @@
 #if ENABLE_SVE_FOR_NS
 	sve_enable(el2_unused);
 #endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	mpam_enable(el2_unused);
+#endif
 #endif
 }
 
diff --git a/lib/extensions/mpam/mpam.c b/lib/extensions/mpam/mpam.c
new file mode 100644
index 0000000..e628827
--- /dev/null
+++ b/lib/extensions/mpam/mpam.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <mpam.h>
+#include <stdbool.h>
+
+bool mpam_supported(void)
+{
+	uint64_t features = read_id_aa64dfr0_el1() >> ID_AA64PFR0_MPAM_SHIFT;
+
+	return ((features & ID_AA64PFR0_MPAM_MASK) != 0U);
+}
+
+void mpam_enable(int el2_unused)
+{
+	if (!mpam_supported())
+		return;
+
+	/*
+	 * Enable MPAM, and disable trapping to EL3 when lower ELs access their
+	 * own MPAM registers.
+	 */
+	write_mpam3_el3(MPAM3_EL3_MPAMEN_BIT);
+
+	/*
+	 * If EL2 is implemented but unused, disable trapping to EL2 when lower
+	 * ELs access their own MPAM registers.
+	 */
+	if (el2_unused != 0) {
+		write_mpam2_el2(0);
+
+		if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U)
+			write_mpamhcr_el2(0);
+	}
+}