xref: /rk3399_ARM-atf/plat/xilinx/common/ipi.c (revision 10ecd58093a34e95e2dfad65b1180610f29397cc)
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  */
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  */
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  */
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) == 0) {
94 		ret = -EINVAL;
95 	} else if (IPI_IS_SECURE(local) && (is_secure == 0U)) {
96 		ret = -EPERM;
97 	} else if (IPI_IS_SECURE(remote) && (is_secure == 0U)) {
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  */
112 void ipi_mb_open(uint32_t local, uint32_t remote)
113 {
114 	uint64_t idr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_IDR_OFFSET);
115 	uint64_t isr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
116 
117 	mmio_write_32(idr_offset,
118 		      IPI_BIT_MASK(remote));
119 	mmio_write_32(isr_offset,
120 		      IPI_BIT_MASK(remote));
121 }
122 
123 /**
124  * ipi_mb_release() - Open IPI mailbox.
125  * @local: local IPI ID.
126  * @remote: remote IPI ID.
127  *
128  */
129 void ipi_mb_release(uint32_t local, uint32_t remote)
130 {
131 	uint64_t idr_offset = (uint64_t)(IPI_REG_BASE(local) + IPI_IDR_OFFSET);
132 
133 	mmio_write_32(idr_offset,
134 		      IPI_BIT_MASK(remote));
135 }
136 
137 /**
138  * ipi_mb_enquire_status() - Enquire IPI mailbox status.
139  * @local: local IPI ID.
140  * @remote: remote IPI ID.
141  *
142  * Return: 0 idle, positive value for pending sending or receiving,
143  *         negative value for errors.
144  *
145  */
146 int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
147 {
148 	int ret = 0U;
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  */
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  */
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  */
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  */
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