1 /* 2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch_helpers.h> 8 #include <assert.h> 9 #include <css_pm.h> 10 #include <debug.h> 11 #include <plat_arm.h> 12 #include "../scpi/css_scpi.h" 13 #include "css_scp.h" 14 15 /* 16 * This file implements the SCP power management functions using SCPI protocol. 17 */ 18 19 /* 20 * Helper function to inform power down state to SCP. 21 */ 22 void css_scp_suspend(const psci_power_state_t *target_state) 23 { 24 uint32_t cluster_state = scpi_power_on; 25 uint32_t system_state = scpi_power_on; 26 27 /* Check if power down at system power domain level is requested */ 28 if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 29 system_state = scpi_power_retention; 30 31 /* Cluster is to be turned off, so disable coherency */ 32 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 33 cluster_state = scpi_power_off; 34 35 /* 36 * Ask the SCP to power down the appropriate components depending upon 37 * their state. 38 */ 39 scpi_set_css_power_state(read_mpidr_el1(), 40 scpi_power_off, 41 cluster_state, 42 system_state); 43 } 44 45 /* 46 * Helper function to turn off a CPU power domain and its parent power domains 47 * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we 48 * call the suspend helper here. 49 */ 50 void css_scp_off(const psci_power_state_t *target_state) 51 { 52 css_scp_suspend(target_state); 53 } 54 55 /* 56 * Helper function to turn ON a CPU power domain and its parent power domains 57 * if applicable. 58 */ 59 void css_scp_on(u_register_t mpidr) 60 { 61 /* 62 * SCP takes care of powering up parent power domains so we 63 * only need to care about level 0 64 */ 65 scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, 66 scpi_power_on); 67 } 68 69 /* 70 * Helper function to get the power state of a power domain node as reported 71 * by the SCP. 72 */ 73 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) 74 { 75 int rc, element; 76 unsigned int cpu_state, cluster_state; 77 78 /* 79 * The format of 'power_level' is implementation-defined, but 0 must 80 * mean a CPU. We also allow 1 to denote the cluster 81 */ 82 if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1) 83 return PSCI_E_INVALID_PARAMS; 84 85 /* Query SCP */ 86 rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state); 87 if (rc != 0) 88 return PSCI_E_INVALID_PARAMS; 89 90 /* Map power states of CPU and cluster to expected PSCI return codes */ 91 if (power_level == ARM_PWR_LVL0) { 92 /* 93 * The CPU state returned by SCP is an 8-bit bit mask 94 * corresponding to each CPU in the cluster 95 */ 96 #if ARM_PLAT_MT 97 /* 98 * The current SCPI driver only caters for single-threaded 99 * platforms. Hence we ignore the thread ID (which is always 0) 100 * for such platforms. 101 */ 102 element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; 103 #else 104 element = mpidr & MPIDR_AFFLVL_MASK; 105 #endif /* ARM_PLAT_MT */ 106 return CSS_CPU_PWR_STATE(cpu_state, element) == 107 CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF; 108 } else { 109 assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON || 110 cluster_state == CSS_CLUSTER_PWR_STATE_OFF); 111 return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON : 112 HW_OFF; 113 } 114 } 115 116 /* 117 * Helper function to shutdown the system via SCPI. 118 */ 119 void __dead2 css_scp_sys_shutdown(void) 120 { 121 uint32_t response; 122 123 /* 124 * Disable GIC CPU interface to prevent pending interrupt 125 * from waking up the AP from WFI. 126 */ 127 plat_arm_gic_cpuif_disable(); 128 129 /* Send the power down request to the SCP */ 130 response = scpi_sys_power_state(scpi_system_shutdown); 131 132 if (response != SCP_OK) { 133 ERROR("CSS System Off: SCP error %u.\n", response); 134 panic(); 135 } 136 wfi(); 137 ERROR("CSS System Off: operation not handled.\n"); 138 panic(); 139 } 140 141 /* 142 * Helper function to reset the system via SCPI. 143 */ 144 void __dead2 css_scp_sys_reboot(void) 145 { 146 uint32_t response; 147 148 /* 149 * Disable GIC CPU interface to prevent pending interrupt 150 * from waking up the AP from WFI. 151 */ 152 plat_arm_gic_cpuif_disable(); 153 154 /* Send the system reset request to the SCP */ 155 response = scpi_sys_power_state(scpi_system_reboot); 156 157 if (response != SCP_OK) { 158 ERROR("CSS System Reset: SCP error %u.\n", response); 159 panic(); 160 } 161 wfi(); 162 ERROR("CSS System Reset: operation not handled.\n"); 163 panic(); 164 } 165