Enable v8.6 AMU enhancements (FEAT_AMUv1p1)

ARMv8.6 adds virtual offset registers to support virtualization of the
event counters in EL1 and EL0.  This patch enables support for this
feature in EL3 firmware.

Signed-off-by: John Powell <john.powell@arm.com>
Change-Id: I7ee1f3d9f554930bf5ef6f3d492e932e6d95b217
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
index 0f75f07..ed56ddd 100644
--- a/lib/extensions/amu/aarch32/amu.c
+++ b/lib/extensions/amu/aarch32/amu.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
  */
@@ -18,13 +18,17 @@
 
 static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
 
-/* Check if AMUv1 for Armv8.4 or 8.6 is implemented */
-bool amu_supported(void)
+/*
+ * 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)
 {
-	uint32_t features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT;
-
-	features &= ID_PFR0_AMU_MASK;
-	return ((features == 1U) || (features == 2U));
+	return (unsigned int)(read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
+		ID_PFR0_AMU_MASK;
 }
 
 #if AMU_GROUP1_NR_COUNTERS
@@ -43,7 +47,7 @@
  */
 void amu_enable(bool el2_unused)
 {
-	if (!amu_supported()) {
+	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
 		return;
 	}
 
@@ -87,12 +91,31 @@
 	/* Enable group 1 counters */
 	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
 #endif
+
+	/* Initialize FEAT_AMUv1p1 features if present. */
+	if (amu_get_version() < ID_PFR0_AMU_V1P1) {
+		return;
+	}
+
+#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(read_amcr() | AMCR_CG1RZ_BIT);
+#else
+	write_amcr(read_amcr() & ~AMCR_CG1RZ_BIT);
+#endif
 }
 
 /* Read the group 0 counter identified by the given `idx`. */
 uint64_t amu_group0_cnt_read(unsigned int idx)
 {
-	assert(amu_supported());
+	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
 	assert(idx < AMU_GROUP0_NR_COUNTERS);
 
 	return amu_group0_cnt_read_internal(idx);
@@ -101,7 +124,7 @@
 /* Write the group 0 counter identified by the given `idx` with `val` */
 void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
 {
-	assert(amu_supported());
+	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
 	assert(idx < AMU_GROUP0_NR_COUNTERS);
 
 	amu_group0_cnt_write_internal(idx, val);
@@ -112,7 +135,7 @@
 /* Read the group 1 counter identified by the given `idx` */
 uint64_t amu_group1_cnt_read(unsigned  int idx)
 {
-	assert(amu_supported());
+	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
 	assert(amu_group1_supported());
 	assert(idx < AMU_GROUP1_NR_COUNTERS);
 
@@ -122,7 +145,7 @@
 /* Write the group 1 counter identified by the given `idx` with `val` */
 void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
 {
-	assert(amu_supported());
+	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
 	assert(amu_group1_supported());
 	assert(idx < AMU_GROUP1_NR_COUNTERS);
 
@@ -136,7 +159,7 @@
  */
 void amu_group1_set_evtype(unsigned int idx, unsigned int val)
 {
-	assert(amu_supported());
+	assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED);
 	assert(amu_group1_supported());
 	assert(idx < AMU_GROUP1_NR_COUNTERS);
 
@@ -150,7 +173,7 @@
 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
 	unsigned int i;
 
-	if (!amu_supported()) {
+	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
 		return (void *)-1;
 	}
 
@@ -197,7 +220,7 @@
 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
 	unsigned int i;
 
-	if (!amu_supported()) {
+	if (amu_get_version() == ID_PFR0_AMU_NOT_SUPPORTED) {
 		return (void *)-1;
 	}
 
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
index effb8e5..d387341 100644
--- a/lib/extensions/amu/aarch32/amu_helpers.S
+++ b/lib/extensions/amu/aarch32/amu_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -75,13 +75,13 @@
 
 1:
 	stcopr16	r2, r3, AMEVCNTR00	/* index 0 */
-	bx 		lr
+	bx		lr
 	stcopr16	r2, r3, AMEVCNTR01	/* index 1 */
-	bx 		lr
+	bx		lr
 	stcopr16	r2, r3, AMEVCNTR02	/* index 2 */
-	bx 		lr
+	bx		lr
 	stcopr16	r2, r3, AMEVCNTR03	/* index 3 */
-	bx 		lr
+	bx		lr
 endfunc amu_group0_cnt_write_internal
 
 /*
@@ -169,37 +169,37 @@
 	bx	r1
 
 1:
-	stcopr16	r2, r3,	AMEVCNTR10	/* index 0 */
+	stcopr16	r2, r3, AMEVCNTR10	/* index 0 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR11	/* index 1 */
+	stcopr16	r2, r3, AMEVCNTR11	/* index 1 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR12	/* index 2 */
+	stcopr16	r2, r3, AMEVCNTR12	/* index 2 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR13	/* index 3 */
+	stcopr16	r2, r3, AMEVCNTR13	/* index 3 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR14	/* index 4 */
+	stcopr16	r2, r3, AMEVCNTR14	/* index 4 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR15	/* index 5 */
+	stcopr16	r2, r3, AMEVCNTR15	/* index 5 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR16	/* index 6 */
+	stcopr16	r2, r3, AMEVCNTR16	/* index 6 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR17	/* index 7 */
+	stcopr16	r2, r3, AMEVCNTR17	/* index 7 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR18	/* index 8 */
+	stcopr16	r2, r3, AMEVCNTR18	/* index 8 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR19	/* index 9 */
+	stcopr16	r2, r3, AMEVCNTR19	/* index 9 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1A	/* index 10 */
+	stcopr16	r2, r3, AMEVCNTR1A	/* index 10 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1B	/* index 11 */
+	stcopr16	r2, r3, AMEVCNTR1B	/* index 11 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1C	/* index 12 */
+	stcopr16	r2, r3, AMEVCNTR1C	/* index 12 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1D	/* index 13 */
+	stcopr16	r2, r3, AMEVCNTR1D	/* index 13 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1E	/* index 14 */
+	stcopr16	r2, r3, AMEVCNTR1E	/* index 14 */
 	bx		lr
-	stcopr16	r2, r3,	AMEVCNTR1F	/* index 15 */
+	stcopr16	r2, r3, AMEVCNTR1F	/* index 15 */
 	bx		lr
 endfunc amu_group1_cnt_write_internal
 
@@ -234,36 +234,36 @@
 	bx	r2
 
 1:
-	stcopr	r1,	AMEVTYPER10 /* index 0 */
+	stcopr	r1, AMEVTYPER10 /* index 0 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER11 /* index 1 */
+	stcopr	r1, AMEVTYPER11 /* index 1 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER12 /* index 2 */
+	stcopr	r1, AMEVTYPER12 /* index 2 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER13 /* index 3 */
+	stcopr	r1, AMEVTYPER13 /* index 3 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER14 /* index 4 */
+	stcopr	r1, AMEVTYPER14 /* index 4 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER15 /* index 5 */
+	stcopr	r1, AMEVTYPER15 /* index 5 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER16 /* index 6 */
+	stcopr	r1, AMEVTYPER16 /* index 6 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER17 /* index 7 */
+	stcopr	r1, AMEVTYPER17 /* index 7 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER18 /* index 8 */
+	stcopr	r1, AMEVTYPER18 /* index 8 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER19 /* index 9 */
+	stcopr	r1, AMEVTYPER19 /* index 9 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1A /* index 10 */
+	stcopr	r1, AMEVTYPER1A /* index 10 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1B /* index 11 */
+	stcopr	r1, AMEVTYPER1B /* index 11 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1C /* index 12 */
+	stcopr	r1, AMEVTYPER1C /* index 12 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1D /* index 13 */
+	stcopr	r1, AMEVTYPER1D /* index 13 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1E /* index 14 */
+	stcopr	r1, AMEVTYPER1E /* index 14 */
 	bx	lr
-	stcopr	r1,	AMEVTYPER1F /* index 15 */
+	stcopr	r1, AMEVTYPER1F /* index 15 */
 	bx	lr
 endfunc amu_group1_set_evtype_internal