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