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 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 440 static unsigned int matrix_read(int base, unsigned int offset) 441 { 442 return io_read32(offset + base); 443 } 444 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 451 void matrix_write_protect_disable(unsigned int matrix_base) 452 { 453 matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD); 454 } 455 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 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 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 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 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 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 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 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 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 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 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