xref: /rk3399_ARM-atf/plat/xilinx/zynqmp/zynqmp_ipi.c (revision 85dc2d4dae674a6ab94467bea88656a44630dac8)
1dc1dfe83SWendy Liang /*
2dc1dfe83SWendy Liang  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3dc1dfe83SWendy Liang  *
4dc1dfe83SWendy Liang  * SPDX-License-Identifier: BSD-3-Clause
5dc1dfe83SWendy Liang  */
6dc1dfe83SWendy Liang 
7dc1dfe83SWendy Liang /*
8dc1dfe83SWendy Liang  * Zynq UltraScale+ MPSoC IPI agent registers access management
9dc1dfe83SWendy Liang  */
10dc1dfe83SWendy Liang 
11dc1dfe83SWendy Liang #include <bakery_lock.h>
12dc1dfe83SWendy Liang #include <debug.h>
13dc1dfe83SWendy Liang #include <errno.h>
14dc1dfe83SWendy Liang #include <mmio.h>
15dc1dfe83SWendy Liang #include <runtime_svc.h>
16dc1dfe83SWendy Liang #include <string.h>
17dc1dfe83SWendy Liang #include "zynqmp_ipi.h"
18dc1dfe83SWendy Liang #include "../zynqmp_private.h"
19dc1dfe83SWendy Liang 
20dc1dfe83SWendy Liang /*********************************************************************
21dc1dfe83SWendy Liang  * Macros definitions
22dc1dfe83SWendy Liang  ********************************************************************/
23dc1dfe83SWendy Liang 
24dc1dfe83SWendy Liang /* IPI registers base address */
25dc1dfe83SWendy Liang #define IPI_REGS_BASE   0xFF300000U
26dc1dfe83SWendy Liang 
27dc1dfe83SWendy Liang /* IPI registers offsets macros */
28dc1dfe83SWendy Liang #define IPI_TRIG_OFFSET 0x00U
29dc1dfe83SWendy Liang #define IPI_OBR_OFFSET  0x04U
30dc1dfe83SWendy Liang #define IPI_ISR_OFFSET  0x10U
31dc1dfe83SWendy Liang #define IPI_IMR_OFFSET  0x14U
32dc1dfe83SWendy Liang #define IPI_IER_OFFSET  0x18U
33dc1dfe83SWendy Liang #define IPI_IDR_OFFSET  0x1CU
34dc1dfe83SWendy Liang 
35dc1dfe83SWendy Liang /* IPI register start offset */
36dc1dfe83SWendy Liang #define IPI_REG_BASE(I) (zynqmp_ipi_table[(I)].ipi_reg_base)
37dc1dfe83SWendy Liang 
38dc1dfe83SWendy Liang /* IPI register bit mask */
39dc1dfe83SWendy Liang #define IPI_BIT_MASK(I) (zynqmp_ipi_table[(I)].ipi_bit_mask)
40dc1dfe83SWendy Liang 
41dc1dfe83SWendy Liang /* IPI secure check */
42dc1dfe83SWendy Liang #define IPI_SECURE_MASK  0x1U
43dc1dfe83SWendy Liang #define IPI_IS_SECURE(I) ((zynqmp_ipi_table[(I)].secure_only & \
44dc1dfe83SWendy Liang 			   IPI_SECURE_MASK) ? 1 : 0)
45dc1dfe83SWendy Liang 
46dc1dfe83SWendy Liang /*********************************************************************
47dc1dfe83SWendy Liang  * Struct definitions
48dc1dfe83SWendy Liang  ********************************************************************/
49dc1dfe83SWendy Liang 
50dc1dfe83SWendy Liang /* structure to maintain IPI configuration information */
51dc1dfe83SWendy Liang struct zynqmp_ipi_config {
52dc1dfe83SWendy Liang 	unsigned int ipi_bit_mask;
53dc1dfe83SWendy Liang 	unsigned int ipi_reg_base;
54dc1dfe83SWendy Liang 	unsigned char secure_only;
55dc1dfe83SWendy Liang };
56dc1dfe83SWendy Liang 
57dc1dfe83SWendy Liang /* Zynqmp ipi configuration table */
58dc1dfe83SWendy Liang const static struct zynqmp_ipi_config zynqmp_ipi_table[] = {
59dc1dfe83SWendy Liang 	/* APU IPI */
60dc1dfe83SWendy Liang 	{
61dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x1,
62dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF300000,
63dc1dfe83SWendy Liang 		.secure_only = 0,
64dc1dfe83SWendy Liang 	},
65dc1dfe83SWendy Liang 	/* RPU0 IPI */
66dc1dfe83SWendy Liang 	{
67dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x100,
68dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF310000,
69dc1dfe83SWendy Liang 		.secure_only = 0,
70dc1dfe83SWendy Liang 	},
71dc1dfe83SWendy Liang 	/* RPU1 IPI */
72dc1dfe83SWendy Liang 	{
73dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x200,
74dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF320000,
75dc1dfe83SWendy Liang 		.secure_only = 0,
76dc1dfe83SWendy Liang 	},
77dc1dfe83SWendy Liang 	/* PMU0 IPI */
78dc1dfe83SWendy Liang 	{
79dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x10000,
80dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF330000,
81dc1dfe83SWendy Liang 		.secure_only = IPI_SECURE_MASK,
82dc1dfe83SWendy Liang 	},
83dc1dfe83SWendy Liang 	/* PMU1 IPI */
84dc1dfe83SWendy Liang 	{
85dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x20000,
86dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF331000,
87*85dc2d4dSRajan Vaja 		.secure_only = 0,
88dc1dfe83SWendy Liang 	},
89dc1dfe83SWendy Liang 	/* PMU2 IPI */
90dc1dfe83SWendy Liang 	{
91dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x40000,
92dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF332000,
93dc1dfe83SWendy Liang 		.secure_only = IPI_SECURE_MASK,
94dc1dfe83SWendy Liang 	},
95dc1dfe83SWendy Liang 	/* PMU3 IPI */
96dc1dfe83SWendy Liang 	{
97dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x80000,
98dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF333000,
99dc1dfe83SWendy Liang 		.secure_only = IPI_SECURE_MASK,
100dc1dfe83SWendy Liang 	},
101dc1dfe83SWendy Liang 	/* PL0 IPI */
102dc1dfe83SWendy Liang 	{
103dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x1000000,
104dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF340000,
105dc1dfe83SWendy Liang 		.secure_only = 0,
106dc1dfe83SWendy Liang 	},
107dc1dfe83SWendy Liang 	/* PL1 IPI */
108dc1dfe83SWendy Liang 	{
109dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x2000000,
110dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF350000,
111dc1dfe83SWendy Liang 		.secure_only = 0,
112dc1dfe83SWendy Liang 	},
113dc1dfe83SWendy Liang 	/* PL2 IPI */
114dc1dfe83SWendy Liang 	{
115dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x4000000,
116dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF360000,
117dc1dfe83SWendy Liang 		.secure_only = 0,
118dc1dfe83SWendy Liang 	},
119dc1dfe83SWendy Liang 	/* PL3 IPI */
120dc1dfe83SWendy Liang 	{
121dc1dfe83SWendy Liang 		.ipi_bit_mask = 0x8000000,
122dc1dfe83SWendy Liang 		.ipi_reg_base = 0xFF370000,
123dc1dfe83SWendy Liang 		.secure_only = 0,
124dc1dfe83SWendy Liang 	},
125dc1dfe83SWendy Liang };
126dc1dfe83SWendy Liang 
127dc1dfe83SWendy Liang /* is_ipi_mb_within_range() - verify if IPI mailbox is within range
128dc1dfe83SWendy Liang  *
129dc1dfe83SWendy Liang  * @local  - local IPI ID
130dc1dfe83SWendy Liang  * @remote - remote IPI ID
131dc1dfe83SWendy Liang  *
132dc1dfe83SWendy Liang  * return - 1 if within range, 0 if not
133dc1dfe83SWendy Liang  */
134dc1dfe83SWendy Liang static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote)
135dc1dfe83SWendy Liang {
136dc1dfe83SWendy Liang 	int ret = 1;
137dc1dfe83SWendy Liang 	uint32_t ipi_total = ARRAY_SIZE(zynqmp_ipi_table);
138dc1dfe83SWendy Liang 
139dc1dfe83SWendy Liang 	if (remote >= ipi_total || local >= ipi_total)
140dc1dfe83SWendy Liang 		ret = 0;
141dc1dfe83SWendy Liang 
142dc1dfe83SWendy Liang 	return ret;
143dc1dfe83SWendy Liang }
144dc1dfe83SWendy Liang 
145dc1dfe83SWendy Liang /**
146dc1dfe83SWendy Liang  * ipi_mb_validate() - validate IPI mailbox access
147dc1dfe83SWendy Liang  *
148dc1dfe83SWendy Liang  * @local  - local IPI ID
149dc1dfe83SWendy Liang  * @remote - remote IPI ID
150dc1dfe83SWendy Liang  * @is_secure - indicate if the requester is from secure software
151dc1dfe83SWendy Liang  *
152dc1dfe83SWendy Liang  * return - 0 success, negative value for errors
153dc1dfe83SWendy Liang  */
154dc1dfe83SWendy Liang int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure)
155dc1dfe83SWendy Liang {
156dc1dfe83SWendy Liang 	int ret = 0;
157dc1dfe83SWendy Liang 
158dc1dfe83SWendy Liang 	if (!is_ipi_mb_within_range(local, remote))
159dc1dfe83SWendy Liang 		ret = -EINVAL;
160dc1dfe83SWendy Liang 	else if (IPI_IS_SECURE(local) && !is_secure)
161dc1dfe83SWendy Liang 		ret = -EPERM;
162dc1dfe83SWendy Liang 	else if (IPI_IS_SECURE(remote) && !is_secure)
163dc1dfe83SWendy Liang 		ret = -EPERM;
164dc1dfe83SWendy Liang 
165dc1dfe83SWendy Liang 	return ret;
166dc1dfe83SWendy Liang }
167dc1dfe83SWendy Liang 
168dc1dfe83SWendy Liang /**
169dc1dfe83SWendy Liang  * ipi_mb_open() - Open IPI mailbox.
170dc1dfe83SWendy Liang  *
171dc1dfe83SWendy Liang  * @local  - local IPI ID
172dc1dfe83SWendy Liang  * @remote - remote IPI ID
173dc1dfe83SWendy Liang  *
174dc1dfe83SWendy Liang  */
175dc1dfe83SWendy Liang void ipi_mb_open(uint32_t local, uint32_t remote)
176dc1dfe83SWendy Liang {
177dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
178dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
179dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
180dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
181dc1dfe83SWendy Liang }
182dc1dfe83SWendy Liang 
183dc1dfe83SWendy Liang /**
184dc1dfe83SWendy Liang  * ipi_mb_release() - Open IPI mailbox.
185dc1dfe83SWendy Liang  *
186dc1dfe83SWendy Liang  * @local  - local IPI ID
187dc1dfe83SWendy Liang  * @remote - remote IPI ID
188dc1dfe83SWendy Liang  *
189dc1dfe83SWendy Liang  */
190dc1dfe83SWendy Liang void ipi_mb_release(uint32_t local, uint32_t remote)
191dc1dfe83SWendy Liang {
192dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
193dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
194dc1dfe83SWendy Liang }
195dc1dfe83SWendy Liang 
196dc1dfe83SWendy Liang /**
197dc1dfe83SWendy Liang  * ipi_mb_enquire_status() - Enquire IPI mailbox status
198dc1dfe83SWendy Liang  *
199dc1dfe83SWendy Liang  * @local  - local IPI ID
200dc1dfe83SWendy Liang  * @remote - remote IPI ID
201dc1dfe83SWendy Liang  *
202dc1dfe83SWendy Liang  * return - 0 idle, positive value for pending sending or receiving,
203dc1dfe83SWendy Liang  *          negative value for errors
204dc1dfe83SWendy Liang  */
205dc1dfe83SWendy Liang int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
206dc1dfe83SWendy Liang {
207dc1dfe83SWendy Liang 	int ret = 0;
208dc1dfe83SWendy Liang 	uint32_t status;
209dc1dfe83SWendy Liang 
210dc1dfe83SWendy Liang 	status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
211dc1dfe83SWendy Liang 	if (status & IPI_BIT_MASK(remote))
212dc1dfe83SWendy Liang 		ret |= IPI_MB_STATUS_SEND_PENDING;
213dc1dfe83SWendy Liang 	status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
214dc1dfe83SWendy Liang 	if (status & IPI_BIT_MASK(remote))
215dc1dfe83SWendy Liang 		ret |= IPI_MB_STATUS_RECV_PENDING;
216dc1dfe83SWendy Liang 
217dc1dfe83SWendy Liang 	return ret;
218dc1dfe83SWendy Liang }
219dc1dfe83SWendy Liang 
220dc1dfe83SWendy Liang /* ipi_mb_notify() - Trigger IPI mailbox notification
221dc1dfe83SWendy Liang  *
222dc1dfe83SWendy Liang  * @local - local IPI ID
223dc1dfe83SWendy Liang  * @remote - remote IPI ID
224dc1dfe83SWendy Liang  * @is_blocking - if to trigger the notification in blocking mode or not.
225dc1dfe83SWendy Liang  *
226dc1dfe83SWendy Liang  * It sets the remote bit in the IPI agent trigger register.
227dc1dfe83SWendy Liang  *
228dc1dfe83SWendy Liang  */
229dc1dfe83SWendy Liang void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
230dc1dfe83SWendy Liang {
231dc1dfe83SWendy Liang 	uint32_t status;
232dc1dfe83SWendy Liang 
233dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET,
234dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
235dc1dfe83SWendy Liang 	if (is_blocking) {
236dc1dfe83SWendy Liang 		do {
237dc1dfe83SWendy Liang 			status = mmio_read_32(IPI_REG_BASE(local) +
238dc1dfe83SWendy Liang 					      IPI_OBR_OFFSET);
239dc1dfe83SWendy Liang 		} while (status & IPI_BIT_MASK(remote));
240dc1dfe83SWendy Liang 	}
241dc1dfe83SWendy Liang }
242dc1dfe83SWendy Liang 
243dc1dfe83SWendy Liang /* ipi_mb_ack() - Ack IPI mailbox notification from the other end
244dc1dfe83SWendy Liang  *
245dc1dfe83SWendy Liang  * @local - local IPI ID
246dc1dfe83SWendy Liang  * @remote - remote IPI ID
247dc1dfe83SWendy Liang  *
248dc1dfe83SWendy Liang  * It will clear the remote bit in the isr register.
249dc1dfe83SWendy Liang  *
250dc1dfe83SWendy Liang  */
251dc1dfe83SWendy Liang void ipi_mb_ack(uint32_t local, uint32_t remote)
252dc1dfe83SWendy Liang {
253dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
254dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
255dc1dfe83SWendy Liang }
256dc1dfe83SWendy Liang 
257dc1dfe83SWendy Liang /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt
258dc1dfe83SWendy Liang  *
259dc1dfe83SWendy Liang  * @local - local IPI ID
260dc1dfe83SWendy Liang  * @remote - remote IPI ID
261dc1dfe83SWendy Liang  *
262dc1dfe83SWendy Liang  * It will mask the remote bit in the idr register.
263dc1dfe83SWendy Liang  *
264dc1dfe83SWendy Liang  */
265dc1dfe83SWendy Liang void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
266dc1dfe83SWendy Liang {
267dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
268dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
269dc1dfe83SWendy Liang }
270dc1dfe83SWendy Liang 
271dc1dfe83SWendy Liang /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt
272dc1dfe83SWendy Liang  *
273dc1dfe83SWendy Liang  * @local - local IPI ID
274dc1dfe83SWendy Liang  * @remote - remote IPI ID
275dc1dfe83SWendy Liang  *
276dc1dfe83SWendy Liang  * It will mask the remote bit in the idr register.
277dc1dfe83SWendy Liang  *
278dc1dfe83SWendy Liang  */
279dc1dfe83SWendy Liang void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
280dc1dfe83SWendy Liang {
281dc1dfe83SWendy Liang 	mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET,
282dc1dfe83SWendy Liang 		      IPI_BIT_MASK(remote));
283dc1dfe83SWendy Liang }
284