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