1 /* 2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* 8 * Top-level SMC handler for ZynqMP power management calls and 9 * IPI setup functions for communication with PMU. 10 */ 11 12 #include <errno.h> 13 #include <gic_common.h> 14 #include <runtime_svc.h> 15 #include <string.h> 16 #include "../zynqmp_private.h" 17 #include "pm_api_sys.h" 18 #include "pm_client.h" 19 #include "pm_ipi.h" 20 21 #define PM_GET_CALLBACK_DATA 0xa01 22 23 /* 0 - UP, !0 - DOWN */ 24 static int32_t pm_down = !0; 25 26 /** 27 * pm_context - Structure which contains data for power management 28 * @api_version version of PM API, must match with one on PMU side 29 * @payload payload array used to store received 30 * data from ipi buffer registers 31 */ 32 static struct { 33 uint32_t api_version; 34 uint32_t payload[PAYLOAD_ARG_CNT]; 35 } pm_ctx; 36 37 /** 38 * pm_setup() - PM service setup 39 * 40 * @return On success, the initialization function must return 0. 41 * Any other return value will cause the framework to ignore 42 * the service 43 * 44 * Initialization functions for ZynqMP power management for 45 * communicaton with PMU. 46 * 47 * Called from sip_svc_setup initialization function with the 48 * rt_svc_init signature. 49 */ 50 int pm_setup(void) 51 { 52 int status; 53 54 if (!zynqmp_is_pmu_up()) 55 return -ENODEV; 56 57 status = pm_ipi_init(); 58 59 if (status == 0) 60 INFO("BL31: PM Service Init Complete: API v%d.%d\n", 61 PM_VERSION_MAJOR, PM_VERSION_MINOR); 62 else 63 INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); 64 65 pm_down = status; 66 67 return status; 68 } 69 70 /** 71 * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. 72 * @smc_fid - Function Identifier 73 * @x1 - x4 - Arguments 74 * @cookie - Unused 75 * @handler - Pointer to caller's context structure 76 * 77 * @return - Unused 78 * 79 * Determines that smc_fid is valid and supported PM SMC Function ID from the 80 * list of pm_api_ids, otherwise completes the request with 81 * the unknown SMC Function ID 82 * 83 * The SMC calls for PM service are forwarded from SIP Service SMC handler 84 * function with rt_svc_handle signature 85 */ 86 uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, 87 uint64_t x4, void *cookie, void *handle, uint64_t flags) 88 { 89 enum pm_ret_status ret; 90 91 uint32_t pm_arg[4]; 92 93 /* Handle case where PM wasn't initialized properly */ 94 if (pm_down) 95 SMC_RET1(handle, SMC_UNK); 96 97 pm_arg[0] = (uint32_t)x1; 98 pm_arg[1] = (uint32_t)(x1 >> 32); 99 pm_arg[2] = (uint32_t)x2; 100 pm_arg[3] = (uint32_t)(x2 >> 32); 101 102 switch (smc_fid & FUNCID_NUM_MASK) { 103 /* PM API Functions */ 104 case PM_SELF_SUSPEND: 105 ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], 106 pm_arg[3]); 107 SMC_RET1(handle, (uint64_t)ret); 108 109 case PM_REQ_SUSPEND: 110 ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], 111 pm_arg[3]); 112 SMC_RET1(handle, (uint64_t)ret); 113 114 case PM_REQ_WAKEUP: 115 ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], 116 pm_arg[3]); 117 SMC_RET1(handle, (uint64_t)ret); 118 119 case PM_FORCE_POWERDOWN: 120 ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); 121 SMC_RET1(handle, (uint64_t)ret); 122 123 case PM_ABORT_SUSPEND: 124 ret = pm_abort_suspend(pm_arg[0]); 125 SMC_RET1(handle, (uint64_t)ret); 126 127 case PM_SET_WAKEUP_SOURCE: 128 ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]); 129 SMC_RET1(handle, (uint64_t)ret); 130 131 case PM_SYSTEM_SHUTDOWN: 132 ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); 133 SMC_RET1(handle, (uint64_t)ret); 134 135 case PM_REQ_NODE: 136 ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); 137 SMC_RET1(handle, (uint64_t)ret); 138 139 case PM_RELEASE_NODE: 140 ret = pm_release_node(pm_arg[0]); 141 SMC_RET1(handle, (uint64_t)ret); 142 143 case PM_SET_REQUIREMENT: 144 ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2], 145 pm_arg[3]); 146 SMC_RET1(handle, (uint64_t)ret); 147 148 case PM_SET_MAX_LATENCY: 149 ret = pm_set_max_latency(pm_arg[0], pm_arg[1]); 150 SMC_RET1(handle, (uint64_t)ret); 151 152 case PM_GET_API_VERSION: 153 /* Check is PM API version already verified */ 154 if (pm_ctx.api_version == PM_VERSION) { 155 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | 156 ((uint64_t)PM_VERSION << 32)); 157 } 158 159 ret = pm_get_api_version(&pm_ctx.api_version); 160 /* 161 * Enable IPI IRQ 162 * assume the rich OS is OK to handle callback IRQs now. 163 * Even if we were wrong, it would not enable the IRQ in 164 * the GIC. 165 */ 166 pm_ipi_irq_enable(); 167 SMC_RET1(handle, (uint64_t)ret | 168 ((uint64_t)pm_ctx.api_version << 32)); 169 170 case PM_SET_CONFIGURATION: 171 ret = pm_set_configuration(pm_arg[0]); 172 SMC_RET1(handle, (uint64_t)ret); 173 174 case PM_GET_NODE_STATUS: 175 ret = pm_get_node_status(pm_arg[0]); 176 SMC_RET1(handle, (uint64_t)ret); 177 178 case PM_GET_OP_CHARACTERISTIC: 179 { 180 uint32_t result; 181 182 ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result); 183 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32)); 184 } 185 186 case PM_REGISTER_NOTIFIER: 187 ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2], 188 pm_arg[3]); 189 SMC_RET1(handle, (uint64_t)ret); 190 191 case PM_RESET_ASSERT: 192 ret = pm_reset_assert(pm_arg[0], pm_arg[1]); 193 SMC_RET1(handle, (uint64_t)ret); 194 195 case PM_RESET_GET_STATUS: 196 { 197 uint32_t reset_status; 198 199 ret = pm_reset_get_status(pm_arg[0], &reset_status); 200 SMC_RET1(handle, (uint64_t)ret | 201 ((uint64_t)reset_status << 32)); 202 } 203 204 /* PM memory access functions */ 205 case PM_MMIO_WRITE: 206 ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]); 207 SMC_RET1(handle, (uint64_t)ret); 208 209 case PM_MMIO_READ: 210 { 211 uint32_t value; 212 213 ret = pm_mmio_read(pm_arg[0], &value); 214 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); 215 } 216 217 case PM_FPGA_LOAD: 218 ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); 219 SMC_RET1(handle, (uint64_t)ret); 220 221 case PM_FPGA_GET_STATUS: 222 { 223 uint32_t value; 224 225 ret = pm_fpga_get_status(&value); 226 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); 227 } 228 229 case PM_GET_CHIPID: 230 { 231 uint32_t result[2]; 232 233 ret = pm_get_chipid(result); 234 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32), 235 result[1]); 236 } 237 238 case PM_GET_CALLBACK_DATA: 239 { 240 uint32_t result[4]; 241 242 pm_get_callbackdata(result, sizeof(result)); 243 SMC_RET2(handle, 244 (uint64_t)result[0] | ((uint64_t)result[1] << 32), 245 (uint64_t)result[2] | ((uint64_t)result[3] << 32)); 246 } 247 248 default: 249 WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); 250 SMC_RET1(handle, SMC_UNK); 251 } 252 } 253