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