diff --git a/plat/ti/k3/board/generic/include/board_def.h b/plat/ti/k3/board/generic/include/board_def.h index c1a5966..0d45116 100644 --- a/plat/ti/k3/board/generic/include/board_def.h +++ b/plat/ti/k3/board/generic/include/board_def.h @@ -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 */ 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 a921e51..2d23f9a 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 @@ 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 @@ /* 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 15bdc3e..cf0a21d 100644 --- a/plat/ti/k3/common/k3_psci.c +++ b/plat/ti/k3/common/k3_psci.c @@ -17,6 +17,10 @@ #include #include +#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 @@ 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 @@ 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 @@ 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)