Commit 586621f1 authored by Andrew F. Davis's avatar Andrew F. Davis
Browse files

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: default avatarAndrew F. Davis <afd@ti.com>
Change-Id: I0ffeb339852c66ef62743aecd3e17ca20bad6216
parent 9f49a177
......@@ -27,5 +27,6 @@
#define PLAT_PROC_START_ID 32
#define PLAT_PROC_DEVICE_START_ID 202
#define PLAT_CLUSTER_DEVICE_START_ID 198
#endif /* BOARD_DEF_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
......
......@@ -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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment