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