1 /*
2  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 /*
9  * Xilinx IPI agent registers access management
10  */
11 
12 #include <errno.h>
13 #include <string.h>
14 
15 #include <common/debug.h>
16 #include <common/runtime_svc.h>
17 #include <lib/bakery_lock.h>
18 #include <lib/mmio.h>
19 
20 #include <ipi.h>
21 #include <plat_private.h>
22 
23 /*********************************************************************
24  * Macros definitions
25  ********************************************************************/
26 
27 /* IPI registers offsets macros */
28 #define IPI_TRIG_OFFSET 0x00U
29 #define IPI_OBR_OFFSET  0x04U
30 #define IPI_ISR_OFFSET  0x10U
31 #define IPI_IMR_OFFSET  0x14U
32 #define IPI_IER_OFFSET  0x18U
33 #define IPI_IDR_OFFSET  0x1CU
34 
35 /* IPI register start offset */
36 #define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base)
37 
38 /* IPI register bit mask */
39 #define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask)
40 
41 /* IPI configuration table */
42 const static struct ipi_config *ipi_table;
43 
44 /* Total number of IPI */
45 static uint32_t ipi_total;
46 
47 /**
48  * ipi_config_init() - Initialize IPI configuration data
49  *
50  * @ipi_config_table  - IPI configuration table
51  * @ipi_total - Total number of IPI available
52  *
53  */
ipi_config_table_init(const struct ipi_config * ipi_config_table,uint32_t total_ipi)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 /* is_ipi_mb_within_range() - verify if IPI mailbox is within range
62  *
63  * @local  - local IPI ID
64  * @remote - remote IPI ID
65  *
66  * return - 1 if within range, 0 if not
67  */
is_ipi_mb_within_range(uint32_t local,uint32_t remote)68 static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote)
69 {
70 	int ret = 1;
71 
72 	if (remote >= ipi_total || local >= ipi_total) {
73 		ret = 0;
74 	}
75 
76 	return ret;
77 }
78 
79 /**
80  * ipi_mb_validate() - validate IPI mailbox access
81  *
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  */
ipi_mb_validate(uint32_t local,uint32_t remote,unsigned int is_secure)88 int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure)
89 {
90 	int ret = 0;
91 
92 	if (!is_ipi_mb_within_range(local, remote)) {
93 		ret = -EINVAL;
94 	} else if (IPI_IS_SECURE(local) && !is_secure) {
95 		ret = -EPERM;
96 	} else if (IPI_IS_SECURE(remote) && !is_secure) {
97 		ret = -EPERM;
98 	} else {
99 		/* To fix the misra 15.7 warning */
100 	}
101 
102 	return ret;
103 }
104 
105 /**
106  * ipi_mb_open() - Open IPI mailbox.
107  *
108  * @local  - local IPI ID
109  * @remote - remote IPI ID
110  *
111  */
ipi_mb_open(uint32_t local,uint32_t remote)112 void ipi_mb_open(uint32_t local, uint32_t remote)
113 {
114 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
115 		      IPI_BIT_MASK(remote));
116 	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
117 		      IPI_BIT_MASK(remote));
118 }
119 
120 /**
121  * ipi_mb_release() - Open IPI mailbox.
122  *
123  * @local  - local IPI ID
124  * @remote - remote IPI ID
125  *
126  */
ipi_mb_release(uint32_t local,uint32_t remote)127 void ipi_mb_release(uint32_t local, uint32_t remote)
128 {
129 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
130 		      IPI_BIT_MASK(remote));
131 }
132 
133 /**
134  * ipi_mb_enquire_status() - Enquire IPI mailbox status
135  *
136  * @local  - local IPI ID
137  * @remote - remote IPI ID
138  *
139  * return - 0 idle, positive value for pending sending or receiving,
140  *          negative value for errors
141  */
ipi_mb_enquire_status(uint32_t local,uint32_t remote)142 int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
143 {
144 	int ret = 0U;
145 	uint32_t status;
146 
147 	status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
148 	if (status & IPI_BIT_MASK(remote)) {
149 		ret |= IPI_MB_STATUS_SEND_PENDING;
150 	}
151 	status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
152 	if (status & IPI_BIT_MASK(remote)) {
153 		ret |= IPI_MB_STATUS_RECV_PENDING;
154 	}
155 
156 	return ret;
157 }
158 
159 /* ipi_mb_notify() - Trigger IPI mailbox notification
160  *
161  * @local - local IPI ID
162  * @remote - remote IPI ID
163  * @is_blocking - if to trigger the notification in blocking mode or not.
164  *
165  * It sets the remote bit in the IPI agent trigger register.
166  *
167  */
ipi_mb_notify(uint32_t local,uint32_t remote,uint32_t is_blocking)168 void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
169 {
170 	uint32_t status;
171 
172 	mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET,
173 		      IPI_BIT_MASK(remote));
174 	if (is_blocking) {
175 		do {
176 			status = mmio_read_32(IPI_REG_BASE(local) +
177 					      IPI_OBR_OFFSET);
178 		} while (status & IPI_BIT_MASK(remote));
179 	}
180 }
181 
182 /* ipi_mb_ack() - Ack IPI mailbox notification from the other end
183  *
184  * @local - local IPI ID
185  * @remote - remote IPI ID
186  *
187  * It will clear the remote bit in the isr register.
188  *
189  */
ipi_mb_ack(uint32_t local,uint32_t remote)190 void ipi_mb_ack(uint32_t local, uint32_t remote)
191 {
192 	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
193 		      IPI_BIT_MASK(remote));
194 }
195 
196 /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt
197  *
198  * @local - local IPI ID
199  * @remote - remote IPI ID
200  *
201  * It will mask the remote bit in the idr register.
202  *
203  */
ipi_mb_disable_irq(uint32_t local,uint32_t remote)204 void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
205 {
206 	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
207 		      IPI_BIT_MASK(remote));
208 }
209 
210 /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt
211  *
212  * @local - local IPI ID
213  * @remote - remote IPI ID
214  *
215  * It will mask the remote bit in the idr register.
216  *
217  */
ipi_mb_enable_irq(uint32_t local,uint32_t remote)218 void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
219 {
220 	mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET,
221 		      IPI_BIT_MASK(remote));
222 }
223