feat(xilinx): power down all cores on receiving cpu pwrdwn req
On receiving CPU power down request from firmware, TF-A raises SGI
interrupt to all active cores for entering in power down state. So add support
for power down core on receiving CPU power down request. PWRDWN_WAIT_TIMEOUT
is the timeout value in milliseconds for the other cores to transition to
power down state.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Change-Id: I29760a2098852c546fa5a1324262a62c3d75b391
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index 8ff4949..3a01dd2 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -17,6 +17,8 @@
#include <common/runtime_svc.h>
#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
#include <plat_private.h>
@@ -32,6 +34,8 @@
#define PM_INIT_SUSPEND_CB (30U)
#define PM_NOTIFY_CB (32U)
#define EVENT_CPU_PWRDWN (4U)
+/* 1 sec of wait timeout for secondary core down */
+#define PWRDWN_WAIT_TIMEOUT (1000U)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
/* pm_up = true - UP, pm_up = false - DOWN */
@@ -63,10 +67,35 @@
return psci_cpu_off();
}
+/**
+ * raise_pwr_down_interrupt() - Callback function to raise SGI.
+ * @mpidr: MPIDR for the target CPU.
+ *
+ * Raise SGI interrupt to trigger the CPU power down sequence on all the
+ * online secondary cores.
+ */
+static void raise_pwr_down_interrupt(u_register_t mpidr)
+{
+ plat_ic_raise_el3_sgi(CPU_PWR_DOWN_REQ_INTR, mpidr);
+}
+
static void request_cpu_pwrdwn(void)
{
+ enum pm_ret_status ret;
+
VERBOSE("CPU power down request received\n");
+
+ /* Send powerdown request to online secondary core(s) */
+ ret = psci_stop_other_cores(PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("Failed to powerdown secondary core(s)\n");
+ }
+
+ /* Clear IPI IRQ */
pm_ipi_irq_clear(primary_proc);
+
+ /* Deactivate IPI IRQ */
+ plat_ic_end_of_interrupt(PLAT_VERSAL_IPI_IRQ);
}
static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
@@ -96,6 +125,7 @@
if (pwrdwn_req_received) {
pwrdwn_req_received = false;
request_cpu_pwrdwn();
+ (void)psci_cpu_off();
break;
} else {
pwrdwn_req_received = true;