1 /* 2 * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 8 #include <arch_helpers.h> 9 10 #include <lib/bakery_lock.h> 11 #include <lib/mmio.h> 12 13 #include <ipi.h> 14 #include <plat_ipi.h> 15 #include <plat_private.h> 16 #include <plat/common/platform.h> 17 18 #include "pm_ipi.h" 19 20 21 #define ERROR_CODE_MASK 0xFFFFU 22 23 DEFINE_BAKERY_LOCK(pm_secure_lock); 24 25 /** 26 * pm_ipi_init() - Initialize IPI peripheral for communication with 27 * remote processor 28 * 29 * @proc Pointer to the processor who is initiating request 30 * @return On success, the initialization function must return 0. 31 * Any other return value will cause the framework to ignore 32 * the service 33 * 34 * Called from pm_setup initialization function 35 */ 36 int pm_ipi_init(const struct pm_proc *proc) 37 { 38 bakery_lock_init(&pm_secure_lock); 39 ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); 40 41 return 0; 42 } 43 44 /** 45 * pm_ipi_send_common() - Sends IPI request to the remote processor 46 * @proc Pointer to the processor who is initiating request 47 * @payload API id and call arguments to be written in IPI buffer 48 * 49 * Send an IPI request to the power controller. Caller needs to hold 50 * the 'pm_secure_lock' lock. 51 * 52 * @return Returns status, either success or error+reason 53 */ 54 static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, 55 uint32_t payload[PAYLOAD_ARG_CNT], 56 uint32_t is_blocking) 57 { 58 unsigned int offset = 0; 59 uintptr_t buffer_base = proc->ipi->buffer_base + 60 IPI_BUFFER_TARGET_REMOTE_OFFSET + 61 IPI_BUFFER_REQ_OFFSET; 62 #if IPI_CRC_CHECK 63 payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE); 64 #endif 65 66 /* Write payload into IPI buffer */ 67 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { 68 mmio_write_32(buffer_base + offset, payload[i]); 69 offset += PAYLOAD_ARG_SIZE; 70 } 71 72 /* Generate IPI to remote processor */ 73 ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id, 74 is_blocking); 75 76 return PM_RET_SUCCESS; 77 } 78 79 /** 80 * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor 81 * without blocking notification 82 * @proc Pointer to the processor who is initiating request 83 * @payload API id and call arguments to be written in IPI buffer 84 * 85 * Send an IPI request to the power controller. 86 * 87 * @return Returns status, either success or error+reason 88 */ 89 enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, 90 uint32_t payload[PAYLOAD_ARG_CNT]) 91 { 92 enum pm_ret_status ret; 93 94 bakery_lock_get(&pm_secure_lock); 95 96 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING); 97 98 bakery_lock_release(&pm_secure_lock); 99 100 return ret; 101 } 102 103 /** 104 * pm_ipi_send() - Sends IPI request to the remote processor 105 * @proc Pointer to the processor who is initiating request 106 * @payload API id and call arguments to be written in IPI buffer 107 * 108 * Send an IPI request to the power controller. 109 * 110 * @return Returns status, either success or error+reason 111 */ 112 enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, 113 uint32_t payload[PAYLOAD_ARG_CNT]) 114 { 115 enum pm_ret_status ret; 116 117 bakery_lock_get(&pm_secure_lock); 118 119 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); 120 121 bakery_lock_release(&pm_secure_lock); 122 123 return ret; 124 } 125 126 127 /** 128 * pm_ipi_buff_read() - Reads IPI response after remote processor has handled 129 * interrupt 130 * @proc Pointer to the processor who is waiting and reading response 131 * @value Used to return value from IPI buffer element (optional) 132 * @count Number of values to return in @value 133 * 134 * @return Returns status, either success or error+reason 135 */ 136 static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, 137 unsigned int *value, size_t count) 138 { 139 size_t i; 140 #if IPI_CRC_CHECK 141 size_t j; 142 unsigned int response_payload[PAYLOAD_ARG_CNT]; 143 #endif 144 uintptr_t buffer_base = proc->ipi->buffer_base + 145 IPI_BUFFER_TARGET_REMOTE_OFFSET + 146 IPI_BUFFER_RESP_OFFSET; 147 148 /* 149 * Read response from IPI buffer 150 * buf-0: success or error+reason 151 * buf-1: value 152 * buf-2: unused 153 * buf-3: unused 154 */ 155 for (i = 1; i <= count; i++) { 156 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 157 value++; 158 } 159 #if IPI_CRC_CHECK 160 for (j = 0; j < PAYLOAD_ARG_CNT; j++) 161 response_payload[j] = mmio_read_32(buffer_base + 162 (j * PAYLOAD_ARG_SIZE)); 163 164 if (response_payload[PAYLOAD_CRC_POS] != 165 calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) 166 NOTICE("ERROR in CRC response payload value:0x%x\n", 167 response_payload[PAYLOAD_CRC_POS]); 168 #endif 169 170 return mmio_read_32(buffer_base); 171 } 172 173 /** 174 * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has 175 * handled interrupt 176 * @value Used to return value from IPI buffer element (optional) 177 * @count Number of values to return in @value 178 * 179 * @return Returns status, either success or error+reason 180 */ 181 void pm_ipi_buff_read_callb(unsigned int *value, size_t count) 182 { 183 size_t i; 184 #if IPI_CRC_CHECK 185 size_t j; 186 unsigned int response_payload[PAYLOAD_ARG_CNT]; 187 #endif 188 uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE + 189 IPI_BUFFER_TARGET_LOCAL_OFFSET + 190 IPI_BUFFER_REQ_OFFSET; 191 192 if (count > IPI_BUFFER_MAX_WORDS) 193 count = IPI_BUFFER_MAX_WORDS; 194 195 for (i = 0; i <= count; i++) { 196 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 197 value++; 198 } 199 #if IPI_CRC_CHECK 200 for (j = 0; j < PAYLOAD_ARG_CNT; j++) 201 response_payload[j] = mmio_read_32(buffer_base + 202 (j * PAYLOAD_ARG_SIZE)); 203 204 if (response_payload[PAYLOAD_CRC_POS] != 205 calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) 206 NOTICE("ERROR in CRC response payload value:0x%x\n", 207 response_payload[PAYLOAD_CRC_POS]); 208 #endif 209 } 210 211 /** 212 * pm_ipi_send_sync() - Sends IPI request to the remote processor 213 * @proc Pointer to the processor who is initiating request 214 * @payload API id and call arguments to be written in IPI buffer 215 * @value Used to return value from IPI buffer element (optional) 216 * @count Number of values to return in @value 217 * 218 * Send an IPI request to the power controller and wait for it to be handled. 219 * 220 * @return Returns status, either success or error+reason and, optionally, 221 * @value 222 */ 223 enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, 224 uint32_t payload[PAYLOAD_ARG_CNT], 225 unsigned int *value, size_t count) 226 { 227 enum pm_ret_status ret; 228 229 bakery_lock_get(&pm_secure_lock); 230 231 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); 232 if (ret != PM_RET_SUCCESS) 233 goto unlock; 234 235 ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count)); 236 237 unlock: 238 bakery_lock_release(&pm_secure_lock); 239 240 return ret; 241 } 242 243 void pm_ipi_irq_enable(const struct pm_proc *proc) 244 { 245 ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); 246 } 247 248 void pm_ipi_irq_clear(const struct pm_proc *proc) 249 { 250 ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); 251 } 252 253 uint32_t pm_ipi_irq_status(const struct pm_proc *proc) 254 { 255 int ret; 256 257 ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id, 258 proc->ipi->remote_ipi_id); 259 if (ret & IPI_MB_STATUS_RECV_PENDING) 260 return 1; 261 else 262 return 0; 263 } 264 265 #if IPI_CRC_CHECK 266 uint32_t calculate_crc(uint32_t *payload, uint32_t bufsize) 267 { 268 uint32_t crcinit = CRC_INIT_VALUE; 269 uint32_t order = CRC_ORDER; 270 uint32_t polynom = CRC_POLYNOM; 271 uint32_t i, j, c, bit, datain, crcmask, crchighbit; 272 uint32_t crc = crcinit; 273 274 crcmask = ((uint32_t)((1U << (order - 1U)) - 1U) << 1U) | 1U; 275 crchighbit = (uint32_t)(1U << (order - 1U)); 276 277 for (i = 0U; i < bufsize; i++) { 278 datain = mmio_read_8((unsigned long)payload + i); 279 c = datain; 280 j = 0x80U; 281 while (j != 0U) { 282 bit = crc & crchighbit; 283 crc <<= 1U; 284 if (0U != (c & j)) 285 bit ^= crchighbit; 286 if (bit != 0U) 287 crc ^= polynom; 288 j >>= 1U; 289 } 290 crc &= crcmask; 291 } 292 return crc; 293 } 294 #endif 295