xref: /optee_os/core/arch/arm/plat-sam/matrix.c (revision 5a913ee74d3c71af2a2860ce8a4e7aeab2916f9b)
1 // SPDX-License-Identifier: BSD-Source-Code
2 /*
3  * Copyright (c) 2013, Atmel Corporation
4  * Copyright (c) 2017, Timesys Corporation
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * - Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the disclaimer below.
13  *
14  * Atmel's name may not be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include <arm32.h>
29 #include <io.h>
30 #include <sama5d2.h>
31 #include <platform_config.h>
32 #include <stdint.h>
33 #include <matrix.h>
34 #include <tz_matrix.h>
35 #include <trace.h>
36 
37 #define MATRIX_AXIMX	1
38 #define MATRIX_H64MX	2
39 #define MATRIX_H32MX	3
40 
41 #define SECURITY_TYPE_AS	1
42 #define SECURITY_TYPE_NS	2
43 #define SECURITY_TYPE_PS	3
44 
45 struct peri_security {
46 	unsigned int peri_id;
47 	unsigned int matrix;
48 	unsigned int security_type;
49 };
50 
51 static const struct peri_security peri_security_array[] = {
52 	/*
53 	 * AT91C_ID_1 - This is a undocumented bit in the datasheet.
54 	 * However needs to be set for Linux to boot in "normal world"
55 	 */
56 	{
57 		.peri_id = AT91C_ID_1,
58 		.matrix = MATRIX_H64MX,
59 		.security_type = SECURITY_TYPE_PS,
60 	},
61 	{
62 		.peri_id = AT91C_ID_ARM,
63 		.matrix = MATRIX_H64MX,
64 		.security_type = SECURITY_TYPE_PS,
65 	},
66 	{
67 		.peri_id = AT91C_ID_PIT,
68 		.matrix = MATRIX_H32MX,
69 		.security_type = SECURITY_TYPE_PS,
70 	},
71 	{
72 		.peri_id = AT91C_ID_WDT,
73 		.matrix = MATRIX_H32MX,
74 		.security_type = SECURITY_TYPE_PS,
75 	},
76 	{
77 		.peri_id = AT91C_ID_GMAC,
78 		.matrix = MATRIX_H32MX,
79 		.security_type = SECURITY_TYPE_PS,
80 	},
81 	{
82 		.peri_id = AT91C_ID_XDMAC0,
83 		.matrix = MATRIX_H64MX,
84 		.security_type = SECURITY_TYPE_PS,
85 	},
86 	{
87 		.peri_id = AT91C_ID_XDMAC1,
88 		.matrix = MATRIX_H64MX,
89 		.security_type = SECURITY_TYPE_PS,
90 	},
91 	{
92 		.peri_id = AT91C_ID_ICM,
93 		.matrix = MATRIX_H32MX,
94 		.security_type = SECURITY_TYPE_PS,
95 	},
96 	{
97 		.peri_id = AT91C_ID_AES,
98 		.matrix = MATRIX_H64MX,
99 		.security_type = SECURITY_TYPE_PS,
100 	},
101 	{
102 		.peri_id = AT91C_ID_AESB,
103 		.matrix = MATRIX_H64MX,
104 		.security_type = SECURITY_TYPE_PS,
105 	},
106 	{
107 		.peri_id = AT91C_ID_TDES,
108 		.matrix = MATRIX_H32MX,
109 		.security_type = SECURITY_TYPE_PS,
110 	},
111 	{
112 		.peri_id = AT91C_ID_SHA,
113 		.matrix = MATRIX_H64MX,
114 		.security_type = SECURITY_TYPE_PS,
115 	},
116 	{
117 		.peri_id = AT91C_ID_MPDDRC,
118 		.matrix = MATRIX_H64MX,
119 		.security_type = SECURITY_TYPE_PS,
120 	},
121 	{
122 		.peri_id = AT91C_ID_MATRIX1,
123 		.matrix = MATRIX_H32MX,
124 		.security_type = SECURITY_TYPE_AS,
125 	},
126 	{
127 		.peri_id = AT91C_ID_MATRIX0,
128 		.matrix = MATRIX_H64MX,
129 		.security_type = SECURITY_TYPE_AS,
130 	},
131 	{
132 		.peri_id = AT91C_ID_SECUMOD,
133 		.matrix = MATRIX_H32MX,
134 		.security_type = SECURITY_TYPE_AS,
135 	},
136 	{
137 		.peri_id = AT91C_ID_HSMC,
138 		.matrix = MATRIX_H32MX,
139 		.security_type = SECURITY_TYPE_PS,
140 	},
141 	{
142 		.peri_id = AT91C_ID_PIOA,
143 		.matrix = MATRIX_H32MX,
144 		.security_type = SECURITY_TYPE_AS,
145 	},
146 	{
147 		.peri_id = AT91C_ID_FLEXCOM0,
148 		.matrix = MATRIX_H32MX,
149 		.security_type = SECURITY_TYPE_PS,
150 	},
151 	{
152 		.peri_id = AT91C_ID_FLEXCOM1,
153 		.matrix = MATRIX_H32MX,
154 		.security_type = SECURITY_TYPE_PS,
155 	},
156 	{
157 		.peri_id = AT91C_ID_FLEXCOM2,
158 		.matrix = MATRIX_H32MX,
159 		.security_type = SECURITY_TYPE_PS,
160 	},
161 	{
162 		.peri_id = AT91C_ID_FLEXCOM3,
163 		.matrix = MATRIX_H32MX,
164 		.security_type = SECURITY_TYPE_PS,
165 	},
166 	{
167 		.peri_id = AT91C_ID_FLEXCOM4,
168 		.matrix = MATRIX_H32MX,
169 		.security_type = SECURITY_TYPE_PS,
170 	},
171 	{
172 		.peri_id = AT91C_ID_UART0,
173 		.matrix = MATRIX_H32MX,
174 		.security_type = SECURITY_TYPE_PS,
175 	},
176 	{
177 		.peri_id = AT91C_ID_UART1,
178 		.matrix = MATRIX_H32MX,
179 		.security_type = SECURITY_TYPE_PS,
180 	},
181 	{
182 		.peri_id = AT91C_ID_UART2,
183 		.matrix = MATRIX_H32MX,
184 		.security_type = SECURITY_TYPE_PS,
185 	},
186 	{
187 		.peri_id = AT91C_ID_UART3,
188 		.matrix = MATRIX_H32MX,
189 		.security_type = SECURITY_TYPE_PS,
190 	},
191 	{
192 		.peri_id = AT91C_ID_UART4,
193 		.matrix = MATRIX_H32MX,
194 		.security_type = SECURITY_TYPE_PS,
195 	},
196 	{
197 		.peri_id = AT91C_ID_TWI0,
198 		.matrix = MATRIX_H32MX,
199 		.security_type = SECURITY_TYPE_PS,
200 	},
201 	{
202 		.peri_id = AT91C_ID_TWI1,
203 		.matrix = MATRIX_H32MX,
204 		.security_type = SECURITY_TYPE_PS,
205 	},
206 	{
207 		.peri_id = AT91C_ID_SDMMC0,
208 		.matrix = MATRIX_H64MX,
209 		.security_type = SECURITY_TYPE_PS,
210 	},
211 	{
212 		.peri_id = AT91C_ID_SDMMC1,
213 		.matrix = MATRIX_H64MX,
214 		.security_type = SECURITY_TYPE_PS,
215 	},
216 	{
217 		.peri_id = AT91C_ID_SPI0,
218 		.matrix = MATRIX_H32MX,
219 		.security_type = SECURITY_TYPE_PS,
220 	},
221 	{
222 		.peri_id = AT91C_ID_SPI1,
223 		.matrix = MATRIX_H32MX,
224 		.security_type = SECURITY_TYPE_PS,
225 	},
226 	{
227 		.peri_id = AT91C_ID_TC0,
228 		.matrix = MATRIX_H32MX,
229 		.security_type = SECURITY_TYPE_PS,
230 	},
231 	{
232 		.peri_id = AT91C_ID_TC1,
233 		.matrix = MATRIX_H32MX,
234 		.security_type = SECURITY_TYPE_PS,
235 	},
236 	{
237 		.peri_id = AT91C_ID_PWM,
238 		.matrix = MATRIX_H32MX,
239 		.security_type = SECURITY_TYPE_PS,
240 	},
241 	{
242 		.peri_id = AT91C_ID_ADC,
243 		.matrix = MATRIX_H32MX,
244 		.security_type = SECURITY_TYPE_PS,
245 	},
246 	{
247 		.peri_id = AT91C_ID_UHPHS,
248 		.matrix = MATRIX_H32MX,
249 		.security_type = SECURITY_TYPE_PS,
250 	},
251 	{
252 		.peri_id = AT91C_ID_UDPHS,
253 		.matrix = MATRIX_H32MX,
254 		.security_type = SECURITY_TYPE_PS,
255 	},
256 	{
257 		.peri_id = AT91C_ID_SSC0,
258 		.matrix = MATRIX_H32MX,
259 		.security_type = SECURITY_TYPE_PS,
260 	},
261 	{
262 		.peri_id = AT91C_ID_SSC1,
263 		.matrix = MATRIX_H32MX,
264 		.security_type = SECURITY_TYPE_PS,
265 	},
266 	{
267 		.peri_id = AT91C_ID_LCDC,
268 		.matrix = MATRIX_H64MX,
269 		.security_type = SECURITY_TYPE_PS,
270 	},
271 	{
272 		.peri_id = AT91C_ID_ISI,
273 		.matrix = MATRIX_H64MX,
274 		.security_type = SECURITY_TYPE_PS,
275 	},
276 	{
277 		.peri_id = AT91C_ID_TRNG,
278 		.matrix = MATRIX_H32MX,
279 		.security_type = SECURITY_TYPE_PS,
280 	},
281 	{
282 		.peri_id = AT91C_ID_PDMIC,
283 		.matrix = MATRIX_H32MX,
284 		.security_type = SECURITY_TYPE_PS,
285 	},
286 	{
287 		.peri_id = AT91C_ID_IRQ,
288 		.matrix = MATRIX_H32MX,
289 		.security_type = SECURITY_TYPE_NS,
290 	},
291 	{
292 		.peri_id = AT91C_ID_SFC,
293 		.matrix = MATRIX_H32MX,
294 		.security_type = SECURITY_TYPE_PS,
295 	},
296 	{
297 		.peri_id = AT91C_ID_SECURAM,
298 		.matrix = MATRIX_H32MX,
299 		.security_type = SECURITY_TYPE_AS,
300 	},
301 	{
302 		.peri_id = AT91C_ID_QSPI0,
303 		.matrix = MATRIX_H64MX,
304 		.security_type = SECURITY_TYPE_PS,
305 	},
306 	{
307 		.peri_id = AT91C_ID_QSPI1,
308 		.matrix = MATRIX_H64MX,
309 		.security_type = SECURITY_TYPE_PS,
310 	},
311 	{
312 		.peri_id = AT91C_ID_I2SC0,
313 		.matrix = MATRIX_H32MX,
314 		.security_type = SECURITY_TYPE_PS,
315 	},
316 	{
317 		.peri_id = AT91C_ID_I2SC1,
318 		.matrix = MATRIX_H32MX,
319 		.security_type = SECURITY_TYPE_PS,
320 	},
321 	{
322 		.peri_id = AT91C_ID_CAN0_INT0,
323 		.matrix = MATRIX_H32MX,
324 		.security_type = SECURITY_TYPE_PS,
325 	},
326 	{
327 		.peri_id = AT91C_ID_CAN1_INT0,
328 		.matrix = MATRIX_H32MX,
329 		.security_type = SECURITY_TYPE_PS,
330 	},
331 	{
332 		.peri_id = AT91C_ID_CLASSD,
333 		.matrix = MATRIX_H32MX,
334 		.security_type = SECURITY_TYPE_PS,
335 	},
336 	{
337 		.peri_id = AT91C_ID_SFR,
338 		.matrix = MATRIX_H32MX,
339 		.security_type = SECURITY_TYPE_PS,
340 	},
341 	{
342 		.peri_id = AT91C_ID_SAIC,
343 		.matrix = MATRIX_H32MX,
344 		.security_type = SECURITY_TYPE_AS,
345 	},
346 	{
347 		.peri_id = AT91C_ID_AIC,
348 		.matrix = MATRIX_H32MX,
349 		.security_type = SECURITY_TYPE_NS,
350 	},
351 	{
352 		.peri_id = AT91C_ID_L2CC,
353 		.matrix = MATRIX_H64MX,
354 		.security_type = SECURITY_TYPE_PS,
355 	},
356 	{
357 		.peri_id = AT91C_ID_CAN0_INT1,
358 		.matrix = MATRIX_H32MX,
359 		.security_type = SECURITY_TYPE_PS,
360 	},
361 	{
362 		.peri_id = AT91C_ID_CAN1_INT1,
363 		.matrix = MATRIX_H32MX,
364 		.security_type = SECURITY_TYPE_PS,
365 	},
366 	{
367 		.peri_id = AT91C_ID_GMAC_Q1,
368 		.matrix = MATRIX_H32MX,
369 		.security_type = SECURITY_TYPE_PS,
370 	},
371 	{
372 		.peri_id = AT91C_ID_GMAC_Q2,
373 		.matrix = MATRIX_H32MX,
374 		.security_type = SECURITY_TYPE_PS,
375 	},
376 	{
377 		.peri_id = AT91C_ID_PIOB,
378 		.matrix = MATRIX_H32MX,
379 		.security_type = SECURITY_TYPE_AS,
380 	},
381 	{
382 		.peri_id = AT91C_ID_PIOC,
383 		.matrix = MATRIX_H32MX,
384 		.security_type = SECURITY_TYPE_AS,
385 	},
386 	{
387 		.peri_id = AT91C_ID_PIOD,
388 		.matrix = MATRIX_H32MX,
389 		.security_type = SECURITY_TYPE_AS,
390 	},
391 	{
392 		.peri_id = AT91C_ID_SDMMC0_TIMER,
393 		.matrix = MATRIX_H32MX,
394 		.security_type = SECURITY_TYPE_PS,
395 	},
396 	{
397 		.peri_id = AT91C_ID_SDMMC1_TIMER,
398 		.matrix = MATRIX_H32MX,
399 		.security_type = SECURITY_TYPE_PS,
400 	},
401 	{
402 		.peri_id = AT91C_ID_SYS,
403 		.matrix = MATRIX_H32MX,
404 		.security_type = SECURITY_TYPE_PS,
405 	},
406 	{
407 		.peri_id = AT91C_ID_ACC,
408 		.matrix = MATRIX_H32MX,
409 		.security_type = SECURITY_TYPE_PS,
410 	},
411 	{
412 		.peri_id = AT91C_ID_RXLP,
413 		.matrix = MATRIX_H32MX,
414 		.security_type = SECURITY_TYPE_PS,
415 	},
416 	{
417 		.peri_id = AT91C_ID_SFRBU,
418 		.matrix = MATRIX_H32MX,
419 		.security_type = SECURITY_TYPE_PS,
420 	},
421 	{
422 		.peri_id = AT91C_ID_CHIPID,
423 		.matrix = MATRIX_H32MX,
424 		.security_type = SECURITY_TYPE_PS,
425 	},
426 };
427 
428 static void matrix_write(unsigned int base,
429 			 unsigned int offset,
430 			 const unsigned int value)
431 {
432 	io_write32(offset + base, value);
433 }
434 
435 static unsigned int matrix_read(int base, unsigned int offset)
436 {
437 	return io_read32(offset + base);
438 }
439 
440 void matrix_write_protect_enable(unsigned int matrix_base)
441 {
442 	matrix_write(matrix_base, MATRIX_WPMR,
443 		    (MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN_ENABLE));
444 }
445 
446 void matrix_write_protect_disable(unsigned int matrix_base)
447 {
448 	matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD);
449 }
450 
451 void matrix_configure_slave_security(unsigned int matrix_base,
452 				     unsigned int slave,
453 				     unsigned int srtop_setting,
454 				     unsigned int srsplit_setting,
455 				     unsigned int ssr_setting)
456 {
457 	matrix_write(matrix_base, MATRIX_SSR(slave), ssr_setting);
458 	matrix_write(matrix_base, MATRIX_SRTSR(slave), srtop_setting);
459 	matrix_write(matrix_base, MATRIX_SASSR(slave), srsplit_setting);
460 }
461 
462 static const struct peri_security *get_peri_security(unsigned int peri_id)
463 {
464 	unsigned int i;
465 
466 	for (i = 0; i < ARRAY_SIZE(peri_security_array); i++) {
467 		if (peri_id == peri_security_array[i].peri_id)
468 			return &peri_security_array[i];
469 	}
470 
471 	return NULL;
472 }
473 
474 static int matrix_set_peri_security(unsigned int matrix, unsigned int peri_id)
475 {
476 	unsigned int base;
477 	unsigned int spselr;
478 	unsigned int idx;
479 	unsigned int bit;
480 
481 	idx = peri_id / 32;
482 	if (idx > 3)
483 		return -1;
484 
485 	bit = (0x01 << (peri_id % 32));
486 
487 	/* The Peripheral ID to SPSELR register bit mapping breaks at ID 73 */
488 	if (peri_id > AT91C_ID_SDMMC1_TIMER)
489 		bit = bit >> 1;
490 
491 	if (matrix == MATRIX_H32MX)
492 		base = matrix32_base();
493 	else if (matrix == MATRIX_H64MX)
494 		base = matrix64_base();
495 	else
496 		return -1;
497 
498 	spselr = matrix_read(base, MATRIX_SPSELR(idx));
499 	spselr |= bit;
500 	matrix_write(base, MATRIX_SPSELR(idx), spselr);
501 
502 	return 0;
503 }
504 
505 int matrix_configure_peri_security(unsigned int *peri_id_array,
506 				   unsigned int size)
507 {
508 	unsigned int i;
509 	unsigned int *peri_id_p;
510 	unsigned int matrix;
511 	unsigned int peri_id;
512 	const struct peri_security *peripheral_sec;
513 	int ret;
514 
515 	if (!peri_id_array || !size)
516 		return -1;
517 
518 	peri_id_p = peri_id_array;
519 	for (i = 0; i < size; i++) {
520 		peripheral_sec = get_peri_security(*peri_id_p);
521 		if (!peripheral_sec)
522 			return -1;
523 
524 		if (peripheral_sec->security_type != SECURITY_TYPE_PS)
525 			return -1;
526 
527 		matrix = peripheral_sec->matrix;
528 		peri_id = *peri_id_p;
529 		ret = matrix_set_peri_security(matrix, peri_id);
530 		if (ret)
531 			return -1;
532 
533 		peri_id_p++;
534 	}
535 
536 	return 0;
537 }
538