1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <config.h> 8 #include <initcall.h> 9 #include <kernel/dt.h> 10 #include <kernel/dt_driver.h> 11 #include <kernel/interrupt.h> 12 #include <libfdt.h> 13 #include <mm/core_memprot.h> 14 #include <mm/core_mmu.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <trace.h> 18 19 static struct dt_descriptor external_dt __nex_bss; 20 21 #if defined(CFG_CORE_FFA) 22 static void *manifest_dt __nex_bss; 23 #endif 24 25 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs) 26 { 27 const struct dt_device_match *dm; 28 const struct dt_driver *drv; 29 30 for_each_dt_driver(drv) { 31 for (dm = drv->match_table; dm; dm++) { 32 if (!dm->compatible) { 33 break; 34 } 35 if (!fdt_node_check_compatible(fdt, offs, 36 dm->compatible)) { 37 return drv; 38 } 39 } 40 } 41 42 return NULL; 43 } 44 45 bool dt_have_prop(const void *fdt, int offs, const char *propname) 46 { 47 const void *prop; 48 49 prop = fdt_getprop(fdt, offs, propname, NULL); 50 51 return prop; 52 } 53 54 int dt_disable_status(void *fdt, int node) 55 { 56 const char *prop = NULL; 57 int len = 0; 58 59 prop = fdt_getprop(fdt, node, "status", &len); 60 if (!prop) { 61 if (fdt_setprop_string(fdt, node, "status", "disabled")) 62 return -1; 63 } else { 64 /* 65 * Status is there, modify it. 66 * Ask to set "disabled" value to the property. The value 67 * will be automatically truncated with "len" size by the 68 * fdt_setprop_inplace function. 69 * Setting a value different from "ok" or "okay" will disable 70 * the property. 71 * Setting a truncated value of "disabled" with the original 72 * property "len" is preferred to not increase the DT size and 73 * losing time in recalculating the overall DT offsets. 74 * If original length of the status property is larger than 75 * "disabled", the property will start with "disabled" and be 76 * completed with the rest of the original property. 77 */ 78 if (fdt_setprop_inplace(fdt, node, "status", "disabled", len)) 79 return -1; 80 } 81 82 return 0; 83 } 84 85 int dt_enable_secure_status(void *fdt, int node) 86 { 87 if (dt_disable_status(fdt, node)) { 88 EMSG("Unable to disable Normal Status"); 89 return -1; 90 } 91 92 if (fdt_setprop_string(fdt, node, "secure-status", "okay")) 93 return -1; 94 95 return 0; 96 } 97 98 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 99 enum dt_map_dev_directive mapping) 100 { 101 enum teecore_memtypes mtype; 102 paddr_t pbase; 103 vaddr_t vbase; 104 size_t sz; 105 int st; 106 107 assert(cpu_mmu_enabled()); 108 109 st = fdt_get_status(fdt, offs); 110 if (st == DT_STATUS_DISABLED) 111 return -1; 112 113 pbase = fdt_reg_base_address(fdt, offs); 114 if (pbase == DT_INFO_INVALID_REG) 115 return -1; 116 sz = fdt_reg_size(fdt, offs); 117 if (sz == DT_INFO_INVALID_REG_SIZE) 118 return -1; 119 120 switch (mapping) { 121 case DT_MAP_AUTO: 122 if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC)) 123 mtype = MEM_AREA_IO_SEC; 124 else 125 mtype = MEM_AREA_IO_NSEC; 126 break; 127 case DT_MAP_SECURE: 128 mtype = MEM_AREA_IO_SEC; 129 break; 130 case DT_MAP_NON_SECURE: 131 mtype = MEM_AREA_IO_NSEC; 132 break; 133 default: 134 panic("Invalid mapping specified"); 135 break; 136 } 137 138 /* Check if we have a mapping, create one if needed */ 139 vbase = (vaddr_t)core_mmu_add_mapping(mtype, pbase, sz); 140 if (!vbase) { 141 EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA, 142 (size_t)sz, pbase); 143 return -1; 144 } 145 146 *base = vbase; 147 *size = sz; 148 return 0; 149 } 150 151 /* Read a physical address (n=1 or 2 cells) */ 152 static paddr_t fdt_read_paddr(const uint32_t *cell, int n) 153 { 154 paddr_t addr; 155 156 if (n < 1 || n > 2) 157 goto bad; 158 159 addr = fdt32_to_cpu(*cell); 160 cell++; 161 if (n == 2) { 162 #ifdef ARM32 163 if (addr) { 164 /* High order 32 bits can't be nonzero */ 165 goto bad; 166 } 167 addr = fdt32_to_cpu(*cell); 168 #else 169 addr = (addr << 32) | fdt32_to_cpu(*cell); 170 #endif 171 } 172 173 return addr; 174 bad: 175 return DT_INFO_INVALID_REG; 176 177 } 178 179 paddr_t fdt_reg_base_address(const void *fdt, int offs) 180 { 181 const void *reg; 182 int ncells; 183 int len; 184 int parent; 185 186 parent = fdt_parent_offset(fdt, offs); 187 if (parent < 0) 188 return DT_INFO_INVALID_REG; 189 190 reg = fdt_getprop(fdt, offs, "reg", &len); 191 if (!reg) 192 return DT_INFO_INVALID_REG; 193 194 ncells = fdt_address_cells(fdt, parent); 195 if (ncells < 0) 196 return DT_INFO_INVALID_REG; 197 198 return fdt_read_paddr(reg, ncells); 199 } 200 201 static size_t fdt_read_size(const uint32_t *cell, int n) 202 { 203 uint32_t sz = 0; 204 205 sz = fdt32_to_cpu(*cell); 206 if (n == 2) { 207 if (sz) 208 return DT_INFO_INVALID_REG_SIZE; 209 210 cell++; 211 sz = fdt32_to_cpu(*cell); 212 } 213 214 return sz; 215 } 216 217 size_t fdt_reg_size(const void *fdt, int offs) 218 { 219 const uint32_t *reg; 220 int n; 221 int len; 222 int parent; 223 224 parent = fdt_parent_offset(fdt, offs); 225 if (parent < 0) 226 return DT_INFO_INVALID_REG_SIZE; 227 228 reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len); 229 if (!reg) 230 return DT_INFO_INVALID_REG_SIZE; 231 232 n = fdt_address_cells(fdt, parent); 233 if (n < 1 || n > 2) 234 return DT_INFO_INVALID_REG_SIZE; 235 236 reg += n; 237 238 n = fdt_size_cells(fdt, parent); 239 if (n < 1 || n > 2) 240 return DT_INFO_INVALID_REG_SIZE; 241 242 return fdt_read_size(reg, n); 243 } 244 245 static bool is_okay(const char *st, int len) 246 { 247 return !strncmp(st, "ok", len) || !strncmp(st, "okay", len); 248 } 249 250 int fdt_get_status(const void *fdt, int offs) 251 { 252 const char *prop; 253 int st = 0; 254 int len; 255 256 prop = fdt_getprop(fdt, offs, "status", &len); 257 if (!prop || is_okay(prop, len)) { 258 /* If status is not specified, it defaults to "okay" */ 259 st |= DT_STATUS_OK_NSEC; 260 } 261 262 prop = fdt_getprop(fdt, offs, "secure-status", &len); 263 if (!prop) { 264 /* 265 * When secure-status is not specified it defaults to the same 266 * value as status 267 */ 268 if (st & DT_STATUS_OK_NSEC) 269 st |= DT_STATUS_OK_SEC; 270 } else { 271 if (is_okay(prop, len)) 272 st |= DT_STATUS_OK_SEC; 273 } 274 275 return st; 276 } 277 278 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs) 279 { 280 struct dt_node_info dinfo = { 281 .reg = DT_INFO_INVALID_REG, 282 .reg_size = DT_INFO_INVALID_REG_SIZE, 283 .clock = DT_INFO_INVALID_CLOCK, 284 .reset = DT_INFO_INVALID_RESET, 285 .interrupt = DT_INFO_INVALID_INTERRUPT, 286 }; 287 const fdt32_t *cuint; 288 289 dinfo.reg = fdt_reg_base_address(fdt, offs); 290 dinfo.reg_size = fdt_reg_size(fdt, offs); 291 292 cuint = fdt_getprop(fdt, offs, "clocks", NULL); 293 if (cuint) { 294 cuint++; 295 dinfo.clock = (int)fdt32_to_cpu(*cuint); 296 } 297 298 cuint = fdt_getprop(fdt, offs, "resets", NULL); 299 if (cuint) { 300 cuint++; 301 dinfo.reset = (int)fdt32_to_cpu(*cuint); 302 } 303 304 dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type, 305 &dinfo.prio); 306 307 dinfo.status = fdt_get_status(fdt, offs); 308 309 *info = dinfo; 310 } 311 312 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 313 uint32_t *array, size_t count) 314 { 315 const fdt32_t *cuint = NULL; 316 int len = 0; 317 uint32_t i = 0; 318 319 cuint = fdt_getprop(fdt, node, prop_name, &len); 320 if (!cuint) 321 return len; 322 323 if ((uint32_t)len != (count * sizeof(uint32_t))) 324 return -FDT_ERR_BADLAYOUT; 325 326 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 327 *array = fdt32_to_cpu(*cuint); 328 array++; 329 cuint++; 330 } 331 332 return 0; 333 } 334 335 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name, 336 int index, uint32_t *value) 337 { 338 const fdt32_t *cuint = NULL; 339 int len = 0; 340 341 cuint = fdt_getprop(fdt, node, prop_name, &len); 342 if (!cuint) 343 return len; 344 345 if ((uint32_t)len < (sizeof(uint32_t) * (index + 1))) 346 return -FDT_ERR_BADLAYOUT; 347 348 *value = fdt32_to_cpu(cuint[index]); 349 350 return 0; 351 } 352 353 int fdt_read_uint32(const void *fdt, int node, const char *prop_name, 354 uint32_t *value) 355 { 356 return fdt_read_uint32_array(fdt, node, prop_name, value, 1); 357 } 358 359 uint32_t fdt_read_uint32_default(const void *fdt, int node, 360 const char *prop_name, uint32_t dflt_value) 361 { 362 uint32_t ret = dflt_value; 363 364 fdt_read_uint32_index(fdt, node, prop_name, 0, &ret); 365 366 return ret; 367 } 368 369 int fdt_get_reg_props_by_index(const void *fdt, int node, int index, 370 paddr_t *base, size_t *size) 371 { 372 const fdt32_t *prop = NULL; 373 int parent = 0; 374 int len = 0; 375 int address_cells = 0; 376 int size_cells = 0; 377 int cell = 0; 378 379 parent = fdt_parent_offset(fdt, node); 380 if (parent < 0) 381 return parent; 382 383 address_cells = fdt_address_cells(fdt, parent); 384 if (address_cells < 0) 385 return address_cells; 386 387 size_cells = fdt_size_cells(fdt, parent); 388 if (size_cells < 0) 389 return size_cells; 390 391 cell = index * (address_cells + size_cells); 392 393 prop = fdt_getprop(fdt, node, "reg", &len); 394 if (!prop) 395 return len; 396 397 if (((cell + address_cells + size_cells) * (int)sizeof(uint32_t)) > len) 398 return -FDT_ERR_BADVALUE; 399 400 if (base) { 401 *base = fdt_read_paddr(&prop[cell], address_cells); 402 if (*base == DT_INFO_INVALID_REG) 403 return -FDT_ERR_BADVALUE; 404 } 405 406 if (size) { 407 *size = fdt_read_size(&prop[cell + address_cells], size_cells); 408 if (*size == DT_INFO_INVALID_REG_SIZE) 409 return -FDT_ERR_BADVALUE; 410 } 411 412 return 0; 413 } 414 415 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name, 416 paddr_t *base, size_t *size) 417 { 418 int index = 0; 419 420 index = fdt_stringlist_search(fdt, node, "reg-names", name); 421 if (index < 0) 422 return index; 423 424 return fdt_get_reg_props_by_index(fdt, node, index, base, size); 425 } 426 427 int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name, 428 uint64_t *num) 429 { 430 const void *prop = NULL; 431 int len = 0; 432 433 prop = fdt_getprop(fdt, nodeoffset, name, &len); 434 if (!prop) 435 return len; 436 437 switch (len) { 438 case sizeof(uint32_t): 439 *num = fdt32_ld(prop); 440 return 0; 441 case sizeof(uint64_t): 442 *num = fdt64_ld(prop); 443 return 0; 444 default: 445 return -FDT_ERR_BADVALUE; 446 } 447 } 448 449 void *get_dt(void) 450 { 451 void *fdt = get_embedded_dt(); 452 453 if (!fdt) 454 fdt = get_external_dt(); 455 456 return fdt; 457 } 458 459 void *get_secure_dt(void) 460 { 461 void *fdt = get_embedded_dt(); 462 463 if (!fdt && IS_ENABLED(CFG_MAP_EXT_DT_SECURE)) 464 fdt = get_external_dt(); 465 466 return fdt; 467 } 468 469 #if defined(CFG_EMBED_DTB) 470 void *get_embedded_dt(void) 471 { 472 static bool checked; 473 474 assert(cpu_mmu_enabled()); 475 476 if (!checked) { 477 IMSG("Embedded DTB found"); 478 479 if (fdt_check_header(embedded_secure_dtb)) 480 panic("Invalid embedded DTB"); 481 482 checked = true; 483 } 484 485 return embedded_secure_dtb; 486 } 487 #else 488 void *get_embedded_dt(void) 489 { 490 return NULL; 491 } 492 #endif /*CFG_EMBED_DTB*/ 493 494 #ifdef _CFG_USE_DTB_OVERLAY 495 static int add_dt_overlay_fragment(struct dt_descriptor *dt, int ioffs) 496 { 497 char frag[32] = { }; 498 int offs = 0; 499 int ret = 0; 500 501 ret = snprintf(frag, sizeof(frag), "fragment@%d", dt->frag_id); 502 if (ret < 0 || (size_t)ret >= sizeof(frag)) 503 return -1; 504 505 offs = fdt_add_subnode(dt->blob, ioffs, frag); 506 if (offs < 0) 507 return offs; 508 509 dt->frag_id += 1; 510 511 ret = fdt_setprop_string(dt->blob, offs, "target-path", "/"); 512 if (ret < 0) 513 return ret; 514 515 return fdt_add_subnode(dt->blob, offs, "__overlay__"); 516 } 517 518 static int init_dt_overlay(struct dt_descriptor *dt, int __maybe_unused dt_size) 519 { 520 int fragment = 0; 521 522 if (IS_ENABLED(CFG_EXTERNAL_DTB_OVERLAY)) { 523 if (!fdt_check_header(dt->blob)) { 524 fdt_for_each_subnode(fragment, dt->blob, 0) 525 dt->frag_id += 1; 526 return 0; 527 } 528 } 529 530 return fdt_create_empty_tree(dt->blob, dt_size); 531 } 532 #else 533 static int add_dt_overlay_fragment(struct dt_descriptor *dt __unused, int offs) 534 { 535 return offs; 536 } 537 538 static int init_dt_overlay(struct dt_descriptor *dt __unused, 539 int dt_size __unused) 540 { 541 return 0; 542 } 543 #endif /* _CFG_USE_DTB_OVERLAY */ 544 545 struct dt_descriptor *get_external_dt_desc(void) 546 { 547 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 548 return NULL; 549 550 return &external_dt; 551 } 552 553 void init_external_dt(unsigned long phys_dt, size_t dt_sz) 554 { 555 struct dt_descriptor *dt = &external_dt; 556 int ret = 0; 557 enum teecore_memtypes mtype = MEM_AREA_MAXTYPE; 558 559 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 560 return; 561 562 if (!phys_dt || !dt_sz) { 563 /* 564 * No need to panic as we're not using the DT in OP-TEE 565 * yet, we're only adding some nodes for normal world use. 566 * This makes the switch to using DT easier as we can boot 567 * a newer OP-TEE with older boot loaders. Once we start to 568 * initialize devices based on DT we'll likely panic 569 * instead of returning here. 570 */ 571 IMSG("No non-secure external DT"); 572 return; 573 } 574 575 mtype = core_mmu_get_type_by_pa(phys_dt); 576 if (mtype == MEM_AREA_MAXTYPE) { 577 /* Map the DTB if it is not yet mapped */ 578 dt->blob = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt, 579 dt_sz); 580 if (!dt->blob) 581 panic("Failed to map external DTB"); 582 } else { 583 /* Get the DTB address if already mapped in a memory area */ 584 dt->blob = phys_to_virt(phys_dt, mtype, dt_sz); 585 if (!dt->blob) { 586 EMSG("Failed to get a mapped external DTB for PA %#lx", 587 phys_dt); 588 panic(); 589 } 590 } 591 592 ret = init_dt_overlay(dt, dt_sz); 593 if (ret < 0) { 594 EMSG("Device Tree Overlay init fail @ %#lx: error %d", phys_dt, 595 ret); 596 panic(); 597 } 598 599 ret = fdt_open_into(dt->blob, dt->blob, dt_sz); 600 if (ret < 0) { 601 EMSG("Invalid Device Tree at %#lx: error %d", phys_dt, ret); 602 panic(); 603 } 604 605 IMSG("Non-secure external DT found"); 606 } 607 608 void *get_external_dt(void) 609 { 610 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 611 return NULL; 612 613 assert(cpu_mmu_enabled()); 614 return external_dt.blob; 615 } 616 617 static TEE_Result release_external_dt(void) 618 { 619 int ret = 0; 620 paddr_t pa_dt = 0; 621 622 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 623 return TEE_SUCCESS; 624 625 if (!external_dt.blob) 626 return TEE_SUCCESS; 627 628 pa_dt = virt_to_phys(external_dt.blob); 629 /* 630 * Skip packing and un-mapping operations if the external DTB is mapped 631 * in a different memory area 632 */ 633 if (core_mmu_get_type_by_pa(pa_dt) != MEM_AREA_EXT_DT) 634 return TEE_SUCCESS; 635 636 ret = fdt_pack(external_dt.blob); 637 if (ret < 0) { 638 EMSG("Failed to pack Device Tree at 0x%" PRIxPA ": error %d", 639 virt_to_phys(external_dt.blob), ret); 640 panic(); 641 } 642 643 if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob, 644 CFG_DTB_MAX_SIZE)) 645 panic("Failed to remove temporary Device Tree mapping"); 646 647 /* External DTB no more reached, reset pointer to invalid */ 648 external_dt.blob = NULL; 649 650 return TEE_SUCCESS; 651 } 652 653 boot_final(release_external_dt); 654 655 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path, 656 const char *subnode) 657 { 658 int offs = 0; 659 660 offs = fdt_path_offset(dt->blob, path); 661 if (offs < 0) 662 return offs; 663 offs = add_dt_overlay_fragment(dt, offs); 664 if (offs < 0) 665 return offs; 666 return fdt_add_subnode(dt->blob, offs, subnode); 667 } 668 669 static void set_dt_val(void *data, uint32_t cell_size, uint64_t val) 670 { 671 if (cell_size == 1) { 672 fdt32_t v = cpu_to_fdt32((uint32_t)val); 673 674 memcpy(data, &v, sizeof(v)); 675 } else { 676 fdt64_t v = cpu_to_fdt64(val); 677 678 memcpy(data, &v, sizeof(v)); 679 } 680 } 681 682 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name, 683 paddr_t pa, size_t size) 684 { 685 int offs = 0; 686 int ret = 0; 687 int addr_size = -1; 688 int len_size = -1; 689 bool found = true; 690 char subnode_name[80] = { }; 691 692 offs = fdt_path_offset(dt->blob, "/reserved-memory"); 693 694 if (offs < 0) { 695 found = false; 696 offs = 0; 697 } 698 699 if (IS_ENABLED2(_CFG_USE_DTB_OVERLAY)) { 700 len_size = sizeof(paddr_t) / sizeof(uint32_t); 701 addr_size = sizeof(paddr_t) / sizeof(uint32_t); 702 } else { 703 len_size = fdt_size_cells(dt->blob, offs); 704 if (len_size < 0) 705 return len_size; 706 addr_size = fdt_address_cells(dt->blob, offs); 707 if (addr_size < 0) 708 return addr_size; 709 } 710 711 if (!found) { 712 offs = add_dt_path_subnode(dt, "/", "reserved-memory"); 713 if (offs < 0) 714 return offs; 715 ret = fdt_setprop_cell(dt->blob, offs, "#address-cells", 716 addr_size); 717 if (ret < 0) 718 return ret; 719 ret = fdt_setprop_cell(dt->blob, offs, "#size-cells", len_size); 720 if (ret < 0) 721 return ret; 722 ret = fdt_setprop(dt->blob, offs, "ranges", NULL, 0); 723 if (ret < 0) 724 return ret; 725 } 726 727 ret = snprintf(subnode_name, sizeof(subnode_name), 728 "%s@%" PRIxPA, name, pa); 729 if (ret < 0 || ret >= (int)sizeof(subnode_name)) 730 DMSG("truncated node \"%s@%" PRIxPA"\"", name, pa); 731 offs = fdt_add_subnode(dt->blob, offs, subnode_name); 732 if (offs >= 0) { 733 uint32_t data[FDT_MAX_NCELLS * 2] = { }; 734 735 set_dt_val(data, addr_size, pa); 736 set_dt_val(data + addr_size, len_size, size); 737 ret = fdt_setprop(dt->blob, offs, "reg", data, 738 sizeof(uint32_t) * (addr_size + len_size)); 739 if (ret < 0) 740 return ret; 741 ret = fdt_setprop(dt->blob, offs, "no-map", NULL, 0); 742 if (ret < 0) 743 return ret; 744 } else { 745 return offs; 746 } 747 return 0; 748 } 749 750 #if defined(CFG_CORE_FFA) 751 void init_manifest_dt(void *fdt) 752 { 753 manifest_dt = fdt; 754 } 755 756 void reinit_manifest_dt(void) 757 { 758 paddr_t pa = (unsigned long)manifest_dt; 759 void *fdt = NULL; 760 int ret = 0; 761 762 if (!pa) { 763 EMSG("No manifest DT found"); 764 return; 765 } 766 767 fdt = core_mmu_add_mapping(MEM_AREA_MANIFEST_DT, pa, CFG_DTB_MAX_SIZE); 768 if (!fdt) 769 panic("Failed to map manifest DT"); 770 771 manifest_dt = fdt; 772 773 ret = fdt_check_full(fdt, CFG_DTB_MAX_SIZE); 774 if (ret < 0) { 775 EMSG("Invalid manifest Device Tree at %#lx: error %d", pa, ret); 776 panic(); 777 } 778 779 IMSG("manifest DT found"); 780 } 781 782 void *get_manifest_dt(void) 783 { 784 return manifest_dt; 785 } 786 787 static TEE_Result release_manifest_dt(void) 788 { 789 if (!manifest_dt) 790 return TEE_SUCCESS; 791 792 if (core_mmu_remove_mapping(MEM_AREA_MANIFEST_DT, manifest_dt, 793 CFG_DTB_MAX_SIZE)) 794 panic("Failed to remove temporary manifest DT mapping"); 795 manifest_dt = NULL; 796 797 return TEE_SUCCESS; 798 } 799 800 boot_final(release_manifest_dt); 801 #else 802 void init_manifest_dt(void *fdt __unused) 803 { 804 } 805 806 void reinit_manifest_dt(void) 807 { 808 } 809 810 void *get_manifest_dt(void) 811 { 812 return NULL; 813 } 814 #endif /*CFG_CORE_FFA*/ 815