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 */
ipi_config_table_init(const struct ipi_config * ipi_config_table,uint32_t total_ipi)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 */
is_ipi_mb_within_range(uint32_t local,uint32_t remote)70 static inline uint32_t is_ipi_mb_within_range(uint32_t local, uint32_t remote)
71 {
72 uint32_t ret = 1U;
73
74 if ((remote >= ipi_total) || (local >= ipi_total)) {
75 ret = 0U;
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 */
ipi_mb_validate(uint32_t local,uint32_t remote,uint32_t is_secure)90 int32_t ipi_mb_validate(uint32_t local, uint32_t remote, uint32_t is_secure)
91 {
92 int32_t ret = 0;
93
94 if (is_ipi_mb_within_range(local, remote) == 0U) {
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 */
ipi_mb_open(uint32_t local,uint32_t remote)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 */
ipi_mb_release(uint32_t local,uint32_t remote)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 and positive value for pending sending or receiving.
144 *
145 */
ipi_mb_enquire_status(uint32_t local,uint32_t remote)146 uint32_t ipi_mb_enquire_status(uint32_t local, uint32_t remote)
147 {
148 uint32_t ret = (uint32_t)PM_RET_SUCCESS;
149 uint32_t status;
150 uint64_t obr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
151 uint64_t isr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
152
153 status = mmio_read_32(obr_offset);
154 if ((status & IPI_BIT_MASK(remote)) != 0U) {
155 ret |= IPI_MB_STATUS_SEND_PENDING;
156 }
157 status = mmio_read_32(isr_offset);
158 if ((status & IPI_BIT_MASK(remote)) != 0U) {
159 ret |= IPI_MB_STATUS_RECV_PENDING;
160 }
161
162 return ret;
163 }
164
165 /**
166 * ipi_mb_notify() - Trigger IPI mailbox notification.
167 * @local: local IPI ID.
168 * @remote: remote IPI ID.
169 * @is_blocking: if to trigger the notification in blocking mode or not.
170 *
171 * It sets the remote bit in the IPI agent trigger register.
172 *
173 */
ipi_mb_notify(uint32_t local,uint32_t remote,uint32_t is_blocking)174 void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
175 {
176 uint32_t status;
177 uint64_t trig_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_TRIG_OFFSET);
178 uint64_t obr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
179
180 mmio_write_32(trig_offset,
181 IPI_BIT_MASK(remote));
182 if (is_blocking != 0U) {
183 do {
184 status = mmio_read_32(obr_offset);
185 } while ((status & IPI_BIT_MASK(remote)) != 0U);
186 }
187 }
188
189 /**
190 * ipi_mb_ack() - Ack IPI mailbox notification from the other end.
191 * @local: local IPI ID.
192 * @remote: remote IPI ID.
193 *
194 * It will clear the remote bit in the isr register.
195 *
196 */
ipi_mb_ack(uint32_t local,uint32_t remote)197 void ipi_mb_ack(uint32_t local, uint32_t remote)
198 {
199 uint64_t isr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
200
201 mmio_write_32(isr_offset,
202 IPI_BIT_MASK(remote));
203 }
204
205 /**
206 * ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt.
207 * @local: local IPI ID.
208 * @remote: remote IPI ID.
209 *
210 * It will mask the remote bit in the idr register.
211 *
212 */
ipi_mb_disable_irq(uint32_t local,uint32_t remote)213 void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
214 {
215 uint64_t idr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_IDR_OFFSET);
216
217 mmio_write_32(idr_offset,
218 IPI_BIT_MASK(remote));
219 }
220
221 /**
222 * ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt.
223 * @local: local IPI ID.
224 * @remote: remote IPI ID.
225 *
226 * It will mask the remote bit in the idr register.
227 *
228 */
ipi_mb_enable_irq(uint32_t local,uint32_t remote)229 void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
230 {
231 uint64_t ier_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_IER_OFFSET);
232
233 mmio_write_32(ier_offset,
234 IPI_BIT_MASK(remote));
235 }
236