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