12d4135e0SAntonio Nino Diaz /*
2*c5c54e20SBoyan Karatotev * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
32d4135e0SAntonio Nino Diaz *
42d4135e0SAntonio Nino Diaz * SPDX-License-Identifier: BSD-3-Clause
52d4135e0SAntonio Nino Diaz */
62d4135e0SAntonio Nino Diaz
72d4135e0SAntonio Nino Diaz #include <assert.h>
82d4135e0SAntonio Nino Diaz
92d4135e0SAntonio Nino Diaz #include <arch_helpers.h>
102d4135e0SAntonio Nino Diaz #include <common/debug.h>
112d4135e0SAntonio Nino Diaz #include <drivers/arm/css/css_scp.h>
122d4135e0SAntonio Nino Diaz #include <drivers/arm/css/css_scpi.h>
132d4135e0SAntonio Nino Diaz #include <plat/arm/common/plat_arm.h>
142d4135e0SAntonio Nino Diaz #include <plat/arm/css/common/css_pm.h>
152d4135e0SAntonio Nino Diaz
162d4135e0SAntonio Nino Diaz /*
172d4135e0SAntonio Nino Diaz * This file implements the SCP power management functions using SCPI protocol.
182d4135e0SAntonio Nino Diaz */
192d4135e0SAntonio Nino Diaz
202d4135e0SAntonio Nino Diaz /*
212d4135e0SAntonio Nino Diaz * Helper function to inform power down state to SCP.
222d4135e0SAntonio Nino Diaz */
css_scp_suspend(const struct psci_power_state * target_state)232d4135e0SAntonio Nino Diaz void css_scp_suspend(const struct psci_power_state *target_state)
242d4135e0SAntonio Nino Diaz {
252d4135e0SAntonio Nino Diaz uint32_t cluster_state = scpi_power_on;
262d4135e0SAntonio Nino Diaz uint32_t system_state = scpi_power_on;
272d4135e0SAntonio Nino Diaz
282d4135e0SAntonio Nino Diaz /* Check if power down at system power domain level is requested */
292d4135e0SAntonio Nino Diaz if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
302d4135e0SAntonio Nino Diaz system_state = scpi_power_retention;
312d4135e0SAntonio Nino Diaz
322d4135e0SAntonio Nino Diaz /* Cluster is to be turned off, so disable coherency */
332d4135e0SAntonio Nino Diaz if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
342d4135e0SAntonio Nino Diaz cluster_state = scpi_power_off;
352d4135e0SAntonio Nino Diaz
362d4135e0SAntonio Nino Diaz /*
372d4135e0SAntonio Nino Diaz * Ask the SCP to power down the appropriate components depending upon
382d4135e0SAntonio Nino Diaz * their state.
392d4135e0SAntonio Nino Diaz */
402d4135e0SAntonio Nino Diaz scpi_set_css_power_state(read_mpidr_el1(),
412d4135e0SAntonio Nino Diaz scpi_power_off,
422d4135e0SAntonio Nino Diaz cluster_state,
432d4135e0SAntonio Nino Diaz system_state);
442d4135e0SAntonio Nino Diaz }
452d4135e0SAntonio Nino Diaz
462d4135e0SAntonio Nino Diaz /*
472d4135e0SAntonio Nino Diaz * Helper function to turn off a CPU power domain and its parent power domains
482d4135e0SAntonio Nino Diaz * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
492d4135e0SAntonio Nino Diaz * call the suspend helper here.
502d4135e0SAntonio Nino Diaz */
css_scp_off(const struct psci_power_state * target_state)512d4135e0SAntonio Nino Diaz void css_scp_off(const struct psci_power_state *target_state)
522d4135e0SAntonio Nino Diaz {
532d4135e0SAntonio Nino Diaz css_scp_suspend(target_state);
542d4135e0SAntonio Nino Diaz }
552d4135e0SAntonio Nino Diaz
562d4135e0SAntonio Nino Diaz /*
572d4135e0SAntonio Nino Diaz * Helper function to turn ON a CPU power domain and its parent power domains
582d4135e0SAntonio Nino Diaz * if applicable.
592d4135e0SAntonio Nino Diaz */
css_scp_on(u_register_t mpidr)602d4135e0SAntonio Nino Diaz void css_scp_on(u_register_t mpidr)
612d4135e0SAntonio Nino Diaz {
622d4135e0SAntonio Nino Diaz /*
632d4135e0SAntonio Nino Diaz * SCP takes care of powering up parent power domains so we
642d4135e0SAntonio Nino Diaz * only need to care about level 0
652d4135e0SAntonio Nino Diaz */
662d4135e0SAntonio Nino Diaz scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
672d4135e0SAntonio Nino Diaz scpi_power_on);
682d4135e0SAntonio Nino Diaz }
692d4135e0SAntonio Nino Diaz
702d4135e0SAntonio Nino Diaz /*
712d4135e0SAntonio Nino Diaz * Helper function to get the power state of a power domain node as reported
722d4135e0SAntonio Nino Diaz * by the SCP.
732d4135e0SAntonio Nino Diaz */
css_scp_get_power_state(u_register_t mpidr,unsigned int power_level)742d4135e0SAntonio Nino Diaz int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
752d4135e0SAntonio Nino Diaz {
762d4135e0SAntonio Nino Diaz int rc, element;
772d4135e0SAntonio Nino Diaz unsigned int cpu_state, cluster_state;
782d4135e0SAntonio Nino Diaz
792d4135e0SAntonio Nino Diaz /*
802d4135e0SAntonio Nino Diaz * The format of 'power_level' is implementation-defined, but 0 must
812d4135e0SAntonio Nino Diaz * mean a CPU. We also allow 1 to denote the cluster
822d4135e0SAntonio Nino Diaz */
832d4135e0SAntonio Nino Diaz if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
842d4135e0SAntonio Nino Diaz return PSCI_E_INVALID_PARAMS;
852d4135e0SAntonio Nino Diaz
862d4135e0SAntonio Nino Diaz /* Query SCP */
872d4135e0SAntonio Nino Diaz rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
882d4135e0SAntonio Nino Diaz if (rc != 0)
892d4135e0SAntonio Nino Diaz return PSCI_E_INVALID_PARAMS;
902d4135e0SAntonio Nino Diaz
912d4135e0SAntonio Nino Diaz /* Map power states of CPU and cluster to expected PSCI return codes */
922d4135e0SAntonio Nino Diaz if (power_level == ARM_PWR_LVL0) {
932d4135e0SAntonio Nino Diaz /*
942d4135e0SAntonio Nino Diaz * The CPU state returned by SCP is an 8-bit bit mask
952d4135e0SAntonio Nino Diaz * corresponding to each CPU in the cluster
962d4135e0SAntonio Nino Diaz */
972d4135e0SAntonio Nino Diaz #if ARM_PLAT_MT
982d4135e0SAntonio Nino Diaz /*
992d4135e0SAntonio Nino Diaz * The current SCPI driver only caters for single-threaded
1002d4135e0SAntonio Nino Diaz * platforms. Hence we ignore the thread ID (which is always 0)
1012d4135e0SAntonio Nino Diaz * for such platforms.
1022d4135e0SAntonio Nino Diaz */
1032d4135e0SAntonio Nino Diaz element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
1042d4135e0SAntonio Nino Diaz #else
1052d4135e0SAntonio Nino Diaz element = mpidr & MPIDR_AFFLVL_MASK;
1062d4135e0SAntonio Nino Diaz #endif /* ARM_PLAT_MT */
1072d4135e0SAntonio Nino Diaz return CSS_CPU_PWR_STATE(cpu_state, element) ==
1082d4135e0SAntonio Nino Diaz CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
1092d4135e0SAntonio Nino Diaz } else {
1102d4135e0SAntonio Nino Diaz assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
1112d4135e0SAntonio Nino Diaz cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
1122d4135e0SAntonio Nino Diaz return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
1132d4135e0SAntonio Nino Diaz HW_OFF;
1142d4135e0SAntonio Nino Diaz }
1152d4135e0SAntonio Nino Diaz }
1162d4135e0SAntonio Nino Diaz
1172d4135e0SAntonio Nino Diaz /*
1182d4135e0SAntonio Nino Diaz * Helper function to shutdown the system via SCPI.
1192d4135e0SAntonio Nino Diaz */
css_scp_sys_shutdown(void)120da305ec7SBoyan Karatotev void css_scp_sys_shutdown(void)
1212d4135e0SAntonio Nino Diaz {
1222d4135e0SAntonio Nino Diaz uint32_t response;
1232d4135e0SAntonio Nino Diaz
1242d4135e0SAntonio Nino Diaz /* Send the power down request to the SCP */
1252d4135e0SAntonio Nino Diaz response = scpi_sys_power_state(scpi_system_shutdown);
1262d4135e0SAntonio Nino Diaz
1272d4135e0SAntonio Nino Diaz if (response != SCP_OK) {
1282d4135e0SAntonio Nino Diaz ERROR("CSS System Off: SCP error %u.\n", response);
1292d4135e0SAntonio Nino Diaz panic();
1302d4135e0SAntonio Nino Diaz }
1312d4135e0SAntonio Nino Diaz }
1322d4135e0SAntonio Nino Diaz
1332d4135e0SAntonio Nino Diaz /*
1342d4135e0SAntonio Nino Diaz * Helper function to reset the system via SCPI.
1352d4135e0SAntonio Nino Diaz */
css_scp_sys_reboot(void)136da305ec7SBoyan Karatotev void css_scp_sys_reboot(void)
1372d4135e0SAntonio Nino Diaz {
1382d4135e0SAntonio Nino Diaz uint32_t response;
1392d4135e0SAntonio Nino Diaz
1402d4135e0SAntonio Nino Diaz /* Send the system reset request to the SCP */
1412d4135e0SAntonio Nino Diaz response = scpi_sys_power_state(scpi_system_reboot);
1422d4135e0SAntonio Nino Diaz
1432d4135e0SAntonio Nino Diaz if (response != SCP_OK) {
1442d4135e0SAntonio Nino Diaz ERROR("CSS System Reset: SCP error %u.\n", response);
1452d4135e0SAntonio Nino Diaz panic();
1462d4135e0SAntonio Nino Diaz }
1472d4135e0SAntonio Nino Diaz }
148