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