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 <initcall.h>
30 #include <io.h>
31 #include <kernel/pm.h>
32 #include <kernel/panic.h>
33 #include <matrix.h>
34 #include <platform_config.h>
35 #include <sama5d2.h>
36 #include <stdint.h>
37 #include <tz_matrix.h>
38 #include <trace.h>
39
40 #define MATRIX_AXIMX 1
41 #define MATRIX_H64MX 2
42 #define MATRIX_H32MX 3
43
44 #define SECURITY_TYPE_AS 1
45 #define SECURITY_TYPE_NS 2
46 #define SECURITY_TYPE_PS 3
47
48 #define WORLD_NON_SECURE 0
49 #define WORLD_SECURE 1
50
51 #define MATRIX_SPSELR_COUNT 3
52 #define MATRIX_SLAVE_COUNT 15
53
54 struct peri_security {
55 unsigned int peri_id;
56 unsigned int matrix;
57 unsigned int security_type;
58 };
59
60 static const struct peri_security peri_security_array[] = {
61 {
62 .peri_id = AT91C_ID_PMC,
63 .matrix = MATRIX_H64MX,
64 .security_type = SECURITY_TYPE_PS,
65 },
66 {
67 .peri_id = AT91C_ID_ARM,
68 .matrix = MATRIX_H64MX,
69 .security_type = SECURITY_TYPE_PS,
70 },
71 {
72 .peri_id = AT91C_ID_PIT,
73 .matrix = MATRIX_H32MX,
74 .security_type = SECURITY_TYPE_PS,
75 },
76 {
77 .peri_id = AT91C_ID_WDT,
78 .matrix = MATRIX_H32MX,
79 .security_type = SECURITY_TYPE_PS,
80 },
81 {
82 .peri_id = AT91C_ID_GMAC,
83 .matrix = MATRIX_H32MX,
84 .security_type = SECURITY_TYPE_PS,
85 },
86 {
87 .peri_id = AT91C_ID_XDMAC0,
88 .matrix = MATRIX_H64MX,
89 .security_type = SECURITY_TYPE_PS,
90 },
91 {
92 .peri_id = AT91C_ID_XDMAC1,
93 .matrix = MATRIX_H64MX,
94 .security_type = SECURITY_TYPE_PS,
95 },
96 {
97 .peri_id = AT91C_ID_ICM,
98 .matrix = MATRIX_H32MX,
99 .security_type = SECURITY_TYPE_PS,
100 },
101 {
102 .peri_id = AT91C_ID_AES,
103 .matrix = MATRIX_H64MX,
104 .security_type = SECURITY_TYPE_PS,
105 },
106 {
107 .peri_id = AT91C_ID_AESB,
108 .matrix = MATRIX_H64MX,
109 .security_type = SECURITY_TYPE_PS,
110 },
111 {
112 .peri_id = AT91C_ID_TDES,
113 .matrix = MATRIX_H32MX,
114 .security_type = SECURITY_TYPE_PS,
115 },
116 {
117 .peri_id = AT91C_ID_SHA,
118 .matrix = MATRIX_H64MX,
119 .security_type = SECURITY_TYPE_PS,
120 },
121 {
122 .peri_id = AT91C_ID_MPDDRC,
123 .matrix = MATRIX_H64MX,
124 .security_type = SECURITY_TYPE_PS,
125 },
126 {
127 .peri_id = AT91C_ID_MATRIX1,
128 .matrix = MATRIX_H32MX,
129 .security_type = SECURITY_TYPE_AS,
130 },
131 {
132 .peri_id = AT91C_ID_MATRIX0,
133 .matrix = MATRIX_H64MX,
134 .security_type = SECURITY_TYPE_AS,
135 },
136 {
137 .peri_id = AT91C_ID_SECUMOD,
138 .matrix = MATRIX_H32MX,
139 .security_type = SECURITY_TYPE_AS,
140 },
141 {
142 .peri_id = AT91C_ID_HSMC,
143 .matrix = MATRIX_H32MX,
144 .security_type = SECURITY_TYPE_PS,
145 },
146 {
147 .peri_id = AT91C_ID_PIOA,
148 .matrix = MATRIX_H32MX,
149 .security_type = SECURITY_TYPE_AS,
150 },
151 {
152 .peri_id = AT91C_ID_FLEXCOM0,
153 .matrix = MATRIX_H32MX,
154 .security_type = SECURITY_TYPE_PS,
155 },
156 {
157 .peri_id = AT91C_ID_FLEXCOM1,
158 .matrix = MATRIX_H32MX,
159 .security_type = SECURITY_TYPE_PS,
160 },
161 {
162 .peri_id = AT91C_ID_FLEXCOM2,
163 .matrix = MATRIX_H32MX,
164 .security_type = SECURITY_TYPE_PS,
165 },
166 {
167 .peri_id = AT91C_ID_FLEXCOM3,
168 .matrix = MATRIX_H32MX,
169 .security_type = SECURITY_TYPE_PS,
170 },
171 {
172 .peri_id = AT91C_ID_FLEXCOM4,
173 .matrix = MATRIX_H32MX,
174 .security_type = SECURITY_TYPE_PS,
175 },
176 {
177 .peri_id = AT91C_ID_UART0,
178 .matrix = MATRIX_H32MX,
179 .security_type = SECURITY_TYPE_PS,
180 },
181 {
182 .peri_id = AT91C_ID_UART1,
183 .matrix = MATRIX_H32MX,
184 .security_type = SECURITY_TYPE_PS,
185 },
186 {
187 .peri_id = AT91C_ID_UART2,
188 .matrix = MATRIX_H32MX,
189 .security_type = SECURITY_TYPE_PS,
190 },
191 {
192 .peri_id = AT91C_ID_UART3,
193 .matrix = MATRIX_H32MX,
194 .security_type = SECURITY_TYPE_PS,
195 },
196 {
197 .peri_id = AT91C_ID_UART4,
198 .matrix = MATRIX_H32MX,
199 .security_type = SECURITY_TYPE_PS,
200 },
201 {
202 .peri_id = AT91C_ID_TWI0,
203 .matrix = MATRIX_H32MX,
204 .security_type = SECURITY_TYPE_PS,
205 },
206 {
207 .peri_id = AT91C_ID_TWI1,
208 .matrix = MATRIX_H32MX,
209 .security_type = SECURITY_TYPE_PS,
210 },
211 {
212 .peri_id = AT91C_ID_SDMMC0,
213 .matrix = MATRIX_H64MX,
214 .security_type = SECURITY_TYPE_PS,
215 },
216 {
217 .peri_id = AT91C_ID_SDMMC1,
218 .matrix = MATRIX_H64MX,
219 .security_type = SECURITY_TYPE_PS,
220 },
221 {
222 .peri_id = AT91C_ID_SPI0,
223 .matrix = MATRIX_H32MX,
224 .security_type = SECURITY_TYPE_PS,
225 },
226 {
227 .peri_id = AT91C_ID_SPI1,
228 .matrix = MATRIX_H32MX,
229 .security_type = SECURITY_TYPE_PS,
230 },
231 {
232 .peri_id = AT91C_ID_TC0,
233 .matrix = MATRIX_H32MX,
234 .security_type = SECURITY_TYPE_PS,
235 },
236 {
237 .peri_id = AT91C_ID_TC1,
238 .matrix = MATRIX_H32MX,
239 .security_type = SECURITY_TYPE_PS,
240 },
241 {
242 .peri_id = AT91C_ID_PWM,
243 .matrix = MATRIX_H32MX,
244 .security_type = SECURITY_TYPE_PS,
245 },
246 {
247 .peri_id = AT91C_ID_ADC,
248 .matrix = MATRIX_H32MX,
249 .security_type = SECURITY_TYPE_PS,
250 },
251 {
252 .peri_id = AT91C_ID_UHPHS,
253 .matrix = MATRIX_H32MX,
254 .security_type = SECURITY_TYPE_PS,
255 },
256 {
257 .peri_id = AT91C_ID_UDPHS,
258 .matrix = MATRIX_H32MX,
259 .security_type = SECURITY_TYPE_PS,
260 },
261 {
262 .peri_id = AT91C_ID_SSC0,
263 .matrix = MATRIX_H32MX,
264 .security_type = SECURITY_TYPE_PS,
265 },
266 {
267 .peri_id = AT91C_ID_SSC1,
268 .matrix = MATRIX_H32MX,
269 .security_type = SECURITY_TYPE_PS,
270 },
271 {
272 .peri_id = AT91C_ID_LCDC,
273 .matrix = MATRIX_H64MX,
274 .security_type = SECURITY_TYPE_PS,
275 },
276 {
277 .peri_id = AT91C_ID_ISI,
278 .matrix = MATRIX_H64MX,
279 .security_type = SECURITY_TYPE_PS,
280 },
281 {
282 .peri_id = AT91C_ID_TRNG,
283 .matrix = MATRIX_H32MX,
284 .security_type = SECURITY_TYPE_PS,
285 },
286 {
287 .peri_id = AT91C_ID_PDMIC,
288 .matrix = MATRIX_H32MX,
289 .security_type = SECURITY_TYPE_PS,
290 },
291 {
292 .peri_id = AT91C_ID_IRQ,
293 .matrix = MATRIX_H32MX,
294 .security_type = SECURITY_TYPE_NS,
295 },
296 {
297 .peri_id = AT91C_ID_SFC,
298 .matrix = MATRIX_H32MX,
299 .security_type = SECURITY_TYPE_PS,
300 },
301 {
302 .peri_id = AT91C_ID_SECURAM,
303 .matrix = MATRIX_H32MX,
304 .security_type = SECURITY_TYPE_AS,
305 },
306 {
307 .peri_id = AT91C_ID_QSPI0,
308 .matrix = MATRIX_H64MX,
309 .security_type = SECURITY_TYPE_PS,
310 },
311 {
312 .peri_id = AT91C_ID_QSPI1,
313 .matrix = MATRIX_H64MX,
314 .security_type = SECURITY_TYPE_PS,
315 },
316 {
317 .peri_id = AT91C_ID_I2SC0,
318 .matrix = MATRIX_H32MX,
319 .security_type = SECURITY_TYPE_PS,
320 },
321 {
322 .peri_id = AT91C_ID_I2SC1,
323 .matrix = MATRIX_H32MX,
324 .security_type = SECURITY_TYPE_PS,
325 },
326 {
327 .peri_id = AT91C_ID_CAN0_INT0,
328 .matrix = MATRIX_H32MX,
329 .security_type = SECURITY_TYPE_PS,
330 },
331 {
332 .peri_id = AT91C_ID_CAN1_INT0,
333 .matrix = MATRIX_H32MX,
334 .security_type = SECURITY_TYPE_PS,
335 },
336 {
337 .peri_id = AT91C_ID_CLASSD,
338 .matrix = MATRIX_H32MX,
339 .security_type = SECURITY_TYPE_PS,
340 },
341 {
342 .peri_id = AT91C_ID_SFR,
343 .matrix = MATRIX_H32MX,
344 .security_type = SECURITY_TYPE_PS,
345 },
346 {
347 .peri_id = AT91C_ID_SAIC,
348 .matrix = MATRIX_H32MX,
349 .security_type = SECURITY_TYPE_AS,
350 },
351 {
352 .peri_id = AT91C_ID_AIC,
353 .matrix = MATRIX_H32MX,
354 .security_type = SECURITY_TYPE_NS,
355 },
356 {
357 .peri_id = AT91C_ID_L2CC,
358 .matrix = MATRIX_H64MX,
359 .security_type = SECURITY_TYPE_PS,
360 },
361 {
362 .peri_id = AT91C_ID_CAN0_INT1,
363 .matrix = MATRIX_H32MX,
364 .security_type = SECURITY_TYPE_PS,
365 },
366 {
367 .peri_id = AT91C_ID_CAN1_INT1,
368 .matrix = MATRIX_H32MX,
369 .security_type = SECURITY_TYPE_PS,
370 },
371 {
372 .peri_id = AT91C_ID_GMAC_Q1,
373 .matrix = MATRIX_H32MX,
374 .security_type = SECURITY_TYPE_PS,
375 },
376 {
377 .peri_id = AT91C_ID_GMAC_Q2,
378 .matrix = MATRIX_H32MX,
379 .security_type = SECURITY_TYPE_PS,
380 },
381 {
382 .peri_id = AT91C_ID_PIOB,
383 .matrix = MATRIX_H32MX,
384 .security_type = SECURITY_TYPE_AS,
385 },
386 {
387 .peri_id = AT91C_ID_PIOC,
388 .matrix = MATRIX_H32MX,
389 .security_type = SECURITY_TYPE_AS,
390 },
391 {
392 .peri_id = AT91C_ID_PIOD,
393 .matrix = MATRIX_H32MX,
394 .security_type = SECURITY_TYPE_AS,
395 },
396 {
397 .peri_id = AT91C_ID_SDMMC0_TIMER,
398 .matrix = MATRIX_H32MX,
399 .security_type = SECURITY_TYPE_PS,
400 },
401 {
402 .peri_id = AT91C_ID_SDMMC1_TIMER,
403 .matrix = MATRIX_H32MX,
404 .security_type = SECURITY_TYPE_PS,
405 },
406 {
407 .peri_id = AT91C_ID_SYS,
408 .matrix = MATRIX_H32MX,
409 .security_type = SECURITY_TYPE_PS,
410 },
411 {
412 .peri_id = AT91C_ID_ACC,
413 .matrix = MATRIX_H32MX,
414 .security_type = SECURITY_TYPE_PS,
415 },
416 {
417 .peri_id = AT91C_ID_RXLP,
418 .matrix = MATRIX_H32MX,
419 .security_type = SECURITY_TYPE_PS,
420 },
421 {
422 .peri_id = AT91C_ID_SFRBU,
423 .matrix = MATRIX_H32MX,
424 .security_type = SECURITY_TYPE_PS,
425 },
426 {
427 .peri_id = AT91C_ID_CHIPID,
428 .matrix = MATRIX_H32MX,
429 .security_type = SECURITY_TYPE_PS,
430 },
431 };
432
matrix_write(unsigned int base,unsigned int offset,const unsigned int value)433 static void matrix_write(unsigned int base,
434 unsigned int offset,
435 const unsigned int value)
436 {
437 io_write32(offset + base, value);
438 }
439
matrix_read(int base,unsigned int offset)440 static unsigned int matrix_read(int base, unsigned int offset)
441 {
442 return io_read32(offset + base);
443 }
444
matrix_write_protect_enable(unsigned int matrix_base)445 void matrix_write_protect_enable(unsigned int matrix_base)
446 {
447 matrix_write(matrix_base, MATRIX_WPMR,
448 (MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN_ENABLE));
449 }
450
matrix_write_protect_disable(unsigned int matrix_base)451 void matrix_write_protect_disable(unsigned int matrix_base)
452 {
453 matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD);
454 }
455
matrix_configure_slave_security(unsigned int matrix_base,unsigned int slave,unsigned int srtop_setting,unsigned int srsplit_setting,unsigned int ssr_setting)456 void matrix_configure_slave_security(unsigned int matrix_base,
457 unsigned int slave,
458 unsigned int srtop_setting,
459 unsigned int srsplit_setting,
460 unsigned int ssr_setting)
461 {
462 matrix_write(matrix_base, MATRIX_SSR(slave), ssr_setting);
463 matrix_write(matrix_base, MATRIX_SRTSR(slave), srtop_setting);
464 matrix_write(matrix_base, MATRIX_SASSR(slave), srsplit_setting);
465 }
466
get_peri_security(unsigned int peri_id)467 static const struct peri_security *get_peri_security(unsigned int peri_id)
468 {
469 unsigned int i;
470
471 for (i = 0; i < ARRAY_SIZE(peri_security_array); i++) {
472 if (peri_id == peri_security_array[i].peri_id)
473 return &peri_security_array[i];
474 }
475
476 return NULL;
477 }
478
matrix_set_periph_world(unsigned int matrix,unsigned int peri_id,unsigned int world)479 static int matrix_set_periph_world(unsigned int matrix, unsigned int peri_id,
480 unsigned int world)
481 {
482 unsigned int base;
483 unsigned int spselr;
484 unsigned int idx;
485 unsigned int bit;
486
487 idx = peri_id / 32;
488 if (idx > 3)
489 return -1;
490
491 bit = (0x01 << (peri_id % 32));
492
493 if (matrix == MATRIX_H32MX)
494 base = matrix32_base();
495 else if (matrix == MATRIX_H64MX)
496 base = matrix64_base();
497 else
498 return -1;
499
500 spselr = matrix_read(base, MATRIX_SPSELR(idx));
501 if (world == WORLD_SECURE)
502 spselr &= ~bit;
503 else
504 spselr |= bit;
505 matrix_write(base, MATRIX_SPSELR(idx), spselr);
506
507 return 0;
508 }
509
matrix_configure_periph_secure(unsigned int peri_id)510 int matrix_configure_periph_secure(unsigned int peri_id)
511 {
512 const struct peri_security *psec = NULL;
513
514 psec = get_peri_security(peri_id);
515 if (!psec)
516 return -1;
517
518 return matrix_set_periph_world(psec->matrix, peri_id, WORLD_SECURE);
519 }
520
matrix_configure_periph_non_secure(unsigned int * peri_id_array,unsigned int size)521 int matrix_configure_periph_non_secure(unsigned int *peri_id_array,
522 unsigned int size)
523 {
524 unsigned int i;
525 unsigned int *peri_id_p;
526 unsigned int matrix;
527 unsigned int peri_id;
528 const struct peri_security *peripheral_sec;
529 int ret;
530
531 if (!peri_id_array || !size)
532 return -1;
533
534 peri_id_p = peri_id_array;
535 for (i = 0; i < size; i++) {
536 peripheral_sec = get_peri_security(*peri_id_p);
537 if (!peripheral_sec)
538 return -1;
539
540 if (peripheral_sec->security_type != SECURITY_TYPE_PS)
541 return -1;
542
543 matrix = peripheral_sec->matrix;
544 peri_id = *peri_id_p;
545 ret = matrix_set_periph_world(matrix, peri_id,
546 WORLD_NON_SECURE);
547 if (ret)
548 return -1;
549
550 peri_id_p++;
551 }
552
553 return 0;
554 }
555
556 #ifdef CFG_PM_ARM32
557 struct matrix_state {
558 uint32_t spselr[MATRIX_SPSELR_COUNT];
559 uint32_t ssr[MATRIX_SLAVE_COUNT];
560 uint32_t srtsr[MATRIX_SLAVE_COUNT];
561 uint32_t sassr[MATRIX_SLAVE_COUNT];
562 uint32_t meier;
563 uint32_t meimr;
564 };
565
566 static struct matrix_state matrix32_state;
567 static struct matrix_state matrix64_state;
568
matrix_save_regs(vaddr_t base,struct matrix_state * state)569 static void matrix_save_regs(vaddr_t base, struct matrix_state *state)
570 {
571 int idx = 0;
572
573 for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++)
574 state->spselr[idx] = matrix_read(base, MATRIX_SPSELR(idx));
575
576 for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) {
577 state->ssr[idx] = matrix_read(base, MATRIX_SSR(idx));
578 state->srtsr[idx] = matrix_read(base, MATRIX_SRTSR(idx));
579 state->sassr[idx] = matrix_read(base, MATRIX_SASSR(idx));
580 }
581
582 state->meier = matrix_read(base, MATRIX_MEIER);
583 state->meimr = matrix_read(base, MATRIX_MEIMR);
584 }
585
matrix_suspend(void)586 static void matrix_suspend(void)
587 {
588 matrix_save_regs(matrix32_base(), &matrix32_state);
589 matrix_save_regs(matrix64_base(), &matrix64_state);
590 }
591
matrix_restore_regs(vaddr_t base,struct matrix_state * state)592 static void matrix_restore_regs(vaddr_t base, struct matrix_state *state)
593 {
594 int idx = 0;
595
596 matrix_write_protect_disable(base);
597
598 for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++)
599 matrix_write(base, MATRIX_SPSELR(idx), state->spselr[idx]);
600
601 for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) {
602 matrix_write(base, MATRIX_SSR(idx), state->ssr[idx]);
603 matrix_write(base, MATRIX_SRTSR(idx), state->srtsr[idx]);
604 matrix_write(base, MATRIX_SASSR(idx), state->sassr[idx]);
605 }
606
607 matrix_write(base, MATRIX_MEIER, state->meier);
608 matrix_write(base, MATRIX_MEIMR, state->meimr);
609 }
610
matrix_resume(void)611 static void matrix_resume(void)
612 {
613 matrix_restore_regs(matrix32_base(), &matrix32_state);
614 matrix_restore_regs(matrix64_base(), &matrix64_state);
615 }
616
matrix_pm(enum pm_op op,uint32_t pm_hint __unused,const struct pm_callback_handle * hdl __unused)617 static TEE_Result matrix_pm(enum pm_op op, uint32_t pm_hint __unused,
618 const struct pm_callback_handle *hdl __unused)
619 {
620 switch (op) {
621 case PM_OP_RESUME:
622 matrix_resume();
623 break;
624 case PM_OP_SUSPEND:
625 matrix_suspend();
626 break;
627 default:
628 panic("Invalid PM operation");
629 }
630
631 return TEE_SUCCESS;
632 }
633
matrix_pm_init(void)634 static TEE_Result matrix_pm_init(void)
635 {
636 /*
637 * We can't call matrix_register_pm in matrix_init since allocator is
638 * not ready yet so we just call it later in this driver init callback.
639 */
640 register_pm_driver_cb(matrix_pm, NULL, "sam-matrix");
641
642 return TEE_SUCCESS;
643 }
644 driver_init(matrix_pm_init);
645
646 #endif
647