xref: /optee_os/core/kernel/dt.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
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