1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <kernel/dt.h> 8 #include <kernel/linker.h> 9 #include <libfdt.h> 10 #include <mm/core_memprot.h> 11 #include <mm/core_mmu.h> 12 #include <string.h> 13 #include <trace.h> 14 15 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs) 16 { 17 const struct dt_device_match *dm; 18 const struct dt_driver *drv; 19 20 for_each_dt_driver(drv) 21 for (dm = drv->match_table; dm; dm++) 22 if (!fdt_node_check_compatible(fdt, offs, 23 dm->compatible)) 24 return drv; 25 26 return NULL; 27 } 28 29 const struct dt_driver *__dt_driver_start(void) 30 { 31 return &__rodata_dtdrv_start; 32 } 33 34 const struct dt_driver *__dt_driver_end(void) 35 { 36 return &__rodata_dtdrv_end; 37 } 38 39 bool dt_have_prop(const void *fdt, int offs, const char *propname) 40 { 41 const void *prop; 42 43 prop = fdt_getprop(fdt, offs, propname, NULL); 44 45 return prop; 46 } 47 48 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size) 49 { 50 enum teecore_memtypes mtype; 51 paddr_t pbase; 52 vaddr_t vbase; 53 ssize_t sz; 54 int st; 55 56 assert(cpu_mmu_enabled()); 57 58 st = _fdt_get_status(fdt, offs); 59 if (st == DT_STATUS_DISABLED) 60 return -1; 61 62 pbase = _fdt_reg_base_address(fdt, offs); 63 if (pbase == (paddr_t)-1) 64 return -1; 65 sz = _fdt_reg_size(fdt, offs); 66 if (sz < 0) 67 return -1; 68 69 if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC)) 70 mtype = MEM_AREA_IO_SEC; 71 else 72 mtype = MEM_AREA_IO_NSEC; 73 74 /* Check if we have a mapping, create one if needed */ 75 if (!core_mmu_add_mapping(mtype, pbase, sz)) { 76 EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA, 77 (size_t)sz, pbase); 78 return -1; 79 } 80 vbase = (vaddr_t)phys_to_virt(pbase, mtype); 81 if (!vbase) { 82 EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase); 83 return -1; 84 } 85 86 *base = vbase; 87 *size = sz; 88 return 0; 89 } 90 91 /* Read a physical address (n=1 or 2 cells) */ 92 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n) 93 { 94 paddr_t addr; 95 96 if (n < 1 || n > 2) 97 goto bad; 98 99 addr = fdt32_to_cpu(*cell); 100 cell++; 101 if (n == 2) { 102 #ifdef ARM32 103 if (addr) { 104 /* High order 32 bits can't be nonzero */ 105 goto bad; 106 } 107 addr = fdt32_to_cpu(*cell); 108 #else 109 addr = (addr << 32) | fdt32_to_cpu(*cell); 110 #endif 111 } 112 113 if (!addr) 114 goto bad; 115 116 return addr; 117 bad: 118 return (paddr_t)-1; 119 120 } 121 122 paddr_t _fdt_reg_base_address(const void *fdt, int offs) 123 { 124 const void *reg; 125 int ncells; 126 int len; 127 int parent; 128 129 parent = fdt_parent_offset(fdt, offs); 130 if (parent < 0) 131 return (paddr_t)-1; 132 133 reg = fdt_getprop(fdt, offs, "reg", &len); 134 if (!reg) 135 return (paddr_t)-1; 136 137 ncells = fdt_address_cells(fdt, parent); 138 if (ncells < 0) 139 return (paddr_t)-1; 140 141 return _fdt_read_paddr(reg, ncells); 142 } 143 144 ssize_t _fdt_reg_size(const void *fdt, int offs) 145 { 146 const uint32_t *reg; 147 uint32_t sz; 148 int n; 149 int len; 150 int parent; 151 152 parent = fdt_parent_offset(fdt, offs); 153 if (parent < 0) 154 return (paddr_t)-1; 155 156 reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len); 157 if (!reg) 158 return -1; 159 160 n = fdt_address_cells(fdt, parent); 161 if (n < 1 || n > 2) 162 return -1; 163 164 reg += n; 165 166 n = fdt_size_cells(fdt, parent); 167 if (n < 1 || n > 2) 168 return -1; 169 170 sz = fdt32_to_cpu(*reg); 171 if (n == 2) { 172 if (sz) 173 return -1; 174 reg++; 175 sz = fdt32_to_cpu(*reg); 176 } 177 178 return sz; 179 } 180 181 static bool is_okay(const char *st, int len) 182 { 183 return !strncmp(st, "ok", len) || !strncmp(st, "okay", len); 184 } 185 186 int _fdt_get_status(const void *fdt, int offs) 187 { 188 const char *prop; 189 int st = 0; 190 int len; 191 192 prop = fdt_getprop(fdt, offs, "status", &len); 193 if (!prop || is_okay(prop, len)) { 194 /* If status is not specified, it defaults to "okay" */ 195 st |= DT_STATUS_OK_NSEC; 196 } 197 198 prop = fdt_getprop(fdt, offs, "secure-status", &len); 199 if (!prop) { 200 /* 201 * When secure-status is not specified it defaults to the same 202 * value as status 203 */ 204 if (st & DT_STATUS_OK_NSEC) 205 st |= DT_STATUS_OK_SEC; 206 } else { 207 if (is_okay(prop, len)) 208 st |= DT_STATUS_OK_SEC; 209 } 210 211 return st; 212 } 213