1 /*
2 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 /*
9 * Xilinx IPI agent registers access management
10 */
11
12 #include <errno.h>
13 #include <string.h>
14
15 #include <common/debug.h>
16 #include <common/runtime_svc.h>
17 #include <lib/bakery_lock.h>
18 #include <lib/mmio.h>
19
20 #include <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 */
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 /* 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 */
is_ipi_mb_within_range(uint32_t local,uint32_t remote)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
76 return ret;
77 }
78
79 /**
80 * ipi_mb_validate() - validate IPI mailbox access
81 *
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 */
ipi_mb_validate(uint32_t local,uint32_t remote,unsigned int is_secure)88 int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure)
89 {
90 int ret = 0;
91
92 if (!is_ipi_mb_within_range(local, remote)) {
93 ret = -EINVAL;
94 } else if (IPI_IS_SECURE(local) && !is_secure) {
95 ret = -EPERM;
96 } else if (IPI_IS_SECURE(remote) && !is_secure) {
97 ret = -EPERM;
98 } else {
99 /* To fix the misra 15.7 warning */
100 }
101
102 return ret;
103 }
104
105 /**
106 * ipi_mb_open() - Open IPI mailbox.
107 *
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 *
123 * @local - local IPI ID
124 * @remote - remote IPI ID
125 *
126 */
ipi_mb_release(uint32_t local,uint32_t remote)127 void ipi_mb_release(uint32_t local, uint32_t remote)
128 {
129 mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
130 IPI_BIT_MASK(remote));
131 }
132
133 /**
134 * ipi_mb_enquire_status() - Enquire IPI mailbox status
135 *
136 * @local - local IPI ID
137 * @remote - remote IPI ID
138 *
139 * return - 0 idle, positive value for pending sending or receiving,
140 * negative value for errors
141 */
ipi_mb_enquire_status(uint32_t local,uint32_t remote)142 int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
143 {
144 int ret = 0U;
145 uint32_t status;
146
147 status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
148 if (status & IPI_BIT_MASK(remote)) {
149 ret |= IPI_MB_STATUS_SEND_PENDING;
150 }
151 status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
152 if (status & IPI_BIT_MASK(remote)) {
153 ret |= IPI_MB_STATUS_RECV_PENDING;
154 }
155
156 return ret;
157 }
158
159 /* ipi_mb_notify() - Trigger IPI mailbox notification
160 *
161 * @local - local IPI ID
162 * @remote - remote IPI ID
163 * @is_blocking - if to trigger the notification in blocking mode or not.
164 *
165 * It sets the remote bit in the IPI agent trigger register.
166 *
167 */
ipi_mb_notify(uint32_t local,uint32_t remote,uint32_t is_blocking)168 void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
169 {
170 uint32_t status;
171
172 mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET,
173 IPI_BIT_MASK(remote));
174 if (is_blocking) {
175 do {
176 status = mmio_read_32(IPI_REG_BASE(local) +
177 IPI_OBR_OFFSET);
178 } while (status & IPI_BIT_MASK(remote));
179 }
180 }
181
182 /* ipi_mb_ack() - Ack IPI mailbox notification from the other end
183 *
184 * @local - local IPI ID
185 * @remote - remote IPI ID
186 *
187 * It will clear the remote bit in the isr register.
188 *
189 */
ipi_mb_ack(uint32_t local,uint32_t remote)190 void ipi_mb_ack(uint32_t local, uint32_t remote)
191 {
192 mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
193 IPI_BIT_MASK(remote));
194 }
195
196 /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt
197 *
198 * @local - local IPI ID
199 * @remote - remote IPI ID
200 *
201 * It will mask the remote bit in the idr register.
202 *
203 */
ipi_mb_disable_irq(uint32_t local,uint32_t remote)204 void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
205 {
206 mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
207 IPI_BIT_MASK(remote));
208 }
209
210 /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt
211 *
212 * @local - local IPI ID
213 * @remote - remote IPI ID
214 *
215 * It will mask the remote bit in the idr register.
216 *
217 */
ipi_mb_enable_irq(uint32_t local,uint32_t remote)218 void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
219 {
220 mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET,
221 IPI_BIT_MASK(remote));
222 }
223