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 if (!fdt) 457 fdt = get_manifest_dt(); 458 459 return fdt; 460 } 461 462 void *get_secure_dt(void) 463 { 464 void *fdt = get_embedded_dt(); 465 466 if (!fdt && IS_ENABLED(CFG_MAP_EXT_DT_SECURE)) 467 fdt = get_external_dt(); 468 469 if (!fdt) 470 fdt = get_manifest_dt(); 471 472 return fdt; 473 } 474 475 #if defined(CFG_EMBED_DTB) 476 void *get_embedded_dt(void) 477 { 478 static bool checked; 479 480 assert(cpu_mmu_enabled()); 481 482 if (!checked) { 483 IMSG("Embedded DTB found"); 484 485 if (fdt_check_header(embedded_secure_dtb)) 486 panic("Invalid embedded DTB"); 487 488 checked = true; 489 } 490 491 return embedded_secure_dtb; 492 } 493 #else 494 void *get_embedded_dt(void) 495 { 496 return NULL; 497 } 498 #endif /*CFG_EMBED_DTB*/ 499 500 #ifdef _CFG_USE_DTB_OVERLAY 501 static int add_dt_overlay_fragment(struct dt_descriptor *dt, int ioffs) 502 { 503 char frag[32] = { }; 504 int offs = 0; 505 int ret = 0; 506 507 ret = snprintf(frag, sizeof(frag), "fragment@%d", dt->frag_id); 508 if (ret < 0 || (size_t)ret >= sizeof(frag)) 509 return -1; 510 511 offs = fdt_add_subnode(dt->blob, ioffs, frag); 512 if (offs < 0) 513 return offs; 514 515 dt->frag_id += 1; 516 517 ret = fdt_setprop_string(dt->blob, offs, "target-path", "/"); 518 if (ret < 0) 519 return ret; 520 521 return fdt_add_subnode(dt->blob, offs, "__overlay__"); 522 } 523 524 static int init_dt_overlay(struct dt_descriptor *dt, int __maybe_unused dt_size) 525 { 526 int fragment = 0; 527 528 if (IS_ENABLED(CFG_EXTERNAL_DTB_OVERLAY)) { 529 if (!fdt_check_header(dt->blob)) { 530 fdt_for_each_subnode(fragment, dt->blob, 0) 531 dt->frag_id += 1; 532 return 0; 533 } 534 } 535 536 return fdt_create_empty_tree(dt->blob, dt_size); 537 } 538 #else 539 static int add_dt_overlay_fragment(struct dt_descriptor *dt __unused, int offs) 540 { 541 return offs; 542 } 543 544 static int init_dt_overlay(struct dt_descriptor *dt __unused, 545 int dt_size __unused) 546 { 547 return 0; 548 } 549 #endif /* _CFG_USE_DTB_OVERLAY */ 550 551 struct dt_descriptor *get_external_dt_desc(void) 552 { 553 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 554 return NULL; 555 556 return &external_dt; 557 } 558 559 void init_external_dt(unsigned long phys_dt, size_t dt_sz) 560 { 561 struct dt_descriptor *dt = &external_dt; 562 int ret = 0; 563 enum teecore_memtypes mtype = MEM_AREA_MAXTYPE; 564 565 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 566 return; 567 568 if (!phys_dt || !dt_sz) { 569 /* 570 * No need to panic as we're not using the DT in OP-TEE 571 * yet, we're only adding some nodes for normal world use. 572 * This makes the switch to using DT easier as we can boot 573 * a newer OP-TEE with older boot loaders. Once we start to 574 * initialize devices based on DT we'll likely panic 575 * instead of returning here. 576 */ 577 IMSG("No non-secure external DT"); 578 return; 579 } 580 581 mtype = core_mmu_get_type_by_pa(phys_dt); 582 if (mtype == MEM_AREA_MAXTYPE) { 583 /* Map the DTB if it is not yet mapped */ 584 dt->blob = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt, 585 dt_sz); 586 if (!dt->blob) 587 panic("Failed to map external DTB"); 588 } else { 589 /* Get the DTB address if already mapped in a memory area */ 590 dt->blob = phys_to_virt(phys_dt, mtype, dt_sz); 591 if (!dt->blob) { 592 EMSG("Failed to get a mapped external DTB for PA %#lx", 593 phys_dt); 594 panic(); 595 } 596 } 597 598 ret = init_dt_overlay(dt, dt_sz); 599 if (ret < 0) { 600 EMSG("Device Tree Overlay init fail @ %#lx: error %d", phys_dt, 601 ret); 602 panic(); 603 } 604 605 ret = fdt_open_into(dt->blob, dt->blob, dt_sz); 606 if (ret < 0) { 607 EMSG("Invalid Device Tree at %#lx: error %d", phys_dt, ret); 608 panic(); 609 } 610 611 IMSG("Non-secure external DT found"); 612 } 613 614 void *get_external_dt(void) 615 { 616 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 617 return NULL; 618 619 assert(cpu_mmu_enabled()); 620 return external_dt.blob; 621 } 622 623 static TEE_Result release_external_dt(void) 624 { 625 int ret = 0; 626 paddr_t pa_dt = 0; 627 628 if (!IS_ENABLED(CFG_EXTERNAL_DT)) 629 return TEE_SUCCESS; 630 631 if (!external_dt.blob) 632 return TEE_SUCCESS; 633 634 pa_dt = virt_to_phys(external_dt.blob); 635 /* 636 * Skip packing and un-mapping operations if the external DTB is mapped 637 * in a different memory area 638 */ 639 if (core_mmu_get_type_by_pa(pa_dt) != MEM_AREA_EXT_DT) 640 return TEE_SUCCESS; 641 642 ret = fdt_pack(external_dt.blob); 643 if (ret < 0) { 644 EMSG("Failed to pack Device Tree at 0x%" PRIxPA ": error %d", 645 virt_to_phys(external_dt.blob), ret); 646 panic(); 647 } 648 649 if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob, 650 CFG_DTB_MAX_SIZE)) 651 panic("Failed to remove temporary Device Tree mapping"); 652 653 /* External DTB no more reached, reset pointer to invalid */ 654 external_dt.blob = NULL; 655 656 return TEE_SUCCESS; 657 } 658 659 boot_final(release_external_dt); 660 661 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path, 662 const char *subnode) 663 { 664 int offs = 0; 665 666 offs = fdt_path_offset(dt->blob, path); 667 if (offs < 0) 668 return offs; 669 offs = add_dt_overlay_fragment(dt, offs); 670 if (offs < 0) 671 return offs; 672 return fdt_add_subnode(dt->blob, offs, subnode); 673 } 674 675 static void set_dt_val(void *data, uint32_t cell_size, uint64_t val) 676 { 677 if (cell_size == 1) { 678 fdt32_t v = cpu_to_fdt32((uint32_t)val); 679 680 memcpy(data, &v, sizeof(v)); 681 } else { 682 fdt64_t v = cpu_to_fdt64(val); 683 684 memcpy(data, &v, sizeof(v)); 685 } 686 } 687 688 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name, 689 paddr_t pa, size_t size) 690 { 691 int offs = 0; 692 int ret = 0; 693 int addr_size = -1; 694 int len_size = -1; 695 bool found = true; 696 char subnode_name[80] = { }; 697 698 offs = fdt_path_offset(dt->blob, "/reserved-memory"); 699 700 if (offs < 0) { 701 found = false; 702 offs = 0; 703 } 704 705 if (IS_ENABLED2(_CFG_USE_DTB_OVERLAY)) { 706 len_size = sizeof(paddr_t) / sizeof(uint32_t); 707 addr_size = sizeof(paddr_t) / sizeof(uint32_t); 708 } else { 709 len_size = fdt_size_cells(dt->blob, offs); 710 if (len_size < 0) 711 return len_size; 712 addr_size = fdt_address_cells(dt->blob, offs); 713 if (addr_size < 0) 714 return addr_size; 715 } 716 717 if (!found) { 718 offs = add_dt_path_subnode(dt, "/", "reserved-memory"); 719 if (offs < 0) 720 return offs; 721 ret = fdt_setprop_cell(dt->blob, offs, "#address-cells", 722 addr_size); 723 if (ret < 0) 724 return ret; 725 ret = fdt_setprop_cell(dt->blob, offs, "#size-cells", len_size); 726 if (ret < 0) 727 return ret; 728 ret = fdt_setprop(dt->blob, offs, "ranges", NULL, 0); 729 if (ret < 0) 730 return ret; 731 } 732 733 ret = snprintf(subnode_name, sizeof(subnode_name), 734 "%s@%" PRIxPA, name, pa); 735 if (ret < 0 || ret >= (int)sizeof(subnode_name)) 736 DMSG("truncated node \"%s@%" PRIxPA"\"", name, pa); 737 offs = fdt_add_subnode(dt->blob, offs, subnode_name); 738 if (offs >= 0) { 739 uint32_t data[FDT_MAX_NCELLS * 2] = { }; 740 741 set_dt_val(data, addr_size, pa); 742 set_dt_val(data + addr_size, len_size, size); 743 ret = fdt_setprop(dt->blob, offs, "reg", data, 744 sizeof(uint32_t) * (addr_size + len_size)); 745 if (ret < 0) 746 return ret; 747 ret = fdt_setprop(dt->blob, offs, "no-map", NULL, 0); 748 if (ret < 0) 749 return ret; 750 } else { 751 return offs; 752 } 753 return 0; 754 } 755 756 #if defined(CFG_CORE_FFA) 757 void init_manifest_dt(void *fdt) 758 { 759 manifest_dt = fdt; 760 } 761 762 void reinit_manifest_dt(void) 763 { 764 paddr_t pa = (unsigned long)manifest_dt; 765 void *fdt = NULL; 766 int ret = 0; 767 768 if (!pa) { 769 EMSG("No manifest DT found"); 770 return; 771 } 772 773 fdt = core_mmu_add_mapping(MEM_AREA_MANIFEST_DT, pa, CFG_DTB_MAX_SIZE); 774 if (!fdt) 775 panic("Failed to map manifest DT"); 776 777 manifest_dt = fdt; 778 779 ret = fdt_check_full(fdt, CFG_DTB_MAX_SIZE); 780 if (ret < 0) { 781 EMSG("Invalid manifest Device Tree at %#lx: error %d", pa, ret); 782 panic(); 783 } 784 785 IMSG("manifest DT found"); 786 } 787 788 void *get_manifest_dt(void) 789 { 790 return manifest_dt; 791 } 792 793 static TEE_Result release_manifest_dt(void) 794 { 795 if (!manifest_dt) 796 return TEE_SUCCESS; 797 798 if (core_mmu_remove_mapping(MEM_AREA_MANIFEST_DT, manifest_dt, 799 CFG_DTB_MAX_SIZE)) 800 panic("Failed to remove temporary manifest DT mapping"); 801 manifest_dt = NULL; 802 803 return TEE_SUCCESS; 804 } 805 806 boot_final(release_manifest_dt); 807 #else 808 void init_manifest_dt(void *fdt __unused) 809 { 810 } 811 812 void reinit_manifest_dt(void) 813 { 814 } 815 816 void *get_manifest_dt(void) 817 { 818 return NULL; 819 } 820 #endif /*CFG_CORE_FFA*/ 821