1 /* 2 * Copyright (c) 2013-2018, 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 61 /* Write payload into IPI buffer */ 62 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { 63 mmio_write_32(buffer_base + offset, payload[i]); 64 offset += PAYLOAD_ARG_SIZE; 65 } 66 67 /* Generate IPI to remote processor */ 68 ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id, 69 is_blocking); 70 71 return PM_RET_SUCCESS; 72 } 73 74 /** 75 * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor 76 * without blocking notification 77 * @proc Pointer to the processor who is initiating request 78 * @payload API id and call arguments to be written in IPI buffer 79 * 80 * Send an IPI request to the power controller. 81 * 82 * @return Returns status, either success or error+reason 83 */ 84 enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, 85 uint32_t payload[PAYLOAD_ARG_CNT]) 86 { 87 enum pm_ret_status ret; 88 89 bakery_lock_get(&pm_secure_lock); 90 91 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING); 92 93 bakery_lock_release(&pm_secure_lock); 94 95 return ret; 96 } 97 98 /** 99 * pm_ipi_send() - Sends IPI request to the remote processor 100 * @proc Pointer to the processor who is initiating request 101 * @payload API id and call arguments to be written in IPI buffer 102 * 103 * Send an IPI request to the power controller. 104 * 105 * @return Returns status, either success or error+reason 106 */ 107 enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, 108 uint32_t payload[PAYLOAD_ARG_CNT]) 109 { 110 enum pm_ret_status ret; 111 112 bakery_lock_get(&pm_secure_lock); 113 114 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); 115 116 bakery_lock_release(&pm_secure_lock); 117 118 return ret; 119 } 120 121 122 /** 123 * pm_ipi_buff_read() - Reads IPI response after remote processor has handled 124 * interrupt 125 * @proc Pointer to the processor who is waiting and reading response 126 * @value Used to return value from IPI buffer element (optional) 127 * @count Number of values to return in @value 128 * 129 * @return Returns status, either success or error+reason 130 */ 131 static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, 132 unsigned int *value, size_t count) 133 { 134 size_t i; 135 uintptr_t buffer_base = proc->ipi->buffer_base + 136 IPI_BUFFER_TARGET_REMOTE_OFFSET + 137 IPI_BUFFER_RESP_OFFSET; 138 139 /* 140 * Read response from IPI buffer 141 * buf-0: success or error+reason 142 * buf-1: value 143 * buf-2: unused 144 * buf-3: unused 145 */ 146 for (i = 1; i <= count; i++) { 147 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 148 value++; 149 } 150 151 return mmio_read_32(buffer_base); 152 } 153 154 /** 155 * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has 156 * handled interrupt 157 * @value Used to return value from IPI buffer element (optional) 158 * @count Number of values to return in @value 159 * 160 * @return Returns status, either success or error+reason 161 */ 162 void pm_ipi_buff_read_callb(unsigned int *value, size_t count) 163 { 164 size_t i; 165 uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE + 166 IPI_BUFFER_TARGET_LOCAL_OFFSET + 167 IPI_BUFFER_REQ_OFFSET; 168 169 if (count > IPI_BUFFER_MAX_WORDS) 170 count = IPI_BUFFER_MAX_WORDS; 171 172 for (i = 0; i <= count; i++) { 173 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 174 value++; 175 } 176 } 177 178 /** 179 * pm_ipi_send_sync() - Sends IPI request to the remote processor 180 * @proc Pointer to the processor who is initiating request 181 * @payload API id and call arguments to be written in IPI buffer 182 * @value Used to return value from IPI buffer element (optional) 183 * @count Number of values to return in @value 184 * 185 * Send an IPI request to the power controller and wait for it to be handled. 186 * 187 * @return Returns status, either success or error+reason and, optionally, 188 * @value 189 */ 190 enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, 191 uint32_t payload[PAYLOAD_ARG_CNT], 192 unsigned int *value, size_t count) 193 { 194 enum pm_ret_status ret; 195 196 bakery_lock_get(&pm_secure_lock); 197 198 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); 199 if (ret != PM_RET_SUCCESS) 200 goto unlock; 201 202 ret = pm_ipi_buff_read(proc, value, count); 203 204 unlock: 205 bakery_lock_release(&pm_secure_lock); 206 207 return ret; 208 } 209 210 void pm_ipi_irq_enable(const struct pm_proc *proc) 211 { 212 ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); 213 } 214 215 void pm_ipi_irq_clear(const struct pm_proc *proc) 216 { 217 ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); 218 } 219 220 uint32_t pm_ipi_irq_status(const struct pm_proc *proc) 221 { 222 int ret; 223 224 ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id, 225 proc->ipi->remote_ipi_id); 226 if (ret & IPI_MB_STATUS_RECV_PENDING) 227 return 1; 228 else 229 return 0; 230 } 231