Merge "feat(fvp): add cpu power control" into integration
diff --git a/include/drivers/arm/fvp/fvp_cpu_pwr.h b/include/drivers/arm/fvp/fvp_cpu_pwr.h
new file mode 100644
index 0000000..488be18
--- /dev/null
+++ b/include/drivers/arm/fvp/fvp_cpu_pwr.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_CPU_PWR_H
+#define FVP_CPU_PWR_H
+
+#ifndef __ASSEMBLER__
+#include <stdbool.h>
+#include <stdint.h>
+
+#if __aarch64__
+bool check_cpupwrctrl_el1_is_available(void);
+#endif /* __aarch64__ */
+#endif /* __ASSEMBLER__ */
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CPUPWRCTLR_EL1                  S3_0_C15_C2_7
+#define CPUPWRCTLR_EL1_CORE_PWRDN_BIT   U(1)
+
+#endif /* FVP_CPU_PWR_H */
diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S
index 8efc238..46fb44a 100644
--- a/plat/arm/board/fvp/aarch64/fvp_helpers.S
+++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S
@@ -6,9 +6,10 @@
 
 #include <arch.h>
 #include <asm_macros.S>
+#include <drivers/arm/fvp/fvp_cpu_pwr.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
 #include <drivers/arm/gicv2.h>
 #include <drivers/arm/gicv3.h>
-#include <drivers/arm/fvp/fvp_pwrc.h>
 #include <platform_def.h>
 
 	.globl	plat_secondary_cold_boot_setup
@@ -29,6 +30,21 @@
 	 */
 func plat_secondary_cold_boot_setup
 #ifndef EL3_PAYLOAD_BASE
+
+	/* --------------------------------------------
+	 * Check if core supports powering down, if it
+	 * supports power down then set core power down
+	 * bit before requesting for the cores to be
+	 * powered off from base power controller.
+	 * ---------------------------------------------
+	 */
+	bl	check_cpupwrctrl_el1_is_available
+	cbz	x0, base_power_off
+
+	mrs	x1, CPUPWRCTLR_EL1
+	orr	x1, x1, #CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	CPUPWRCTLR_EL1, x1
+
 	/* ---------------------------------------------
 	 * Power down this cpu.
 	 * TODO: Do we need to worry about powering the
@@ -37,6 +53,7 @@
 	 * loader zeroes out the zi section.
 	 * ---------------------------------------------
 	 */
+base_power_off:
 	mrs	x0, mpidr_el1
 	mov_imm	x1, PWRC_BASE
 	str	w0, [x1, #PPOFFR_OFF]
diff --git a/plat/arm/board/fvp/fvp_cpu_pwr.c b/plat/arm/board/fvp/fvp_cpu_pwr.c
new file mode 100644
index 0000000..f2771c2
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_cpu_pwr.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if __aarch64__
+
+#include <aem_generic.h>
+#include <arch_helpers.h>
+#include <cortex_a35.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <cortex_a72.h>
+#include <cortex_a73.h>
+#include <cortex_a78_ae.h>
+#include <drivers/arm/fvp/fvp_cpu_pwr.h>
+#include <lib/utils_def.h>
+#include <neoverse_e1.h>
+
+bool check_cpupwrctrl_el1_is_available(void)
+{
+	/* Poupulate list of CPU midr that doesn't support CPUPWRCTL_EL1 */
+	const unsigned int midr_no_cpupwrctl[] = {
+		BASE_AEM_MIDR,
+		CORTEX_A35_MIDR,
+		CORTEX_A53_MIDR,
+		CORTEX_A57_MIDR,
+		CORTEX_A72_MIDR,
+		CORTEX_A73_MIDR,
+		CORTEX_A78_AE_MIDR,
+		NEOVERSE_E1_MIDR
+	};
+	unsigned int midr = (unsigned int)read_midr();
+
+	for (unsigned int i = 0U; i < ARRAY_SIZE(midr_no_cpupwrctl); i++) {
+		if (midr_no_cpupwrctl[i] == midr) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+#endif /* __arch64__ */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 033eb7c..af2b78d 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -222,6 +222,7 @@
 				lib/semihosting/${ARCH}/semihosting_call.S	\
 				plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
 				plat/arm/board/fvp/fvp_bl1_setup.c		\
+				plat/arm/board/fvp/fvp_cpu_pwr.c		\
 				plat/arm/board/fvp/fvp_err.c			\
 				plat/arm/board/fvp/fvp_io_storage.c		\
 				plat/arm/board/fvp/fvp_topology.c		\
@@ -252,7 +253,8 @@
 endif
 
 ifeq (${ENABLE_RME},1)
-BL2_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_helpers.S
+BL2_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_cpu_pwr.c
 
 BL31_SOURCES		+=	plat/arm/board/fvp/fvp_plat_attest_token.c	\
 				plat/arm/board/fvp/fvp_realm_attest_key.c
@@ -264,6 +266,7 @@
 
 ifeq (${RESET_TO_BL2},1)
 BL2_SOURCES		+=	plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_cpu_pwr.c		\
 				plat/arm/board/fvp/fvp_bl2_el3_setup.c		\
 				${FVP_CPU_LIBS}					\
 				${FVP_INTERCONNECT_SOURCES}
@@ -290,6 +293,7 @@
 				plat/arm/board/fvp/fvp_pm.c			\
 				plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/aarch64/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_cpu_pwr.c		\
 				plat/arm/common/arm_nor_psci_mem_protect.c	\
 				${FVP_CPU_LIBS}					\
 				${FVP_GIC_SOURCES}				\