1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2a4f139d7SJerome Forissier /* 3a4f139d7SJerome Forissier * Copyright (c) 2016, Linaro Limited 4a4f139d7SJerome Forissier * All rights reserved. 5a4f139d7SJerome Forissier * 6a4f139d7SJerome Forissier * Redistribution and use in source and binary forms, with or without 7a4f139d7SJerome Forissier * modification, are permitted provided that the following conditions are met: 8a4f139d7SJerome Forissier * 9a4f139d7SJerome Forissier * 1. Redistributions of source code must retain the above copyright notice, 10a4f139d7SJerome Forissier * this list of conditions and the following disclaimer. 11a4f139d7SJerome Forissier * 12a4f139d7SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright notice, 13a4f139d7SJerome Forissier * this list of conditions and the following disclaimer in the documentation 14a4f139d7SJerome Forissier * and/or other materials provided with the distribution. 15a4f139d7SJerome Forissier * 16a4f139d7SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17a4f139d7SJerome Forissier * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18a4f139d7SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19a4f139d7SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20a4f139d7SJerome Forissier * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21a4f139d7SJerome Forissier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22a4f139d7SJerome Forissier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23a4f139d7SJerome Forissier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24a4f139d7SJerome Forissier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25a4f139d7SJerome Forissier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26a4f139d7SJerome Forissier * POSSIBILITY OF SUCH DAMAGE. 27a4f139d7SJerome Forissier */ 28a4f139d7SJerome Forissier 297ba16abbSJerome Forissier #include <assert.h> 30a4f139d7SJerome Forissier #include <kernel/dt.h> 31bce4951cSJens Wiklander #include <kernel/linker.h> 329fe4c797SJerome Forissier #include <libfdt.h> 337ba16abbSJerome Forissier #include <mm/core_memprot.h> 347ba16abbSJerome Forissier #include <mm/core_mmu.h> 35a4f139d7SJerome Forissier #include <string.h> 367ba16abbSJerome Forissier #include <trace.h> 37a4f139d7SJerome Forissier 38a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs) 39a4f139d7SJerome Forissier { 40a4f139d7SJerome Forissier const struct dt_device_match *dm; 41a4f139d7SJerome Forissier const struct dt_driver *drv; 42a4f139d7SJerome Forissier 43a4f139d7SJerome Forissier for_each_dt_driver(drv) 44a4f139d7SJerome Forissier for (dm = drv->match_table; dm; dm++) 45a4f139d7SJerome Forissier if (!fdt_node_check_compatible(fdt, offs, 46a4f139d7SJerome Forissier dm->compatible)) 47a4f139d7SJerome Forissier return drv; 48a4f139d7SJerome Forissier 49a4f139d7SJerome Forissier return NULL; 50a4f139d7SJerome Forissier } 51a4f139d7SJerome Forissier 52a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_start(void) 53a4f139d7SJerome Forissier { 54a4f139d7SJerome Forissier return &__rodata_dtdrv_start; 55a4f139d7SJerome Forissier } 56a4f139d7SJerome Forissier 57a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_end(void) 58a4f139d7SJerome Forissier { 59a4f139d7SJerome Forissier return &__rodata_dtdrv_end; 60a4f139d7SJerome Forissier } 619fe4c797SJerome Forissier 6250f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname) 6350f3b323SPeng Fan { 6450f3b323SPeng Fan const void *prop; 6550f3b323SPeng Fan 6650f3b323SPeng Fan prop = fdt_getprop(fdt, offs, propname, NULL); 6750f3b323SPeng Fan 6850f3b323SPeng Fan return prop; 6950f3b323SPeng Fan } 7050f3b323SPeng Fan 717ba16abbSJerome Forissier int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size) 727ba16abbSJerome Forissier { 737ba16abbSJerome Forissier enum teecore_memtypes mtype; 747ba16abbSJerome Forissier paddr_t pbase; 757ba16abbSJerome Forissier vaddr_t vbase; 767ba16abbSJerome Forissier ssize_t sz; 777ba16abbSJerome Forissier int st; 787ba16abbSJerome Forissier 797ba16abbSJerome Forissier assert(cpu_mmu_enabled()); 807ba16abbSJerome Forissier 817ba16abbSJerome Forissier st = _fdt_get_status(fdt, offs); 827ba16abbSJerome Forissier if (st == DT_STATUS_DISABLED) 837ba16abbSJerome Forissier return -1; 847ba16abbSJerome Forissier 857ba16abbSJerome Forissier pbase = _fdt_reg_base_address(fdt, offs); 867ba16abbSJerome Forissier if (pbase == (paddr_t)-1) 877ba16abbSJerome Forissier return -1; 887ba16abbSJerome Forissier sz = _fdt_reg_size(fdt, offs); 897ba16abbSJerome Forissier if (sz < 0) 907ba16abbSJerome Forissier return -1; 917ba16abbSJerome Forissier 927ba16abbSJerome Forissier if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC)) 937ba16abbSJerome Forissier mtype = MEM_AREA_IO_SEC; 947ba16abbSJerome Forissier else 957ba16abbSJerome Forissier mtype = MEM_AREA_IO_NSEC; 967ba16abbSJerome Forissier 977ba16abbSJerome Forissier /* Check if we have a mapping, create one if needed */ 987ba16abbSJerome Forissier if (!core_mmu_add_mapping(mtype, pbase, sz)) { 997ba16abbSJerome Forissier EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA, 10023b1daf4SPeng Fan (size_t)sz, pbase); 1017ba16abbSJerome Forissier return -1; 1027ba16abbSJerome Forissier } 1037ba16abbSJerome Forissier vbase = (vaddr_t)phys_to_virt(pbase, mtype); 1047ba16abbSJerome Forissier if (!vbase) { 1057ba16abbSJerome Forissier EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase); 1067ba16abbSJerome Forissier return -1; 1077ba16abbSJerome Forissier } 1087ba16abbSJerome Forissier 1097ba16abbSJerome Forissier *base = vbase; 1107ba16abbSJerome Forissier *size = sz; 1117ba16abbSJerome Forissier return 0; 1127ba16abbSJerome Forissier } 1137ba16abbSJerome Forissier 1149fe4c797SJerome Forissier /* Read a physical address (n=1 or 2 cells) */ 1159fe4c797SJerome Forissier static paddr_t _fdt_read_paddr(const uint32_t *cell, int n) 1169fe4c797SJerome Forissier { 1179fe4c797SJerome Forissier paddr_t addr; 1189fe4c797SJerome Forissier 1199fe4c797SJerome Forissier if (n < 1 || n > 2) 1209fe4c797SJerome Forissier goto bad; 1219fe4c797SJerome Forissier 1229fe4c797SJerome Forissier addr = fdt32_to_cpu(*cell); 1239fe4c797SJerome Forissier cell++; 1249fe4c797SJerome Forissier if (n == 2) { 1259fe4c797SJerome Forissier #ifdef ARM32 1269fe4c797SJerome Forissier if (addr) { 1279fe4c797SJerome Forissier /* High order 32 bits can't be nonzero */ 1289fe4c797SJerome Forissier goto bad; 1299fe4c797SJerome Forissier } 1309fe4c797SJerome Forissier addr = fdt32_to_cpu(*cell); 1319fe4c797SJerome Forissier #else 1329fe4c797SJerome Forissier addr = (addr << 32) | fdt32_to_cpu(*cell); 1339fe4c797SJerome Forissier #endif 1349fe4c797SJerome Forissier } 1359fe4c797SJerome Forissier 1369fe4c797SJerome Forissier if (!addr) 1379fe4c797SJerome Forissier goto bad; 1389fe4c797SJerome Forissier 1399fe4c797SJerome Forissier return addr; 1409fe4c797SJerome Forissier bad: 1419fe4c797SJerome Forissier return (paddr_t)-1; 1429fe4c797SJerome Forissier 1439fe4c797SJerome Forissier } 1449fe4c797SJerome Forissier 1459fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs) 1469fe4c797SJerome Forissier { 1479fe4c797SJerome Forissier const void *reg; 1489fe4c797SJerome Forissier int ncells; 1499fe4c797SJerome Forissier int len; 15034deb103SPeng Fan int parent; 15134deb103SPeng Fan 15234deb103SPeng Fan parent = fdt_parent_offset(fdt, offs); 15334deb103SPeng Fan if (parent < 0) 15434deb103SPeng Fan return (paddr_t)-1; 1559fe4c797SJerome Forissier 1569fe4c797SJerome Forissier reg = fdt_getprop(fdt, offs, "reg", &len); 1579fe4c797SJerome Forissier if (!reg) 1589fe4c797SJerome Forissier return (paddr_t)-1; 1599fe4c797SJerome Forissier 16034deb103SPeng Fan ncells = fdt_address_cells(fdt, parent); 1619fe4c797SJerome Forissier if (ncells < 0) 1629fe4c797SJerome Forissier return (paddr_t)-1; 1639fe4c797SJerome Forissier 1649fe4c797SJerome Forissier return _fdt_read_paddr(reg, ncells); 1659fe4c797SJerome Forissier } 1669fe4c797SJerome Forissier 1679fe4c797SJerome Forissier ssize_t _fdt_reg_size(const void *fdt, int offs) 1689fe4c797SJerome Forissier { 1699fe4c797SJerome Forissier const uint32_t *reg; 1709fe4c797SJerome Forissier uint32_t sz; 1719fe4c797SJerome Forissier int n; 1729fe4c797SJerome Forissier int len; 17334deb103SPeng Fan int parent; 17434deb103SPeng Fan 17534deb103SPeng Fan parent = fdt_parent_offset(fdt, offs); 17634deb103SPeng Fan if (parent < 0) 17734deb103SPeng Fan return (paddr_t)-1; 1789fe4c797SJerome Forissier 1799fe4c797SJerome Forissier reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len); 1809fe4c797SJerome Forissier if (!reg) 1819fe4c797SJerome Forissier return -1; 1829fe4c797SJerome Forissier 18334deb103SPeng Fan n = fdt_address_cells(fdt, parent); 1849fe4c797SJerome Forissier if (n < 1 || n > 2) 1859fe4c797SJerome Forissier return -1; 1869fe4c797SJerome Forissier 1879fe4c797SJerome Forissier reg += n; 1889fe4c797SJerome Forissier 18934deb103SPeng Fan n = fdt_size_cells(fdt, parent); 1909fe4c797SJerome Forissier if (n < 1 || n > 2) 1919fe4c797SJerome Forissier return -1; 1929fe4c797SJerome Forissier 1939fe4c797SJerome Forissier sz = fdt32_to_cpu(*reg); 1949fe4c797SJerome Forissier if (n == 2) { 1959fe4c797SJerome Forissier if (sz) 1969fe4c797SJerome Forissier return -1; 1979fe4c797SJerome Forissier reg++; 1989fe4c797SJerome Forissier sz = fdt32_to_cpu(*reg); 1999fe4c797SJerome Forissier } 2009fe4c797SJerome Forissier 2019fe4c797SJerome Forissier return sz; 2029fe4c797SJerome Forissier } 2039fe4c797SJerome Forissier 2049fe4c797SJerome Forissier static bool is_okay(const char *st, int len) 2059fe4c797SJerome Forissier { 2069fe4c797SJerome Forissier return !strncmp(st, "ok", len) || !strncmp(st, "okay", len); 2079fe4c797SJerome Forissier } 2089fe4c797SJerome Forissier 2099fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs) 2109fe4c797SJerome Forissier { 2119fe4c797SJerome Forissier const char *prop; 2129fe4c797SJerome Forissier int st = 0; 2139fe4c797SJerome Forissier int len; 2149fe4c797SJerome Forissier 2159fe4c797SJerome Forissier prop = fdt_getprop(fdt, offs, "status", &len); 2169fe4c797SJerome Forissier if (!prop || is_okay(prop, len)) { 2179fe4c797SJerome Forissier /* If status is not specified, it defaults to "okay" */ 2189fe4c797SJerome Forissier st |= DT_STATUS_OK_NSEC; 2199fe4c797SJerome Forissier } 2209fe4c797SJerome Forissier 2219fe4c797SJerome Forissier prop = fdt_getprop(fdt, offs, "secure-status", &len); 2229fe4c797SJerome Forissier if (!prop) { 2239fe4c797SJerome Forissier /* 2249fe4c797SJerome Forissier * When secure-status is not specified it defaults to the same 2259fe4c797SJerome Forissier * value as status 2269fe4c797SJerome Forissier */ 2279fe4c797SJerome Forissier if (st & DT_STATUS_OK_NSEC) 2289fe4c797SJerome Forissier st |= DT_STATUS_OK_SEC; 2299fe4c797SJerome Forissier } else { 2309fe4c797SJerome Forissier if (is_okay(prop, len)) 2319fe4c797SJerome Forissier st |= DT_STATUS_OK_SEC; 2329fe4c797SJerome Forissier } 2339fe4c797SJerome Forissier 2349fe4c797SJerome Forissier return st; 2359fe4c797SJerome Forissier } 236