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