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