aboutsummaryrefslogtreecommitdiff
path: root/plat/ti/k3/common
diff options
context:
space:
mode:
authorAndrew F. Davis <afd@ti.com>2019-02-11 16:12:31 -0600
committerAndrew F. Davis <afd@ti.com>2020-01-27 13:26:01 -0500
commit586621f110b082e6a812ce8e9acbd21ca3d162cd (patch)
treeba2584d979f5a2c3bcd5de26e62b2f00ae364e86 /plat/ti/k3/common
parent9f49a177c61aced991339668766843fdc93ff2bf (diff)
downloadtrusted-firmware-a-586621f110b082e6a812ce8e9acbd21ca3d162cd.tar.gz
ti: k3: common: Enable ARM cluster power down
When all cores in a cluster are powered down the parent cluster can be also powered down. When the last core has requested powering down follow by sending the cluster power down sequence to the system power controller firmware. Signed-off-by: Andrew F. Davis <afd@ti.com> Change-Id: I0ffeb339852c66ef62743aecd3e17ca20bad6216
Diffstat (limited to 'plat/ti/k3/common')
-rw-r--r--plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h9
-rw-r--r--plat/ti/k3/common/k3_psci.c95
2 files changed, 102 insertions, 2 deletions
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
index a921e512a8..2d23f9a9cf 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
@@ -563,8 +563,13 @@ struct ti_sci_msg_req_set_proc_boot_config {
uint32_t config_flags_clear;
} __packed;
+/* ARMV8 Control Flags */
+#define PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM 0x00000001
+#define PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS 0x00000002
+#define PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ 0x00000100
+
/* R5 Control Flags */
-#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
+#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
/**
* struct ti_sci_msg_req_set_proc_boot_ctrl - Set Processor boot control flags
@@ -618,6 +623,8 @@ struct ti_sci_msg_req_get_proc_boot_status {
/* ARMv8 Status Flags */
#define PROC_BOOT_STATUS_FLAG_ARMV8_WFE 0x00000001
#define PROC_BOOT_STATUS_FLAG_ARMV8_WFI 0x00000002
+#define PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE 0x00000010
+#define PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2 0x00000020
/* R5 Status Flags */
#define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001
diff --git a/plat/ti/k3/common/k3_psci.c b/plat/ti/k3/common/k3_psci.c
index 15bdc3e253..cf0a21d018 100644
--- a/plat/ti/k3/common/k3_psci.c
+++ b/plat/ti/k3/common/k3_psci.c
@@ -17,6 +17,10 @@
#include <k3_gicv3.h>
#include <ti_sci.h>
+#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
uintptr_t k3_sec_entrypoint;
static void k3_cpu_standby(plat_local_state_t cpu_state)
@@ -60,6 +64,16 @@ static int k3_pwr_domain_on(u_register_t mpidr)
return PSCI_E_INTERN_FAIL;
}
+ /* sanity check these are off before starting a core */
+ ret = ti_sci_proc_set_boot_ctrl(proc_id,
+ 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
+ PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
+ PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
+ if (ret) {
+ ERROR("Request to clear boot configuration failed: %d\n", ret);
+ return PSCI_E_INTERN_FAIL;
+ }
+
ret = ti_sci_device_get(device_id);
if (ret) {
ERROR("Request to start core failed: %d\n", ret);
@@ -71,14 +85,32 @@ static int k3_pwr_domain_on(u_register_t mpidr)
void k3_pwr_domain_off(const psci_power_state_t *target_state)
{
- int core, proc_id, device_id, ret;
+ int core, cluster, proc_id, device_id, cluster_id, ret;
+
+ /* At very least the local core should be powering down */
+ assert(CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
/* Prevent interrupts from spuriously waking up this cpu */
k3_gic_cpuif_disable();
core = plat_my_core_pos();
+ cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
proc_id = PLAT_PROC_START_ID + core;
device_id = PLAT_PROC_DEVICE_START_ID + core;
+ cluster_id = PLAT_CLUSTER_DEVICE_START_ID + (cluster * 2);
+
+ /*
+ * If we are the last core in the cluster then we take a reference to
+ * the cluster device so that it does not get shutdown before we
+ * execute the entire cluster L2 cleaning sequence below.
+ */
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+ ret = ti_sci_device_get(cluster_id);
+ if (ret) {
+ ERROR("Request to get cluster failed: %d\n", ret);
+ return;
+ }
+ }
/* Start by sending wait for WFI command */
ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
@@ -100,6 +132,67 @@ void k3_pwr_domain_off(const psci_power_state_t *target_state)
ERROR("Sending core shutdown message failed (%d)\n", ret);
return;
}
+
+ /* If our cluster is not going down we stop here */
+ if (CLUSTER_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+ return;
+
+ /* set AINACTS */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* set L2FLUSHREQ */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* wait for L2FLUSHDONE*/
+ ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
+ UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
+ PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE, 0, 0, 0);
+ if (ret) {
+ ERROR("Sending wait message failed (%d)\n", ret);
+ return;
+ }
+
+ /* clear L2FLUSHREQ */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* set ACINACTM */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* wait for STANDBYWFIL2 */
+ ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
+ UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
+ PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2, 0, 0, 0);
+ if (ret) {
+ ERROR("Sending wait message failed (%d)\n", ret);
+ return;
+ }
+
+ /* Now queue up the cluster shutdown request */
+ ret = ti_sci_device_put_no_wait(cluster_id);
+ if (ret) {
+ ERROR("Sending cluster shutdown message failed (%d)\n", ret);
+ return;
+ }
}
void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)