xref: /rk3399_ARM-atf/drivers/arm/css/scp/css_pm_scpi.c (revision 139a5d05219e915687057527504f689281744736)
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