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