1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* 8 * Xilinx IPI agent registers access management 9 */ 10 11 #include <errno.h> 12 #include <string.h> 13 14 #include <common/debug.h> 15 #include <common/runtime_svc.h> 16 #include <lib/bakery_lock.h> 17 #include <lib/mmio.h> 18 19 #include <ipi.h> 20 #include <plat_ipi.h> 21 #include <plat_private.h> 22 23 /********************************************************************* 24 * Macros definitions 25 ********************************************************************/ 26 27 /* IPI registers offsets macros */ 28 #define IPI_TRIG_OFFSET 0x00U 29 #define IPI_OBR_OFFSET 0x04U 30 #define IPI_ISR_OFFSET 0x10U 31 #define IPI_IMR_OFFSET 0x14U 32 #define IPI_IER_OFFSET 0x18U 33 #define IPI_IDR_OFFSET 0x1CU 34 35 /* IPI register start offset */ 36 #define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base) 37 38 /* IPI register bit mask */ 39 #define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask) 40 41 /* IPI configuration table */ 42 const static struct ipi_config *ipi_table; 43 44 /* Total number of IPI */ 45 static uint32_t ipi_total; 46 47 /** 48 * ipi_config_init() - Initialize IPI configuration data 49 * 50 * @ipi_config_table - IPI configuration table 51 * @ipi_total - Total number of IPI available 52 * 53 */ 54 void ipi_config_table_init(const struct ipi_config *ipi_config_table, 55 uint32_t total_ipi) 56 { 57 ipi_table = ipi_config_table; 58 ipi_total = total_ipi; 59 } 60 61 /* is_ipi_mb_within_range() - verify if IPI mailbox is within range 62 * 63 * @local - local IPI ID 64 * @remote - remote IPI ID 65 * 66 * return - 1 if within range, 0 if not 67 */ 68 static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote) 69 { 70 int ret = 1; 71 72 if (remote >= ipi_total || local >= ipi_total) 73 ret = 0; 74 75 return ret; 76 } 77 78 /** 79 * ipi_mb_validate() - validate IPI mailbox access 80 * 81 * @local - local IPI ID 82 * @remote - remote IPI ID 83 * @is_secure - indicate if the requester is from secure software 84 * 85 * return - 0 success, negative value for errors 86 */ 87 int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure) 88 { 89 int ret = 0; 90 91 if (!is_ipi_mb_within_range(local, remote)) 92 ret = -EINVAL; 93 else if (IPI_IS_SECURE(local) && !is_secure) 94 ret = -EPERM; 95 else if (IPI_IS_SECURE(remote) && !is_secure) 96 ret = -EPERM; 97 98 return ret; 99 } 100 101 /** 102 * ipi_mb_open() - Open IPI mailbox. 103 * 104 * @local - local IPI ID 105 * @remote - remote IPI ID 106 * 107 */ 108 void ipi_mb_open(uint32_t local, uint32_t remote) 109 { 110 mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 111 IPI_BIT_MASK(remote)); 112 mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, 113 IPI_BIT_MASK(remote)); 114 } 115 116 /** 117 * ipi_mb_release() - Open IPI mailbox. 118 * 119 * @local - local IPI ID 120 * @remote - remote IPI ID 121 * 122 */ 123 void ipi_mb_release(uint32_t local, uint32_t remote) 124 { 125 mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 126 IPI_BIT_MASK(remote)); 127 } 128 129 /** 130 * ipi_mb_enquire_status() - Enquire IPI mailbox status 131 * 132 * @local - local IPI ID 133 * @remote - remote IPI ID 134 * 135 * return - 0 idle, positive value for pending sending or receiving, 136 * negative value for errors 137 */ 138 int ipi_mb_enquire_status(uint32_t local, uint32_t remote) 139 { 140 int ret = 0; 141 uint32_t status; 142 143 status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET); 144 if (status & IPI_BIT_MASK(remote)) 145 ret |= IPI_MB_STATUS_SEND_PENDING; 146 status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET); 147 if (status & IPI_BIT_MASK(remote)) 148 ret |= IPI_MB_STATUS_RECV_PENDING; 149 150 return ret; 151 } 152 153 /* ipi_mb_notify() - Trigger IPI mailbox notification 154 * 155 * @local - local IPI ID 156 * @remote - remote IPI ID 157 * @is_blocking - if to trigger the notification in blocking mode or not. 158 * 159 * It sets the remote bit in the IPI agent trigger register. 160 * 161 */ 162 void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking) 163 { 164 uint32_t status; 165 166 mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET, 167 IPI_BIT_MASK(remote)); 168 if (is_blocking) { 169 do { 170 status = mmio_read_32(IPI_REG_BASE(local) + 171 IPI_OBR_OFFSET); 172 } while (status & IPI_BIT_MASK(remote)); 173 } 174 } 175 176 /* ipi_mb_ack() - Ack IPI mailbox notification from the other end 177 * 178 * @local - local IPI ID 179 * @remote - remote IPI ID 180 * 181 * It will clear the remote bit in the isr register. 182 * 183 */ 184 void ipi_mb_ack(uint32_t local, uint32_t remote) 185 { 186 mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, 187 IPI_BIT_MASK(remote)); 188 } 189 190 /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt 191 * 192 * @local - local IPI ID 193 * @remote - remote IPI ID 194 * 195 * It will mask the remote bit in the idr register. 196 * 197 */ 198 void ipi_mb_disable_irq(uint32_t local, uint32_t remote) 199 { 200 mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 201 IPI_BIT_MASK(remote)); 202 } 203 204 /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt 205 * 206 * @local - local IPI ID 207 * @remote - remote IPI ID 208 * 209 * It will mask the remote bit in the idr register. 210 * 211 */ 212 void ipi_mb_enable_irq(uint32_t local, uint32_t remote) 213 { 214 mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET, 215 IPI_BIT_MASK(remote)); 216 } 217