11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2a4f139d7SJerome Forissier /* 3a4f139d7SJerome Forissier * Copyright (c) 2016, Linaro Limited 4a4f139d7SJerome Forissier */ 5a4f139d7SJerome Forissier 67ba16abbSJerome Forissier #include <assert.h> 7e6027f48SAlvin Chang #include <config.h> 8e6027f48SAlvin Chang #include <initcall.h> 9a4f139d7SJerome Forissier #include <kernel/dt.h> 109e3c57c8SEtienne Carriere #include <kernel/dt_driver.h> 117acb3a47SLudovic Barre #include <kernel/interrupt.h> 129fe4c797SJerome Forissier #include <libfdt.h> 137ba16abbSJerome Forissier #include <mm/core_memprot.h> 147ba16abbSJerome Forissier #include <mm/core_mmu.h> 15e6027f48SAlvin Chang #include <stdio.h> 16a4f139d7SJerome Forissier #include <string.h> 177ba16abbSJerome Forissier #include <trace.h> 18a4f139d7SJerome Forissier 19e6027f48SAlvin Chang static struct dt_descriptor external_dt __nex_bss; 20e6027f48SAlvin Chang 214bc2c5f0SSungbae Yoo #if defined(CFG_CORE_FFA) 224bc2c5f0SSungbae Yoo static void *manifest_dt __nex_bss; 234bc2c5f0SSungbae Yoo #endif 244bc2c5f0SSungbae Yoo 25a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs) 26a4f139d7SJerome Forissier { 27a4f139d7SJerome Forissier const struct dt_device_match *dm; 28a4f139d7SJerome Forissier const struct dt_driver *drv; 29a4f139d7SJerome Forissier 30db783ff8SEtienne Carriere for_each_dt_driver(drv) { 31db783ff8SEtienne Carriere for (dm = drv->match_table; dm; dm++) { 32db783ff8SEtienne Carriere if (!dm->compatible) { 33db783ff8SEtienne Carriere break; 34db783ff8SEtienne Carriere } 35a4f139d7SJerome Forissier if (!fdt_node_check_compatible(fdt, offs, 36db783ff8SEtienne Carriere dm->compatible)) { 37a4f139d7SJerome Forissier return drv; 38db783ff8SEtienne Carriere } 39db783ff8SEtienne Carriere } 40db783ff8SEtienne Carriere } 41a4f139d7SJerome Forissier 42a4f139d7SJerome Forissier return NULL; 43a4f139d7SJerome Forissier } 44a4f139d7SJerome Forissier 4550f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname) 4650f3b323SPeng Fan { 4750f3b323SPeng Fan const void *prop; 4850f3b323SPeng Fan 4950f3b323SPeng Fan prop = fdt_getprop(fdt, offs, propname, NULL); 5050f3b323SPeng Fan 5150f3b323SPeng Fan return prop; 5250f3b323SPeng Fan } 5350f3b323SPeng Fan 5495cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node) 5595cdc5e0SCedric Neveux { 5695cdc5e0SCedric Neveux const char *prop = NULL; 5795cdc5e0SCedric Neveux int len = 0; 5895cdc5e0SCedric Neveux 5995cdc5e0SCedric Neveux prop = fdt_getprop(fdt, node, "status", &len); 6095cdc5e0SCedric Neveux if (!prop) { 6195cdc5e0SCedric Neveux if (fdt_setprop_string(fdt, node, "status", "disabled")) 6295cdc5e0SCedric Neveux return -1; 6395cdc5e0SCedric Neveux } else { 6495cdc5e0SCedric Neveux /* 6595cdc5e0SCedric Neveux * Status is there, modify it. 6695cdc5e0SCedric Neveux * Ask to set "disabled" value to the property. The value 6795cdc5e0SCedric Neveux * will be automatically truncated with "len" size by the 6895cdc5e0SCedric Neveux * fdt_setprop_inplace function. 6995cdc5e0SCedric Neveux * Setting a value different from "ok" or "okay" will disable 7095cdc5e0SCedric Neveux * the property. 7195cdc5e0SCedric Neveux * Setting a truncated value of "disabled" with the original 7295cdc5e0SCedric Neveux * property "len" is preferred to not increase the DT size and 7395cdc5e0SCedric Neveux * losing time in recalculating the overall DT offsets. 7495cdc5e0SCedric Neveux * If original length of the status property is larger than 7595cdc5e0SCedric Neveux * "disabled", the property will start with "disabled" and be 7695cdc5e0SCedric Neveux * completed with the rest of the original property. 7795cdc5e0SCedric Neveux */ 7895cdc5e0SCedric Neveux if (fdt_setprop_inplace(fdt, node, "status", "disabled", len)) 7995cdc5e0SCedric Neveux return -1; 8095cdc5e0SCedric Neveux } 8195cdc5e0SCedric Neveux 8295cdc5e0SCedric Neveux return 0; 8395cdc5e0SCedric Neveux } 8495cdc5e0SCedric Neveux 8595cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node) 8695cdc5e0SCedric Neveux { 8795cdc5e0SCedric Neveux if (dt_disable_status(fdt, node)) { 8895cdc5e0SCedric Neveux EMSG("Unable to disable Normal Status"); 8995cdc5e0SCedric Neveux return -1; 9095cdc5e0SCedric Neveux } 9195cdc5e0SCedric Neveux 9295cdc5e0SCedric Neveux if (fdt_setprop_string(fdt, node, "secure-status", "okay")) 9395cdc5e0SCedric Neveux return -1; 9495cdc5e0SCedric Neveux 9595cdc5e0SCedric Neveux return 0; 9695cdc5e0SCedric Neveux } 9795cdc5e0SCedric Neveux 98a5d5bbc8SVesa Jääskeläinen int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 99a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive mapping) 1007ba16abbSJerome Forissier { 1017ba16abbSJerome Forissier enum teecore_memtypes mtype; 1027ba16abbSJerome Forissier paddr_t pbase; 1037ba16abbSJerome Forissier vaddr_t vbase; 104df7cecc0SLionel Debieve size_t sz; 1057ba16abbSJerome Forissier int st; 1067ba16abbSJerome Forissier 1077ba16abbSJerome Forissier assert(cpu_mmu_enabled()); 1087ba16abbSJerome Forissier 109f354a5d8SGatien Chevallier st = fdt_get_status(fdt, offs); 1107ba16abbSJerome Forissier if (st == DT_STATUS_DISABLED) 1117ba16abbSJerome Forissier return -1; 1127ba16abbSJerome Forissier 113f354a5d8SGatien Chevallier pbase = fdt_reg_base_address(fdt, offs); 114c0cfb36cSEtienne Carriere if (pbase == DT_INFO_INVALID_REG) 1157ba16abbSJerome Forissier return -1; 116f354a5d8SGatien Chevallier sz = fdt_reg_size(fdt, offs); 117df7cecc0SLionel Debieve if (sz == DT_INFO_INVALID_REG_SIZE) 1187ba16abbSJerome Forissier return -1; 1197ba16abbSJerome Forissier 120a5d5bbc8SVesa Jääskeläinen switch (mapping) { 121a5d5bbc8SVesa Jääskeläinen case DT_MAP_AUTO: 1227ba16abbSJerome Forissier if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC)) 1237ba16abbSJerome Forissier mtype = MEM_AREA_IO_SEC; 1247ba16abbSJerome Forissier else 1257ba16abbSJerome Forissier mtype = MEM_AREA_IO_NSEC; 126a5d5bbc8SVesa Jääskeläinen break; 127a5d5bbc8SVesa Jääskeläinen case DT_MAP_SECURE: 128a5d5bbc8SVesa Jääskeläinen mtype = MEM_AREA_IO_SEC; 129a5d5bbc8SVesa Jääskeläinen break; 130a5d5bbc8SVesa Jääskeläinen case DT_MAP_NON_SECURE: 131a5d5bbc8SVesa Jääskeläinen mtype = MEM_AREA_IO_NSEC; 132a5d5bbc8SVesa Jääskeläinen break; 133a5d5bbc8SVesa Jääskeläinen default: 134a5d5bbc8SVesa Jääskeläinen panic("Invalid mapping specified"); 135a5d5bbc8SVesa Jääskeläinen break; 136a5d5bbc8SVesa Jääskeläinen } 1377ba16abbSJerome Forissier 1387ba16abbSJerome Forissier /* Check if we have a mapping, create one if needed */ 139bc9618c0SAnton Rybakov vbase = (vaddr_t)core_mmu_add_mapping(mtype, pbase, sz); 140bc9618c0SAnton Rybakov if (!vbase) { 1417ba16abbSJerome Forissier EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA, 14223b1daf4SPeng Fan (size_t)sz, pbase); 1437ba16abbSJerome Forissier return -1; 1447ba16abbSJerome Forissier } 1457ba16abbSJerome Forissier 1467ba16abbSJerome Forissier *base = vbase; 1477ba16abbSJerome Forissier *size = sz; 1487ba16abbSJerome Forissier return 0; 1497ba16abbSJerome Forissier } 1507ba16abbSJerome Forissier 1519fe4c797SJerome Forissier /* Read a physical address (n=1 or 2 cells) */ 152f354a5d8SGatien Chevallier static paddr_t fdt_read_paddr(const uint32_t *cell, int n) 1539fe4c797SJerome Forissier { 1549fe4c797SJerome Forissier paddr_t addr; 1559fe4c797SJerome Forissier 1569fe4c797SJerome Forissier if (n < 1 || n > 2) 1579fe4c797SJerome Forissier goto bad; 1589fe4c797SJerome Forissier 1599fe4c797SJerome Forissier addr = fdt32_to_cpu(*cell); 1609fe4c797SJerome Forissier cell++; 1619fe4c797SJerome Forissier if (n == 2) { 1629fe4c797SJerome Forissier #ifdef ARM32 1639fe4c797SJerome Forissier if (addr) { 1649fe4c797SJerome Forissier /* High order 32 bits can't be nonzero */ 1659fe4c797SJerome Forissier goto bad; 1669fe4c797SJerome Forissier } 1679fe4c797SJerome Forissier addr = fdt32_to_cpu(*cell); 1689fe4c797SJerome Forissier #else 1699fe4c797SJerome Forissier addr = (addr << 32) | fdt32_to_cpu(*cell); 1709fe4c797SJerome Forissier #endif 1719fe4c797SJerome Forissier } 1729fe4c797SJerome Forissier 1739fe4c797SJerome Forissier return addr; 1749fe4c797SJerome Forissier bad: 175c0cfb36cSEtienne Carriere return DT_INFO_INVALID_REG; 1769fe4c797SJerome Forissier 1779fe4c797SJerome Forissier } 1789fe4c797SJerome Forissier 179f354a5d8SGatien Chevallier paddr_t fdt_reg_base_address(const void *fdt, int offs) 1809fe4c797SJerome Forissier { 181*578bc4feSEtienne Carriere const void *reg = NULL; 182*578bc4feSEtienne Carriere int ncells = 0; 183*578bc4feSEtienne Carriere int len = 0; 184*578bc4feSEtienne Carriere int parent = 0; 1859fe4c797SJerome Forissier 1869fe4c797SJerome Forissier reg = fdt_getprop(fdt, offs, "reg", &len); 1879fe4c797SJerome Forissier if (!reg) 188c0cfb36cSEtienne Carriere return DT_INFO_INVALID_REG; 1899fe4c797SJerome Forissier 190*578bc4feSEtienne Carriere if (fdt_find_cached_parent_reg_cells(fdt, offs, &ncells, NULL)) { 191*578bc4feSEtienne Carriere parent = fdt_parent_offset(fdt, offs); 192*578bc4feSEtienne Carriere if (parent < 0) 193*578bc4feSEtienne Carriere return DT_INFO_INVALID_REG; 194*578bc4feSEtienne Carriere 19534deb103SPeng Fan ncells = fdt_address_cells(fdt, parent); 1969fe4c797SJerome Forissier if (ncells < 0) 197c0cfb36cSEtienne Carriere return DT_INFO_INVALID_REG; 198*578bc4feSEtienne Carriere } 1999fe4c797SJerome Forissier 200f354a5d8SGatien Chevallier return fdt_read_paddr(reg, ncells); 2019fe4c797SJerome Forissier } 2029fe4c797SJerome Forissier 203a2e8c036SGatien Chevallier static size_t fdt_read_size(const uint32_t *cell, int n) 204a2e8c036SGatien Chevallier { 205a2e8c036SGatien Chevallier uint32_t sz = 0; 206a2e8c036SGatien Chevallier 207a2e8c036SGatien Chevallier sz = fdt32_to_cpu(*cell); 208a2e8c036SGatien Chevallier if (n == 2) { 209a2e8c036SGatien Chevallier if (sz) 210a2e8c036SGatien Chevallier return DT_INFO_INVALID_REG_SIZE; 211a2e8c036SGatien Chevallier 212a2e8c036SGatien Chevallier cell++; 213a2e8c036SGatien Chevallier sz = fdt32_to_cpu(*cell); 214a2e8c036SGatien Chevallier } 215a2e8c036SGatien Chevallier 216a2e8c036SGatien Chevallier return sz; 217a2e8c036SGatien Chevallier } 218a2e8c036SGatien Chevallier 219f354a5d8SGatien Chevallier size_t fdt_reg_size(const void *fdt, int offs) 2209fe4c797SJerome Forissier { 221*578bc4feSEtienne Carriere const uint32_t *reg = NULL; 222*578bc4feSEtienne Carriere int n = 0; 223*578bc4feSEtienne Carriere int len = 0; 224*578bc4feSEtienne Carriere int parent = 0; 225*578bc4feSEtienne Carriere int addr_cells = 0; 2269fe4c797SJerome Forissier 2279fe4c797SJerome Forissier reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len); 2289fe4c797SJerome Forissier if (!reg) 229df7cecc0SLionel Debieve return DT_INFO_INVALID_REG_SIZE; 2309fe4c797SJerome Forissier 231*578bc4feSEtienne Carriere if (fdt_find_cached_parent_reg_cells(fdt, offs, &addr_cells, &n) == 0) { 232*578bc4feSEtienne Carriere reg += addr_cells; 233*578bc4feSEtienne Carriere } else { 234*578bc4feSEtienne Carriere parent = fdt_parent_offset(fdt, offs); 235*578bc4feSEtienne Carriere if (parent < 0) 236*578bc4feSEtienne Carriere return DT_INFO_INVALID_REG_SIZE; 237*578bc4feSEtienne Carriere 23834deb103SPeng Fan n = fdt_address_cells(fdt, parent); 2399fe4c797SJerome Forissier if (n < 1 || n > 2) 240df7cecc0SLionel Debieve return DT_INFO_INVALID_REG_SIZE; 2419fe4c797SJerome Forissier 2429fe4c797SJerome Forissier reg += n; 2439fe4c797SJerome Forissier 24434deb103SPeng Fan n = fdt_size_cells(fdt, parent); 245*578bc4feSEtienne Carriere } 246*578bc4feSEtienne Carriere 2479fe4c797SJerome Forissier if (n < 1 || n > 2) 248df7cecc0SLionel Debieve return DT_INFO_INVALID_REG_SIZE; 2499fe4c797SJerome Forissier 250a2e8c036SGatien Chevallier return fdt_read_size(reg, n); 2519fe4c797SJerome Forissier } 2529fe4c797SJerome Forissier 2539fe4c797SJerome Forissier static bool is_okay(const char *st, int len) 2549fe4c797SJerome Forissier { 2559fe4c797SJerome Forissier return !strncmp(st, "ok", len) || !strncmp(st, "okay", len); 2569fe4c797SJerome Forissier } 2579fe4c797SJerome Forissier 258f354a5d8SGatien Chevallier int fdt_get_status(const void *fdt, int offs) 2599fe4c797SJerome Forissier { 2609fe4c797SJerome Forissier const char *prop; 2619fe4c797SJerome Forissier int st = 0; 2629fe4c797SJerome Forissier int len; 2639fe4c797SJerome Forissier 2649fe4c797SJerome Forissier prop = fdt_getprop(fdt, offs, "status", &len); 2659fe4c797SJerome Forissier if (!prop || is_okay(prop, len)) { 2669fe4c797SJerome Forissier /* If status is not specified, it defaults to "okay" */ 2679fe4c797SJerome Forissier st |= DT_STATUS_OK_NSEC; 2689fe4c797SJerome Forissier } 2699fe4c797SJerome Forissier 2709fe4c797SJerome Forissier prop = fdt_getprop(fdt, offs, "secure-status", &len); 2719fe4c797SJerome Forissier if (!prop) { 2729fe4c797SJerome Forissier /* 2739fe4c797SJerome Forissier * When secure-status is not specified it defaults to the same 2749fe4c797SJerome Forissier * value as status 2759fe4c797SJerome Forissier */ 2769fe4c797SJerome Forissier if (st & DT_STATUS_OK_NSEC) 2779fe4c797SJerome Forissier st |= DT_STATUS_OK_SEC; 2789fe4c797SJerome Forissier } else { 2799fe4c797SJerome Forissier if (is_okay(prop, len)) 2809fe4c797SJerome Forissier st |= DT_STATUS_OK_SEC; 2819fe4c797SJerome Forissier } 2829fe4c797SJerome Forissier 2839fe4c797SJerome Forissier return st; 2849fe4c797SJerome Forissier } 285c0cfb36cSEtienne Carriere 286f354a5d8SGatien Chevallier void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs) 287c0cfb36cSEtienne Carriere { 288c0cfb36cSEtienne Carriere struct dt_node_info dinfo = { 289c0cfb36cSEtienne Carriere .reg = DT_INFO_INVALID_REG, 29006fd21ddSLionel Debieve .reg_size = DT_INFO_INVALID_REG_SIZE, 291c0cfb36cSEtienne Carriere .clock = DT_INFO_INVALID_CLOCK, 292c0cfb36cSEtienne Carriere .reset = DT_INFO_INVALID_RESET, 2937acb3a47SLudovic Barre .interrupt = DT_INFO_INVALID_INTERRUPT, 294c0cfb36cSEtienne Carriere }; 295*578bc4feSEtienne Carriere const fdt32_t *cuint = NULL; 296*578bc4feSEtienne Carriere int addr_cells = 0; 297*578bc4feSEtienne Carriere int size_cells = 0; 298c0cfb36cSEtienne Carriere 299*578bc4feSEtienne Carriere if (fdt_find_cached_parent_reg_cells(fdt, offs, &addr_cells, 300*578bc4feSEtienne Carriere &size_cells) == 0) { 301*578bc4feSEtienne Carriere int len = 0; 302*578bc4feSEtienne Carriere 303*578bc4feSEtienne Carriere cuint = fdt_getprop(fdt, offs, "reg", &len); 304*578bc4feSEtienne Carriere if (cuint && 305*578bc4feSEtienne Carriere (size_t)len == (addr_cells + size_cells) * sizeof(*cuint)) { 306*578bc4feSEtienne Carriere dinfo.reg = fdt_read_paddr(cuint, addr_cells); 307*578bc4feSEtienne Carriere dinfo.reg_size = fdt_read_size(cuint + addr_cells, 308*578bc4feSEtienne Carriere size_cells); 309*578bc4feSEtienne Carriere } 310*578bc4feSEtienne Carriere } else { 311f354a5d8SGatien Chevallier dinfo.reg = fdt_reg_base_address(fdt, offs); 312f354a5d8SGatien Chevallier dinfo.reg_size = fdt_reg_size(fdt, offs); 313*578bc4feSEtienne Carriere } 314c0cfb36cSEtienne Carriere 315c0cfb36cSEtienne Carriere cuint = fdt_getprop(fdt, offs, "clocks", NULL); 316c0cfb36cSEtienne Carriere if (cuint) { 317c0cfb36cSEtienne Carriere cuint++; 318c0cfb36cSEtienne Carriere dinfo.clock = (int)fdt32_to_cpu(*cuint); 319c0cfb36cSEtienne Carriere } 320c0cfb36cSEtienne Carriere 321c0cfb36cSEtienne Carriere cuint = fdt_getprop(fdt, offs, "resets", NULL); 322c0cfb36cSEtienne Carriere if (cuint) { 323c0cfb36cSEtienne Carriere cuint++; 324c0cfb36cSEtienne Carriere dinfo.reset = (int)fdt32_to_cpu(*cuint); 325c0cfb36cSEtienne Carriere } 326c0cfb36cSEtienne Carriere 327702fe5a7SClément Léger dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type, 328702fe5a7SClément Léger &dinfo.prio); 3297acb3a47SLudovic Barre 330f354a5d8SGatien Chevallier dinfo.status = fdt_get_status(fdt, offs); 331c0cfb36cSEtienne Carriere 332c0cfb36cSEtienne Carriere *info = dinfo; 333c0cfb36cSEtienne Carriere } 334876826f3SGabriel Fernandez 335f354a5d8SGatien Chevallier int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 336876826f3SGabriel Fernandez uint32_t *array, size_t count) 337876826f3SGabriel Fernandez { 338876826f3SGabriel Fernandez const fdt32_t *cuint = NULL; 339876826f3SGabriel Fernandez int len = 0; 340876826f3SGabriel Fernandez uint32_t i = 0; 341876826f3SGabriel Fernandez 342876826f3SGabriel Fernandez cuint = fdt_getprop(fdt, node, prop_name, &len); 343876826f3SGabriel Fernandez if (!cuint) 34473e27bfaSGatien Chevallier return len; 345876826f3SGabriel Fernandez 346876826f3SGabriel Fernandez if ((uint32_t)len != (count * sizeof(uint32_t))) 347876826f3SGabriel Fernandez return -FDT_ERR_BADLAYOUT; 348876826f3SGabriel Fernandez 349876826f3SGabriel Fernandez for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 350876826f3SGabriel Fernandez *array = fdt32_to_cpu(*cuint); 351876826f3SGabriel Fernandez array++; 352876826f3SGabriel Fernandez cuint++; 353876826f3SGabriel Fernandez } 354876826f3SGabriel Fernandez 355876826f3SGabriel Fernandez return 0; 356876826f3SGabriel Fernandez } 357876826f3SGabriel Fernandez 3587c3a6b7bSGatien Chevallier int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name, 3597c3a6b7bSGatien Chevallier int index, uint32_t *value) 3607c3a6b7bSGatien Chevallier { 3617c3a6b7bSGatien Chevallier const fdt32_t *cuint = NULL; 3627c3a6b7bSGatien Chevallier int len = 0; 3637c3a6b7bSGatien Chevallier 3647c3a6b7bSGatien Chevallier cuint = fdt_getprop(fdt, node, prop_name, &len); 3657c3a6b7bSGatien Chevallier if (!cuint) 3667c3a6b7bSGatien Chevallier return len; 3677c3a6b7bSGatien Chevallier 3687c3a6b7bSGatien Chevallier if ((uint32_t)len < (sizeof(uint32_t) * (index + 1))) 3697c3a6b7bSGatien Chevallier return -FDT_ERR_BADLAYOUT; 3707c3a6b7bSGatien Chevallier 3717c3a6b7bSGatien Chevallier *value = fdt32_to_cpu(cuint[index]); 3727c3a6b7bSGatien Chevallier 3737c3a6b7bSGatien Chevallier return 0; 3747c3a6b7bSGatien Chevallier } 3757c3a6b7bSGatien Chevallier 376f354a5d8SGatien Chevallier int fdt_read_uint32(const void *fdt, int node, const char *prop_name, 377876826f3SGabriel Fernandez uint32_t *value) 378876826f3SGabriel Fernandez { 379f354a5d8SGatien Chevallier return fdt_read_uint32_array(fdt, node, prop_name, value, 1); 380876826f3SGabriel Fernandez } 381876826f3SGabriel Fernandez 382f354a5d8SGatien Chevallier uint32_t fdt_read_uint32_default(const void *fdt, int node, 383876826f3SGabriel Fernandez const char *prop_name, uint32_t dflt_value) 384876826f3SGabriel Fernandez { 3857c3a6b7bSGatien Chevallier uint32_t ret = dflt_value; 386876826f3SGabriel Fernandez 3877c3a6b7bSGatien Chevallier fdt_read_uint32_index(fdt, node, prop_name, 0, &ret); 388876826f3SGabriel Fernandez 3897c3a6b7bSGatien Chevallier return ret; 390876826f3SGabriel Fernandez } 39107ced948SGatien Chevallier 39207ced948SGatien Chevallier int fdt_get_reg_props_by_index(const void *fdt, int node, int index, 39307ced948SGatien Chevallier paddr_t *base, size_t *size) 39407ced948SGatien Chevallier { 39507ced948SGatien Chevallier const fdt32_t *prop = NULL; 39607ced948SGatien Chevallier int parent = 0; 39707ced948SGatien Chevallier int len = 0; 39807ced948SGatien Chevallier int address_cells = 0; 39907ced948SGatien Chevallier int size_cells = 0; 40007ced948SGatien Chevallier int cell = 0; 40107ced948SGatien Chevallier 40207ced948SGatien Chevallier parent = fdt_parent_offset(fdt, node); 40307ced948SGatien Chevallier if (parent < 0) 40407ced948SGatien Chevallier return parent; 40507ced948SGatien Chevallier 40607ced948SGatien Chevallier address_cells = fdt_address_cells(fdt, parent); 40707ced948SGatien Chevallier if (address_cells < 0) 40807ced948SGatien Chevallier return address_cells; 40907ced948SGatien Chevallier 41007ced948SGatien Chevallier size_cells = fdt_size_cells(fdt, parent); 41107ced948SGatien Chevallier if (size_cells < 0) 41207ced948SGatien Chevallier return size_cells; 41307ced948SGatien Chevallier 41407ced948SGatien Chevallier cell = index * (address_cells + size_cells); 41507ced948SGatien Chevallier 41607ced948SGatien Chevallier prop = fdt_getprop(fdt, node, "reg", &len); 41707ced948SGatien Chevallier if (!prop) 41807ced948SGatien Chevallier return len; 41907ced948SGatien Chevallier 42007ced948SGatien Chevallier if (((cell + address_cells + size_cells) * (int)sizeof(uint32_t)) > len) 42107ced948SGatien Chevallier return -FDT_ERR_BADVALUE; 42207ced948SGatien Chevallier 42307ced948SGatien Chevallier if (base) { 42407ced948SGatien Chevallier *base = fdt_read_paddr(&prop[cell], address_cells); 42507ced948SGatien Chevallier if (*base == DT_INFO_INVALID_REG) 42607ced948SGatien Chevallier return -FDT_ERR_BADVALUE; 42707ced948SGatien Chevallier } 42807ced948SGatien Chevallier 42907ced948SGatien Chevallier if (size) { 43007ced948SGatien Chevallier *size = fdt_read_size(&prop[cell + address_cells], size_cells); 43107ced948SGatien Chevallier if (*size == DT_INFO_INVALID_REG_SIZE) 43207ced948SGatien Chevallier return -FDT_ERR_BADVALUE; 43307ced948SGatien Chevallier } 43407ced948SGatien Chevallier 43507ced948SGatien Chevallier return 0; 43607ced948SGatien Chevallier } 43707ced948SGatien Chevallier 43807ced948SGatien Chevallier int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name, 43907ced948SGatien Chevallier paddr_t *base, size_t *size) 44007ced948SGatien Chevallier { 44107ced948SGatien Chevallier int index = 0; 44207ced948SGatien Chevallier 44307ced948SGatien Chevallier index = fdt_stringlist_search(fdt, node, "reg-names", name); 44407ced948SGatien Chevallier if (index < 0) 44507ced948SGatien Chevallier return index; 44607ced948SGatien Chevallier 44707ced948SGatien Chevallier return fdt_get_reg_props_by_index(fdt, node, index, base, size); 44807ced948SGatien Chevallier } 4494e45454aSJens Wiklander 4504e45454aSJens Wiklander int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name, 4514e45454aSJens Wiklander uint64_t *num) 4524e45454aSJens Wiklander { 4534e45454aSJens Wiklander const void *prop = NULL; 4544e45454aSJens Wiklander int len = 0; 4554e45454aSJens Wiklander 4564e45454aSJens Wiklander prop = fdt_getprop(fdt, nodeoffset, name, &len); 4574e45454aSJens Wiklander if (!prop) 4584e45454aSJens Wiklander return len; 4594e45454aSJens Wiklander 4604e45454aSJens Wiklander switch (len) { 4614e45454aSJens Wiklander case sizeof(uint32_t): 4624e45454aSJens Wiklander *num = fdt32_ld(prop); 4634e45454aSJens Wiklander return 0; 4644e45454aSJens Wiklander case sizeof(uint64_t): 4654e45454aSJens Wiklander *num = fdt64_ld(prop); 4664e45454aSJens Wiklander return 0; 4674e45454aSJens Wiklander default: 4684e45454aSJens Wiklander return -FDT_ERR_BADVALUE; 4694e45454aSJens Wiklander } 4704e45454aSJens Wiklander } 471e6027f48SAlvin Chang 472e6027f48SAlvin Chang void *get_dt(void) 473e6027f48SAlvin Chang { 474e6027f48SAlvin Chang void *fdt = get_embedded_dt(); 475e6027f48SAlvin Chang 476e6027f48SAlvin Chang if (!fdt) 477e6027f48SAlvin Chang fdt = get_external_dt(); 478e6027f48SAlvin Chang 479c5e3e79fSSungbae Yoo if (!fdt) 480c5e3e79fSSungbae Yoo fdt = get_manifest_dt(); 481c5e3e79fSSungbae Yoo 482e6027f48SAlvin Chang return fdt; 483e6027f48SAlvin Chang } 484e6027f48SAlvin Chang 485e6027f48SAlvin Chang void *get_secure_dt(void) 486e6027f48SAlvin Chang { 487e6027f48SAlvin Chang void *fdt = get_embedded_dt(); 488e6027f48SAlvin Chang 489e6027f48SAlvin Chang if (!fdt && IS_ENABLED(CFG_MAP_EXT_DT_SECURE)) 490e6027f48SAlvin Chang fdt = get_external_dt(); 491e6027f48SAlvin Chang 492c5e3e79fSSungbae Yoo if (!fdt) 493c5e3e79fSSungbae Yoo fdt = get_manifest_dt(); 494c5e3e79fSSungbae Yoo 495e6027f48SAlvin Chang return fdt; 496e6027f48SAlvin Chang } 497e6027f48SAlvin Chang 498e6027f48SAlvin Chang #if defined(CFG_EMBED_DTB) 499*578bc4feSEtienne Carriere #ifdef CFG_DT_CACHED_NODE_INFO 500*578bc4feSEtienne Carriere /* 501*578bc4feSEtienne Carriere * struct cached_node - Cached information of a DT node 502*578bc4feSEtienne Carriere * 503*578bc4feSEtienne Carriere * @node_offset: Offset of the node in @cached_node_info_fdt 504*578bc4feSEtienne Carriere * @parent_offset: Offset of @node_offset parent node 505*578bc4feSEtienne Carriere * @address_cells: #address-cells property value of the parent node or 0 506*578bc4feSEtienne Carriere * @size_cells: #size-cells property value of the parent node or 0 507*578bc4feSEtienne Carriere * @phandle: Phandle associated to the node or 0 if none 508*578bc4feSEtienne Carriere */ 509*578bc4feSEtienne Carriere struct cached_node { 510*578bc4feSEtienne Carriere int node_offset; 511*578bc4feSEtienne Carriere int parent_offset; 512*578bc4feSEtienne Carriere int8_t address_cells; 513*578bc4feSEtienne Carriere int8_t size_cells; 514*578bc4feSEtienne Carriere uint32_t phandle; 515*578bc4feSEtienne Carriere }; 516*578bc4feSEtienne Carriere 517*578bc4feSEtienne Carriere /* 518*578bc4feSEtienne Carriere * struct dt_node_cache - Reference to cached information of DT nodes 519*578bc4feSEtienne Carriere * 520*578bc4feSEtienne Carriere * @array: Array of the cached node 521*578bc4feSEtienne Carriere * @count: Number of initialized cells in @array 522*578bc4feSEtienne Carriere * @alloced_count: Number of allocated cells in @array 523*578bc4feSEtienne Carriere * @fdt: Reference to the FDT for which node information are cached 524*578bc4feSEtienne Carriere */ 525*578bc4feSEtienne Carriere struct dt_node_cache { 526*578bc4feSEtienne Carriere struct cached_node *array; 527*578bc4feSEtienne Carriere size_t count; 528*578bc4feSEtienne Carriere size_t alloced_count; 529*578bc4feSEtienne Carriere const void *fdt; 530*578bc4feSEtienne Carriere }; 531*578bc4feSEtienne Carriere 532*578bc4feSEtienne Carriere static struct dt_node_cache *dt_node_cache; 533*578bc4feSEtienne Carriere 534*578bc4feSEtienne Carriere static bool fdt_node_info_are_cached(const void *fdt) 535*578bc4feSEtienne Carriere { 536*578bc4feSEtienne Carriere return dt_node_cache && dt_node_cache->fdt == fdt; 537*578bc4feSEtienne Carriere } 538*578bc4feSEtienne Carriere 539*578bc4feSEtienne Carriere static struct cached_node *find_cached_parent_node(const void *fdt, 540*578bc4feSEtienne Carriere int node_offset) 541*578bc4feSEtienne Carriere { 542*578bc4feSEtienne Carriere struct cached_node *cell = NULL; 543*578bc4feSEtienne Carriere size_t n = 0; 544*578bc4feSEtienne Carriere 545*578bc4feSEtienne Carriere if (!fdt_node_info_are_cached(fdt)) 546*578bc4feSEtienne Carriere return NULL; 547*578bc4feSEtienne Carriere 548*578bc4feSEtienne Carriere for (n = 0; n < dt_node_cache->count; n++) 549*578bc4feSEtienne Carriere if (dt_node_cache->array[n].node_offset == node_offset) 550*578bc4feSEtienne Carriere cell = dt_node_cache->array + n; 551*578bc4feSEtienne Carriere 552*578bc4feSEtienne Carriere return cell; 553*578bc4feSEtienne Carriere } 554*578bc4feSEtienne Carriere 555*578bc4feSEtienne Carriere int fdt_find_cached_parent_node(const void *fdt, int node_offset, 556*578bc4feSEtienne Carriere int *parent_offset) 557*578bc4feSEtienne Carriere { 558*578bc4feSEtienne Carriere struct cached_node *cell = NULL; 559*578bc4feSEtienne Carriere 560*578bc4feSEtienne Carriere cell = find_cached_parent_node(fdt, node_offset); 561*578bc4feSEtienne Carriere if (!cell) 562*578bc4feSEtienne Carriere return -FDT_ERR_NOTFOUND; 563*578bc4feSEtienne Carriere 564*578bc4feSEtienne Carriere *parent_offset = cell->parent_offset; 565*578bc4feSEtienne Carriere 566*578bc4feSEtienne Carriere return 0; 567*578bc4feSEtienne Carriere } 568*578bc4feSEtienne Carriere 569*578bc4feSEtienne Carriere int fdt_find_cached_parent_reg_cells(const void *fdt, int node_offset, 570*578bc4feSEtienne Carriere int *address_cells, int *size_cells) 571*578bc4feSEtienne Carriere { 572*578bc4feSEtienne Carriere struct cached_node *cell = NULL; 573*578bc4feSEtienne Carriere int rc = 0; 574*578bc4feSEtienne Carriere 575*578bc4feSEtienne Carriere cell = find_cached_parent_node(fdt, node_offset); 576*578bc4feSEtienne Carriere if (!cell) 577*578bc4feSEtienne Carriere return -FDT_ERR_NOTFOUND; 578*578bc4feSEtienne Carriere 579*578bc4feSEtienne Carriere if (address_cells) { 580*578bc4feSEtienne Carriere if (cell->address_cells >= 0) 581*578bc4feSEtienne Carriere *address_cells = cell->address_cells; 582*578bc4feSEtienne Carriere else 583*578bc4feSEtienne Carriere rc = -FDT_ERR_NOTFOUND; 584*578bc4feSEtienne Carriere } 585*578bc4feSEtienne Carriere 586*578bc4feSEtienne Carriere if (size_cells) { 587*578bc4feSEtienne Carriere if (cell->size_cells >= 0) 588*578bc4feSEtienne Carriere *size_cells = cell->size_cells; 589*578bc4feSEtienne Carriere else 590*578bc4feSEtienne Carriere rc = -FDT_ERR_NOTFOUND; 591*578bc4feSEtienne Carriere } 592*578bc4feSEtienne Carriere 593*578bc4feSEtienne Carriere return rc; 594*578bc4feSEtienne Carriere } 595*578bc4feSEtienne Carriere 596*578bc4feSEtienne Carriere int fdt_find_cached_node_phandle(const void *fdt, uint32_t phandle, 597*578bc4feSEtienne Carriere int *node_offset) 598*578bc4feSEtienne Carriere { 599*578bc4feSEtienne Carriere struct cached_node *cell = NULL; 600*578bc4feSEtienne Carriere size_t n = 0; 601*578bc4feSEtienne Carriere 602*578bc4feSEtienne Carriere if (!fdt_node_info_are_cached(fdt)) 603*578bc4feSEtienne Carriere return -FDT_ERR_NOTFOUND; 604*578bc4feSEtienne Carriere 605*578bc4feSEtienne Carriere for (n = 0; n < dt_node_cache->count; n++) 606*578bc4feSEtienne Carriere if (dt_node_cache->array[n].phandle == phandle) 607*578bc4feSEtienne Carriere cell = dt_node_cache->array + n; 608*578bc4feSEtienne Carriere 609*578bc4feSEtienne Carriere if (!cell) 610*578bc4feSEtienne Carriere return -FDT_ERR_NOTFOUND; 611*578bc4feSEtienne Carriere 612*578bc4feSEtienne Carriere *node_offset = cell->node_offset; 613*578bc4feSEtienne Carriere 614*578bc4feSEtienne Carriere return 0; 615*578bc4feSEtienne Carriere } 616*578bc4feSEtienne Carriere 617*578bc4feSEtienne Carriere static TEE_Result realloc_cached_node_array(void) 618*578bc4feSEtienne Carriere { 619*578bc4feSEtienne Carriere assert(dt_node_cache); 620*578bc4feSEtienne Carriere 621*578bc4feSEtienne Carriere if (dt_node_cache->count + 1 > dt_node_cache->alloced_count) { 622*578bc4feSEtienne Carriere size_t new_count = dt_node_cache->alloced_count * 2; 623*578bc4feSEtienne Carriere struct cached_node *new = NULL; 624*578bc4feSEtienne Carriere 625*578bc4feSEtienne Carriere if (!new_count) 626*578bc4feSEtienne Carriere new_count = 4; 627*578bc4feSEtienne Carriere 628*578bc4feSEtienne Carriere new = realloc(dt_node_cache->array, 629*578bc4feSEtienne Carriere sizeof(*dt_node_cache->array) * new_count); 630*578bc4feSEtienne Carriere if (!new) 631*578bc4feSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 632*578bc4feSEtienne Carriere 633*578bc4feSEtienne Carriere dt_node_cache->array = new; 634*578bc4feSEtienne Carriere dt_node_cache->alloced_count = new_count; 635*578bc4feSEtienne Carriere } 636*578bc4feSEtienne Carriere 637*578bc4feSEtienne Carriere return TEE_SUCCESS; 638*578bc4feSEtienne Carriere } 639*578bc4feSEtienne Carriere 640*578bc4feSEtienne Carriere static TEE_Result add_cached_node(int parent_offset, 641*578bc4feSEtienne Carriere int node_offset, int address_cells, 642*578bc4feSEtienne Carriere int size_cells) 643*578bc4feSEtienne Carriere { 644*578bc4feSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 645*578bc4feSEtienne Carriere 646*578bc4feSEtienne Carriere res = realloc_cached_node_array(); 647*578bc4feSEtienne Carriere if (res) 648*578bc4feSEtienne Carriere return res; 649*578bc4feSEtienne Carriere 650*578bc4feSEtienne Carriere dt_node_cache->array[dt_node_cache->count] = (struct cached_node){ 651*578bc4feSEtienne Carriere .node_offset = node_offset, 652*578bc4feSEtienne Carriere .parent_offset = parent_offset, 653*578bc4feSEtienne Carriere .address_cells = address_cells, 654*578bc4feSEtienne Carriere .size_cells = size_cells, 655*578bc4feSEtienne Carriere .phandle = fdt_get_phandle(dt_node_cache->fdt, node_offset), 656*578bc4feSEtienne Carriere }; 657*578bc4feSEtienne Carriere 658*578bc4feSEtienne Carriere dt_node_cache->count++; 659*578bc4feSEtienne Carriere 660*578bc4feSEtienne Carriere return TEE_SUCCESS; 661*578bc4feSEtienne Carriere } 662*578bc4feSEtienne Carriere 663*578bc4feSEtienne Carriere static TEE_Result add_cached_node_subtree(int node_offset) 664*578bc4feSEtienne Carriere { 665*578bc4feSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 666*578bc4feSEtienne Carriere const fdt32_t *cuint = NULL; 667*578bc4feSEtienne Carriere int subnode_offset = 0; 668*578bc4feSEtienne Carriere int8_t addr_cells = -1; 669*578bc4feSEtienne Carriere int8_t size_cells = -1; 670*578bc4feSEtienne Carriere 671*578bc4feSEtienne Carriere cuint = fdt_getprop(dt_node_cache->fdt, node_offset, "#address-cells", 672*578bc4feSEtienne Carriere NULL); 673*578bc4feSEtienne Carriere if (cuint) 674*578bc4feSEtienne Carriere addr_cells = (int)fdt32_to_cpu(*cuint); 675*578bc4feSEtienne Carriere 676*578bc4feSEtienne Carriere cuint = fdt_getprop(dt_node_cache->fdt, node_offset, "#size-cells", 677*578bc4feSEtienne Carriere NULL); 678*578bc4feSEtienne Carriere if (cuint) 679*578bc4feSEtienne Carriere size_cells = (int)fdt32_to_cpu(*cuint); 680*578bc4feSEtienne Carriere 681*578bc4feSEtienne Carriere fdt_for_each_subnode(subnode_offset, dt_node_cache->fdt, node_offset) { 682*578bc4feSEtienne Carriere res = add_cached_node(node_offset, subnode_offset, addr_cells, 683*578bc4feSEtienne Carriere size_cells); 684*578bc4feSEtienne Carriere if (res) 685*578bc4feSEtienne Carriere return res; 686*578bc4feSEtienne Carriere 687*578bc4feSEtienne Carriere res = add_cached_node_subtree(subnode_offset); 688*578bc4feSEtienne Carriere if (res) 689*578bc4feSEtienne Carriere return res; 690*578bc4feSEtienne Carriere } 691*578bc4feSEtienne Carriere 692*578bc4feSEtienne Carriere return TEE_SUCCESS; 693*578bc4feSEtienne Carriere } 694*578bc4feSEtienne Carriere 695*578bc4feSEtienne Carriere static TEE_Result release_node_cache_info(void) 696*578bc4feSEtienne Carriere { 697*578bc4feSEtienne Carriere if (dt_node_cache) { 698*578bc4feSEtienne Carriere free(dt_node_cache->array); 699*578bc4feSEtienne Carriere free(dt_node_cache); 700*578bc4feSEtienne Carriere dt_node_cache = NULL; 701*578bc4feSEtienne Carriere } 702*578bc4feSEtienne Carriere 703*578bc4feSEtienne Carriere return TEE_SUCCESS; 704*578bc4feSEtienne Carriere } 705*578bc4feSEtienne Carriere 706*578bc4feSEtienne Carriere release_init_resource(release_node_cache_info); 707*578bc4feSEtienne Carriere 708*578bc4feSEtienne Carriere static void init_node_cache_info(const void *fdt) 709*578bc4feSEtienne Carriere { 710*578bc4feSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 711*578bc4feSEtienne Carriere 712*578bc4feSEtienne Carriere assert(!dt_node_cache); 713*578bc4feSEtienne Carriere 714*578bc4feSEtienne Carriere dt_node_cache = calloc(1, sizeof(*dt_node_cache)); 715*578bc4feSEtienne Carriere if (dt_node_cache) { 716*578bc4feSEtienne Carriere dt_node_cache->fdt = fdt; 717*578bc4feSEtienne Carriere res = add_cached_node_subtree(0); 718*578bc4feSEtienne Carriere } else { 719*578bc4feSEtienne Carriere res = TEE_ERROR_OUT_OF_MEMORY; 720*578bc4feSEtienne Carriere } 721*578bc4feSEtienne Carriere 722*578bc4feSEtienne Carriere if (res) { 723*578bc4feSEtienne Carriere EMSG("Error %#"PRIx32", disable DT cached info", res); 724*578bc4feSEtienne Carriere release_node_cache_info(); 725*578bc4feSEtienne Carriere } 726*578bc4feSEtienne Carriere } 727*578bc4feSEtienne Carriere #else 728*578bc4feSEtienne Carriere static void init_node_cache_info(const void *fdt __unused) 729*578bc4feSEtienne Carriere { 730*578bc4feSEtienne Carriere } 731*578bc4feSEtienne Carriere #endif /* CFG_DT_CACHED_NODE_INFO */ 732*578bc4feSEtienne Carriere 733e6027f48SAlvin Chang void *get_embedded_dt(void) 734e6027f48SAlvin Chang { 735e6027f48SAlvin Chang static bool checked; 736e6027f48SAlvin Chang 737e6027f48SAlvin Chang assert(cpu_mmu_enabled()); 738e6027f48SAlvin Chang 739e6027f48SAlvin Chang if (!checked) { 740e6027f48SAlvin Chang IMSG("Embedded DTB found"); 741e6027f48SAlvin Chang 742e6027f48SAlvin Chang if (fdt_check_header(embedded_secure_dtb)) 743e6027f48SAlvin Chang panic("Invalid embedded DTB"); 744e6027f48SAlvin Chang 745e6027f48SAlvin Chang checked = true; 746*578bc4feSEtienne Carriere 747*578bc4feSEtienne Carriere init_node_cache_info(embedded_secure_dtb); 748e6027f48SAlvin Chang } 749e6027f48SAlvin Chang 750e6027f48SAlvin Chang return embedded_secure_dtb; 751e6027f48SAlvin Chang } 752e6027f48SAlvin Chang #else 753e6027f48SAlvin Chang void *get_embedded_dt(void) 754e6027f48SAlvin Chang { 755e6027f48SAlvin Chang return NULL; 756e6027f48SAlvin Chang } 757e6027f48SAlvin Chang #endif /*CFG_EMBED_DTB*/ 758e6027f48SAlvin Chang 759e6027f48SAlvin Chang #ifdef _CFG_USE_DTB_OVERLAY 760e6027f48SAlvin Chang static int add_dt_overlay_fragment(struct dt_descriptor *dt, int ioffs) 761e6027f48SAlvin Chang { 7620c49b6d6SAlvin Chang char frag[32] = { }; 7630c49b6d6SAlvin Chang int offs = 0; 7640c49b6d6SAlvin Chang int ret = 0; 765e6027f48SAlvin Chang 766a039ffc6SClement Faure ret = snprintf(frag, sizeof(frag), "fragment@%d", dt->frag_id); 767a039ffc6SClement Faure if (ret < 0 || (size_t)ret >= sizeof(frag)) 768a039ffc6SClement Faure return -1; 769a039ffc6SClement Faure 770e6027f48SAlvin Chang offs = fdt_add_subnode(dt->blob, ioffs, frag); 771e6027f48SAlvin Chang if (offs < 0) 772e6027f48SAlvin Chang return offs; 773e6027f48SAlvin Chang 774e6027f48SAlvin Chang dt->frag_id += 1; 775e6027f48SAlvin Chang 776e6027f48SAlvin Chang ret = fdt_setprop_string(dt->blob, offs, "target-path", "/"); 777e6027f48SAlvin Chang if (ret < 0) 7780c49b6d6SAlvin Chang return ret; 779e6027f48SAlvin Chang 780e6027f48SAlvin Chang return fdt_add_subnode(dt->blob, offs, "__overlay__"); 781e6027f48SAlvin Chang } 782e6027f48SAlvin Chang 783e6027f48SAlvin Chang static int init_dt_overlay(struct dt_descriptor *dt, int __maybe_unused dt_size) 784e6027f48SAlvin Chang { 7850c49b6d6SAlvin Chang int fragment = 0; 786e6027f48SAlvin Chang 787e6027f48SAlvin Chang if (IS_ENABLED(CFG_EXTERNAL_DTB_OVERLAY)) { 788e6027f48SAlvin Chang if (!fdt_check_header(dt->blob)) { 789e6027f48SAlvin Chang fdt_for_each_subnode(fragment, dt->blob, 0) 790e6027f48SAlvin Chang dt->frag_id += 1; 791e6027f48SAlvin Chang return 0; 792e6027f48SAlvin Chang } 793e6027f48SAlvin Chang } 794e6027f48SAlvin Chang 795e6027f48SAlvin Chang return fdt_create_empty_tree(dt->blob, dt_size); 796e6027f48SAlvin Chang } 797e6027f48SAlvin Chang #else 798e6027f48SAlvin Chang static int add_dt_overlay_fragment(struct dt_descriptor *dt __unused, int offs) 799e6027f48SAlvin Chang { 800e6027f48SAlvin Chang return offs; 801e6027f48SAlvin Chang } 802e6027f48SAlvin Chang 803e6027f48SAlvin Chang static int init_dt_overlay(struct dt_descriptor *dt __unused, 804e6027f48SAlvin Chang int dt_size __unused) 805e6027f48SAlvin Chang { 806e6027f48SAlvin Chang return 0; 807e6027f48SAlvin Chang } 808e6027f48SAlvin Chang #endif /* _CFG_USE_DTB_OVERLAY */ 809e6027f48SAlvin Chang 810e6027f48SAlvin Chang struct dt_descriptor *get_external_dt_desc(void) 811e6027f48SAlvin Chang { 812e6027f48SAlvin Chang if (!IS_ENABLED(CFG_EXTERNAL_DT)) 813e6027f48SAlvin Chang return NULL; 814e6027f48SAlvin Chang 815e6027f48SAlvin Chang return &external_dt; 816e6027f48SAlvin Chang } 817e6027f48SAlvin Chang 818dcff802bSRaymond Mao void init_external_dt(unsigned long phys_dt, size_t dt_sz) 819e6027f48SAlvin Chang { 820e6027f48SAlvin Chang struct dt_descriptor *dt = &external_dt; 8210c49b6d6SAlvin Chang int ret = 0; 82266763721SRaymond Mao enum teecore_memtypes mtype = MEM_AREA_MAXTYPE; 823e6027f48SAlvin Chang 824e6027f48SAlvin Chang if (!IS_ENABLED(CFG_EXTERNAL_DT)) 825e6027f48SAlvin Chang return; 826e6027f48SAlvin Chang 827dcff802bSRaymond Mao if (!phys_dt || !dt_sz) { 828e6027f48SAlvin Chang /* 829e6027f48SAlvin Chang * No need to panic as we're not using the DT in OP-TEE 830e6027f48SAlvin Chang * yet, we're only adding some nodes for normal world use. 831e6027f48SAlvin Chang * This makes the switch to using DT easier as we can boot 832e6027f48SAlvin Chang * a newer OP-TEE with older boot loaders. Once we start to 833e6027f48SAlvin Chang * initialize devices based on DT we'll likely panic 834e6027f48SAlvin Chang * instead of returning here. 835e6027f48SAlvin Chang */ 836e6027f48SAlvin Chang IMSG("No non-secure external DT"); 837e6027f48SAlvin Chang return; 838e6027f48SAlvin Chang } 839e6027f48SAlvin Chang 84066763721SRaymond Mao mtype = core_mmu_get_type_by_pa(phys_dt); 84166763721SRaymond Mao if (mtype == MEM_AREA_MAXTYPE) { 84266763721SRaymond Mao /* Map the DTB if it is not yet mapped */ 84366763721SRaymond Mao dt->blob = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt, 844dcff802bSRaymond Mao dt_sz); 84566763721SRaymond Mao if (!dt->blob) 846e6027f48SAlvin Chang panic("Failed to map external DTB"); 84766763721SRaymond Mao } else { 84866763721SRaymond Mao /* Get the DTB address if already mapped in a memory area */ 849dcff802bSRaymond Mao dt->blob = phys_to_virt(phys_dt, mtype, dt_sz); 85066763721SRaymond Mao if (!dt->blob) { 85166763721SRaymond Mao EMSG("Failed to get a mapped external DTB for PA %#lx", 85266763721SRaymond Mao phys_dt); 85366763721SRaymond Mao panic(); 85466763721SRaymond Mao } 85566763721SRaymond Mao } 856e6027f48SAlvin Chang 857dcff802bSRaymond Mao ret = init_dt_overlay(dt, dt_sz); 858e6027f48SAlvin Chang if (ret < 0) { 859e6027f48SAlvin Chang EMSG("Device Tree Overlay init fail @ %#lx: error %d", phys_dt, 860e6027f48SAlvin Chang ret); 861e6027f48SAlvin Chang panic(); 862e6027f48SAlvin Chang } 863e6027f48SAlvin Chang 864dcff802bSRaymond Mao ret = fdt_open_into(dt->blob, dt->blob, dt_sz); 865e6027f48SAlvin Chang if (ret < 0) { 866e6027f48SAlvin Chang EMSG("Invalid Device Tree at %#lx: error %d", phys_dt, ret); 867e6027f48SAlvin Chang panic(); 868e6027f48SAlvin Chang } 869e6027f48SAlvin Chang 870e6027f48SAlvin Chang IMSG("Non-secure external DT found"); 871e6027f48SAlvin Chang } 872e6027f48SAlvin Chang 873e6027f48SAlvin Chang void *get_external_dt(void) 874e6027f48SAlvin Chang { 875e6027f48SAlvin Chang if (!IS_ENABLED(CFG_EXTERNAL_DT)) 876e6027f48SAlvin Chang return NULL; 877e6027f48SAlvin Chang 878e6027f48SAlvin Chang assert(cpu_mmu_enabled()); 879e6027f48SAlvin Chang return external_dt.blob; 880e6027f48SAlvin Chang } 881e6027f48SAlvin Chang 882e6027f48SAlvin Chang static TEE_Result release_external_dt(void) 883e6027f48SAlvin Chang { 884e6027f48SAlvin Chang int ret = 0; 88566763721SRaymond Mao paddr_t pa_dt = 0; 886e6027f48SAlvin Chang 887e6027f48SAlvin Chang if (!IS_ENABLED(CFG_EXTERNAL_DT)) 888e6027f48SAlvin Chang return TEE_SUCCESS; 889e6027f48SAlvin Chang 890e6027f48SAlvin Chang if (!external_dt.blob) 891e6027f48SAlvin Chang return TEE_SUCCESS; 892e6027f48SAlvin Chang 89366763721SRaymond Mao pa_dt = virt_to_phys(external_dt.blob); 89466763721SRaymond Mao /* 89566763721SRaymond Mao * Skip packing and un-mapping operations if the external DTB is mapped 89666763721SRaymond Mao * in a different memory area 89766763721SRaymond Mao */ 89866763721SRaymond Mao if (core_mmu_get_type_by_pa(pa_dt) != MEM_AREA_EXT_DT) 89966763721SRaymond Mao return TEE_SUCCESS; 90066763721SRaymond Mao 901e6027f48SAlvin Chang ret = fdt_pack(external_dt.blob); 902e6027f48SAlvin Chang if (ret < 0) { 903e6027f48SAlvin Chang EMSG("Failed to pack Device Tree at 0x%" PRIxPA ": error %d", 904e6027f48SAlvin Chang virt_to_phys(external_dt.blob), ret); 905e6027f48SAlvin Chang panic(); 906e6027f48SAlvin Chang } 907e6027f48SAlvin Chang 908e6027f48SAlvin Chang if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob, 909e6027f48SAlvin Chang CFG_DTB_MAX_SIZE)) 910e6027f48SAlvin Chang panic("Failed to remove temporary Device Tree mapping"); 911e6027f48SAlvin Chang 912e6027f48SAlvin Chang /* External DTB no more reached, reset pointer to invalid */ 913e6027f48SAlvin Chang external_dt.blob = NULL; 914e6027f48SAlvin Chang 915e6027f48SAlvin Chang return TEE_SUCCESS; 916e6027f48SAlvin Chang } 917e6027f48SAlvin Chang 918e6027f48SAlvin Chang boot_final(release_external_dt); 919e6027f48SAlvin Chang 920e6027f48SAlvin Chang int add_dt_path_subnode(struct dt_descriptor *dt, const char *path, 921e6027f48SAlvin Chang const char *subnode) 922e6027f48SAlvin Chang { 9230c49b6d6SAlvin Chang int offs = 0; 924e6027f48SAlvin Chang 925e6027f48SAlvin Chang offs = fdt_path_offset(dt->blob, path); 926e6027f48SAlvin Chang if (offs < 0) 9270c49b6d6SAlvin Chang return offs; 928e6027f48SAlvin Chang offs = add_dt_overlay_fragment(dt, offs); 929e6027f48SAlvin Chang if (offs < 0) 930e6027f48SAlvin Chang return offs; 9310c49b6d6SAlvin Chang return fdt_add_subnode(dt->blob, offs, subnode); 932e6027f48SAlvin Chang } 933e6027f48SAlvin Chang 934e6027f48SAlvin Chang static void set_dt_val(void *data, uint32_t cell_size, uint64_t val) 935e6027f48SAlvin Chang { 936e6027f48SAlvin Chang if (cell_size == 1) { 937e6027f48SAlvin Chang fdt32_t v = cpu_to_fdt32((uint32_t)val); 938e6027f48SAlvin Chang 939e6027f48SAlvin Chang memcpy(data, &v, sizeof(v)); 940e6027f48SAlvin Chang } else { 941e6027f48SAlvin Chang fdt64_t v = cpu_to_fdt64(val); 942e6027f48SAlvin Chang 943e6027f48SAlvin Chang memcpy(data, &v, sizeof(v)); 944e6027f48SAlvin Chang } 945e6027f48SAlvin Chang } 946e6027f48SAlvin Chang 947e6027f48SAlvin Chang int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name, 948e6027f48SAlvin Chang paddr_t pa, size_t size) 949e6027f48SAlvin Chang { 950e6027f48SAlvin Chang int offs = 0; 951e6027f48SAlvin Chang int ret = 0; 952e6027f48SAlvin Chang int addr_size = -1; 953e6027f48SAlvin Chang int len_size = -1; 954e6027f48SAlvin Chang bool found = true; 9550c49b6d6SAlvin Chang char subnode_name[80] = { }; 956e6027f48SAlvin Chang 957e6027f48SAlvin Chang offs = fdt_path_offset(dt->blob, "/reserved-memory"); 958e6027f48SAlvin Chang 959e6027f48SAlvin Chang if (offs < 0) { 960e6027f48SAlvin Chang found = false; 961e6027f48SAlvin Chang offs = 0; 962e6027f48SAlvin Chang } 963e6027f48SAlvin Chang 964e6027f48SAlvin Chang if (IS_ENABLED2(_CFG_USE_DTB_OVERLAY)) { 965e6027f48SAlvin Chang len_size = sizeof(paddr_t) / sizeof(uint32_t); 966e6027f48SAlvin Chang addr_size = sizeof(paddr_t) / sizeof(uint32_t); 967e6027f48SAlvin Chang } else { 968e6027f48SAlvin Chang len_size = fdt_size_cells(dt->blob, offs); 969e6027f48SAlvin Chang if (len_size < 0) 9700c49b6d6SAlvin Chang return len_size; 971e6027f48SAlvin Chang addr_size = fdt_address_cells(dt->blob, offs); 972e6027f48SAlvin Chang if (addr_size < 0) 9730c49b6d6SAlvin Chang return addr_size; 974e6027f48SAlvin Chang } 975e6027f48SAlvin Chang 976e6027f48SAlvin Chang if (!found) { 977e6027f48SAlvin Chang offs = add_dt_path_subnode(dt, "/", "reserved-memory"); 978e6027f48SAlvin Chang if (offs < 0) 9790c49b6d6SAlvin Chang return offs; 980e6027f48SAlvin Chang ret = fdt_setprop_cell(dt->blob, offs, "#address-cells", 981e6027f48SAlvin Chang addr_size); 982e6027f48SAlvin Chang if (ret < 0) 9830c49b6d6SAlvin Chang return ret; 984e6027f48SAlvin Chang ret = fdt_setprop_cell(dt->blob, offs, "#size-cells", len_size); 985e6027f48SAlvin Chang if (ret < 0) 9860c49b6d6SAlvin Chang return ret; 987e6027f48SAlvin Chang ret = fdt_setprop(dt->blob, offs, "ranges", NULL, 0); 988e6027f48SAlvin Chang if (ret < 0) 9890c49b6d6SAlvin Chang return ret; 990e6027f48SAlvin Chang } 991e6027f48SAlvin Chang 992e6027f48SAlvin Chang ret = snprintf(subnode_name, sizeof(subnode_name), 993e6027f48SAlvin Chang "%s@%" PRIxPA, name, pa); 994e6027f48SAlvin Chang if (ret < 0 || ret >= (int)sizeof(subnode_name)) 995e6027f48SAlvin Chang DMSG("truncated node \"%s@%" PRIxPA"\"", name, pa); 996e6027f48SAlvin Chang offs = fdt_add_subnode(dt->blob, offs, subnode_name); 997e6027f48SAlvin Chang if (offs >= 0) { 9980c49b6d6SAlvin Chang uint32_t data[FDT_MAX_NCELLS * 2] = { }; 999e6027f48SAlvin Chang 1000e6027f48SAlvin Chang set_dt_val(data, addr_size, pa); 1001e6027f48SAlvin Chang set_dt_val(data + addr_size, len_size, size); 1002e6027f48SAlvin Chang ret = fdt_setprop(dt->blob, offs, "reg", data, 1003e6027f48SAlvin Chang sizeof(uint32_t) * (addr_size + len_size)); 1004e6027f48SAlvin Chang if (ret < 0) 10050c49b6d6SAlvin Chang return ret; 1006e6027f48SAlvin Chang ret = fdt_setprop(dt->blob, offs, "no-map", NULL, 0); 1007e6027f48SAlvin Chang if (ret < 0) 10080c49b6d6SAlvin Chang return ret; 1009e6027f48SAlvin Chang } else { 10100c49b6d6SAlvin Chang return offs; 1011e6027f48SAlvin Chang } 1012e6027f48SAlvin Chang return 0; 1013e6027f48SAlvin Chang } 10144bc2c5f0SSungbae Yoo 10154bc2c5f0SSungbae Yoo #if defined(CFG_CORE_FFA) 10164bc2c5f0SSungbae Yoo void init_manifest_dt(void *fdt) 10174bc2c5f0SSungbae Yoo { 10184bc2c5f0SSungbae Yoo manifest_dt = fdt; 10194bc2c5f0SSungbae Yoo } 10204bc2c5f0SSungbae Yoo 10214bc2c5f0SSungbae Yoo void reinit_manifest_dt(void) 10224bc2c5f0SSungbae Yoo { 10234bc2c5f0SSungbae Yoo paddr_t pa = (unsigned long)manifest_dt; 10244bc2c5f0SSungbae Yoo void *fdt = NULL; 10254bc2c5f0SSungbae Yoo int ret = 0; 10264bc2c5f0SSungbae Yoo 10274bc2c5f0SSungbae Yoo if (!pa) { 10284bc2c5f0SSungbae Yoo EMSG("No manifest DT found"); 10294bc2c5f0SSungbae Yoo return; 10304bc2c5f0SSungbae Yoo } 10314bc2c5f0SSungbae Yoo 10324bc2c5f0SSungbae Yoo fdt = core_mmu_add_mapping(MEM_AREA_MANIFEST_DT, pa, CFG_DTB_MAX_SIZE); 10334bc2c5f0SSungbae Yoo if (!fdt) 10344bc2c5f0SSungbae Yoo panic("Failed to map manifest DT"); 10354bc2c5f0SSungbae Yoo 10364bc2c5f0SSungbae Yoo manifest_dt = fdt; 10374bc2c5f0SSungbae Yoo 10384bc2c5f0SSungbae Yoo ret = fdt_check_full(fdt, CFG_DTB_MAX_SIZE); 10394bc2c5f0SSungbae Yoo if (ret < 0) { 10404bc2c5f0SSungbae Yoo EMSG("Invalid manifest Device Tree at %#lx: error %d", pa, ret); 10414bc2c5f0SSungbae Yoo panic(); 10424bc2c5f0SSungbae Yoo } 10434bc2c5f0SSungbae Yoo 10444bc2c5f0SSungbae Yoo IMSG("manifest DT found"); 10454bc2c5f0SSungbae Yoo } 10464bc2c5f0SSungbae Yoo 10474bc2c5f0SSungbae Yoo void *get_manifest_dt(void) 10484bc2c5f0SSungbae Yoo { 10494bc2c5f0SSungbae Yoo return manifest_dt; 10504bc2c5f0SSungbae Yoo } 10514bc2c5f0SSungbae Yoo 10524bc2c5f0SSungbae Yoo static TEE_Result release_manifest_dt(void) 10534bc2c5f0SSungbae Yoo { 10544bc2c5f0SSungbae Yoo if (!manifest_dt) 10554bc2c5f0SSungbae Yoo return TEE_SUCCESS; 10564bc2c5f0SSungbae Yoo 10574bc2c5f0SSungbae Yoo if (core_mmu_remove_mapping(MEM_AREA_MANIFEST_DT, manifest_dt, 10584bc2c5f0SSungbae Yoo CFG_DTB_MAX_SIZE)) 10594bc2c5f0SSungbae Yoo panic("Failed to remove temporary manifest DT mapping"); 10604bc2c5f0SSungbae Yoo manifest_dt = NULL; 10614bc2c5f0SSungbae Yoo 10624bc2c5f0SSungbae Yoo return TEE_SUCCESS; 10634bc2c5f0SSungbae Yoo } 10644bc2c5f0SSungbae Yoo 10654bc2c5f0SSungbae Yoo boot_final(release_manifest_dt); 10664bc2c5f0SSungbae Yoo #else 10674bc2c5f0SSungbae Yoo void init_manifest_dt(void *fdt __unused) 10684bc2c5f0SSungbae Yoo { 10694bc2c5f0SSungbae Yoo } 10704bc2c5f0SSungbae Yoo 10714bc2c5f0SSungbae Yoo void reinit_manifest_dt(void) 10724bc2c5f0SSungbae Yoo { 10734bc2c5f0SSungbae Yoo } 10744bc2c5f0SSungbae Yoo 10754bc2c5f0SSungbae Yoo void *get_manifest_dt(void) 10764bc2c5f0SSungbae Yoo { 10774bc2c5f0SSungbae Yoo return NULL; 10784bc2c5f0SSungbae Yoo } 10794bc2c5f0SSungbae Yoo #endif /*CFG_CORE_FFA*/ 1080