xref: /optee_os/core/kernel/dt.c (revision c5e3e79f42978270a63506f99ad514c16eb34b5a)
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 {
1819fe4c797SJerome Forissier 	const void *reg;
1829fe4c797SJerome Forissier 	int ncells;
1839fe4c797SJerome Forissier 	int len;
18434deb103SPeng Fan 	int parent;
18534deb103SPeng Fan 
18634deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
18734deb103SPeng Fan 	if (parent < 0)
188c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1899fe4c797SJerome Forissier 
1909fe4c797SJerome Forissier 	reg = fdt_getprop(fdt, offs, "reg", &len);
1919fe4c797SJerome Forissier 	if (!reg)
192c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1939fe4c797SJerome Forissier 
19434deb103SPeng Fan 	ncells = fdt_address_cells(fdt, parent);
1959fe4c797SJerome Forissier 	if (ncells < 0)
196c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1979fe4c797SJerome Forissier 
198f354a5d8SGatien Chevallier 	return fdt_read_paddr(reg, ncells);
1999fe4c797SJerome Forissier }
2009fe4c797SJerome Forissier 
201a2e8c036SGatien Chevallier static size_t fdt_read_size(const uint32_t *cell, int n)
202a2e8c036SGatien Chevallier {
203a2e8c036SGatien Chevallier 	uint32_t sz = 0;
204a2e8c036SGatien Chevallier 
205a2e8c036SGatien Chevallier 	sz = fdt32_to_cpu(*cell);
206a2e8c036SGatien Chevallier 	if (n == 2) {
207a2e8c036SGatien Chevallier 		if (sz)
208a2e8c036SGatien Chevallier 			return DT_INFO_INVALID_REG_SIZE;
209a2e8c036SGatien Chevallier 
210a2e8c036SGatien Chevallier 		cell++;
211a2e8c036SGatien Chevallier 		sz = fdt32_to_cpu(*cell);
212a2e8c036SGatien Chevallier 	}
213a2e8c036SGatien Chevallier 
214a2e8c036SGatien Chevallier 	return sz;
215a2e8c036SGatien Chevallier }
216a2e8c036SGatien Chevallier 
217f354a5d8SGatien Chevallier size_t fdt_reg_size(const void *fdt, int offs)
2189fe4c797SJerome Forissier {
2199fe4c797SJerome Forissier 	const uint32_t *reg;
2209fe4c797SJerome Forissier 	int n;
2219fe4c797SJerome Forissier 	int len;
22234deb103SPeng Fan 	int parent;
22334deb103SPeng Fan 
22434deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
22534deb103SPeng Fan 	if (parent < 0)
2261527e616SMarek Vasut 		return DT_INFO_INVALID_REG_SIZE;
2279fe4c797SJerome Forissier 
2289fe4c797SJerome Forissier 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
2299fe4c797SJerome Forissier 	if (!reg)
230df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2319fe4c797SJerome Forissier 
23234deb103SPeng Fan 	n = fdt_address_cells(fdt, parent);
2339fe4c797SJerome Forissier 	if (n < 1 || n > 2)
234df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2359fe4c797SJerome Forissier 
2369fe4c797SJerome Forissier 	reg += n;
2379fe4c797SJerome Forissier 
23834deb103SPeng Fan 	n = fdt_size_cells(fdt, parent);
2399fe4c797SJerome Forissier 	if (n < 1 || n > 2)
240df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2419fe4c797SJerome Forissier 
242a2e8c036SGatien Chevallier 	return fdt_read_size(reg, n);
2439fe4c797SJerome Forissier }
2449fe4c797SJerome Forissier 
2459fe4c797SJerome Forissier static bool is_okay(const char *st, int len)
2469fe4c797SJerome Forissier {
2479fe4c797SJerome Forissier 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
2489fe4c797SJerome Forissier }
2499fe4c797SJerome Forissier 
250f354a5d8SGatien Chevallier int fdt_get_status(const void *fdt, int offs)
2519fe4c797SJerome Forissier {
2529fe4c797SJerome Forissier 	const char *prop;
2539fe4c797SJerome Forissier 	int st = 0;
2549fe4c797SJerome Forissier 	int len;
2559fe4c797SJerome Forissier 
2569fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "status", &len);
2579fe4c797SJerome Forissier 	if (!prop || is_okay(prop, len)) {
2589fe4c797SJerome Forissier 		/* If status is not specified, it defaults to "okay" */
2599fe4c797SJerome Forissier 		st |= DT_STATUS_OK_NSEC;
2609fe4c797SJerome Forissier 	}
2619fe4c797SJerome Forissier 
2629fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
2639fe4c797SJerome Forissier 	if (!prop) {
2649fe4c797SJerome Forissier 		/*
2659fe4c797SJerome Forissier 		 * When secure-status is not specified it defaults to the same
2669fe4c797SJerome Forissier 		 * value as status
2679fe4c797SJerome Forissier 		 */
2689fe4c797SJerome Forissier 		if (st & DT_STATUS_OK_NSEC)
2699fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2709fe4c797SJerome Forissier 	} else {
2719fe4c797SJerome Forissier 		if (is_okay(prop, len))
2729fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2739fe4c797SJerome Forissier 	}
2749fe4c797SJerome Forissier 
2759fe4c797SJerome Forissier 	return st;
2769fe4c797SJerome Forissier }
277c0cfb36cSEtienne Carriere 
278f354a5d8SGatien Chevallier void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs)
279c0cfb36cSEtienne Carriere {
280c0cfb36cSEtienne Carriere 	struct dt_node_info dinfo = {
281c0cfb36cSEtienne Carriere 		.reg = DT_INFO_INVALID_REG,
28206fd21ddSLionel Debieve 		.reg_size = DT_INFO_INVALID_REG_SIZE,
283c0cfb36cSEtienne Carriere 		.clock = DT_INFO_INVALID_CLOCK,
284c0cfb36cSEtienne Carriere 		.reset = DT_INFO_INVALID_RESET,
2857acb3a47SLudovic Barre 		.interrupt = DT_INFO_INVALID_INTERRUPT,
286c0cfb36cSEtienne Carriere 	};
287c0cfb36cSEtienne Carriere 	const fdt32_t *cuint;
288c0cfb36cSEtienne Carriere 
289f354a5d8SGatien Chevallier 	dinfo.reg = fdt_reg_base_address(fdt, offs);
290f354a5d8SGatien Chevallier 	dinfo.reg_size = fdt_reg_size(fdt, offs);
291c0cfb36cSEtienne Carriere 
292c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "clocks", NULL);
293c0cfb36cSEtienne Carriere 	if (cuint) {
294c0cfb36cSEtienne Carriere 		cuint++;
295c0cfb36cSEtienne Carriere 		dinfo.clock = (int)fdt32_to_cpu(*cuint);
296c0cfb36cSEtienne Carriere 	}
297c0cfb36cSEtienne Carriere 
298c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "resets", NULL);
299c0cfb36cSEtienne Carriere 	if (cuint) {
300c0cfb36cSEtienne Carriere 		cuint++;
301c0cfb36cSEtienne Carriere 		dinfo.reset = (int)fdt32_to_cpu(*cuint);
302c0cfb36cSEtienne Carriere 	}
303c0cfb36cSEtienne Carriere 
304702fe5a7SClément Léger 	dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type,
305702fe5a7SClément Léger 					       &dinfo.prio);
3067acb3a47SLudovic Barre 
307f354a5d8SGatien Chevallier 	dinfo.status = fdt_get_status(fdt, offs);
308c0cfb36cSEtienne Carriere 
309c0cfb36cSEtienne Carriere 	*info = dinfo;
310c0cfb36cSEtienne Carriere }
311876826f3SGabriel Fernandez 
312f354a5d8SGatien Chevallier int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
313876826f3SGabriel Fernandez 			  uint32_t *array, size_t count)
314876826f3SGabriel Fernandez {
315876826f3SGabriel Fernandez 	const fdt32_t *cuint = NULL;
316876826f3SGabriel Fernandez 	int len = 0;
317876826f3SGabriel Fernandez 	uint32_t i = 0;
318876826f3SGabriel Fernandez 
319876826f3SGabriel Fernandez 	cuint = fdt_getprop(fdt, node, prop_name, &len);
320876826f3SGabriel Fernandez 	if (!cuint)
32173e27bfaSGatien Chevallier 		return len;
322876826f3SGabriel Fernandez 
323876826f3SGabriel Fernandez 	if ((uint32_t)len != (count * sizeof(uint32_t)))
324876826f3SGabriel Fernandez 		return -FDT_ERR_BADLAYOUT;
325876826f3SGabriel Fernandez 
326876826f3SGabriel Fernandez 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
327876826f3SGabriel Fernandez 		*array = fdt32_to_cpu(*cuint);
328876826f3SGabriel Fernandez 		array++;
329876826f3SGabriel Fernandez 		cuint++;
330876826f3SGabriel Fernandez 	}
331876826f3SGabriel Fernandez 
332876826f3SGabriel Fernandez 	return 0;
333876826f3SGabriel Fernandez }
334876826f3SGabriel Fernandez 
3357c3a6b7bSGatien Chevallier int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
3367c3a6b7bSGatien Chevallier 			  int index, uint32_t *value)
3377c3a6b7bSGatien Chevallier {
3387c3a6b7bSGatien Chevallier 	const fdt32_t *cuint = NULL;
3397c3a6b7bSGatien Chevallier 	int len = 0;
3407c3a6b7bSGatien Chevallier 
3417c3a6b7bSGatien Chevallier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
3427c3a6b7bSGatien Chevallier 	if (!cuint)
3437c3a6b7bSGatien Chevallier 		return len;
3447c3a6b7bSGatien Chevallier 
3457c3a6b7bSGatien Chevallier 	if ((uint32_t)len < (sizeof(uint32_t) * (index + 1)))
3467c3a6b7bSGatien Chevallier 		return -FDT_ERR_BADLAYOUT;
3477c3a6b7bSGatien Chevallier 
3487c3a6b7bSGatien Chevallier 	*value = fdt32_to_cpu(cuint[index]);
3497c3a6b7bSGatien Chevallier 
3507c3a6b7bSGatien Chevallier 	return 0;
3517c3a6b7bSGatien Chevallier }
3527c3a6b7bSGatien Chevallier 
353f354a5d8SGatien Chevallier int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
354876826f3SGabriel Fernandez 		    uint32_t *value)
355876826f3SGabriel Fernandez {
356f354a5d8SGatien Chevallier 	return fdt_read_uint32_array(fdt, node, prop_name, value, 1);
357876826f3SGabriel Fernandez }
358876826f3SGabriel Fernandez 
359f354a5d8SGatien Chevallier uint32_t fdt_read_uint32_default(const void *fdt, int node,
360876826f3SGabriel Fernandez 				 const char *prop_name, uint32_t dflt_value)
361876826f3SGabriel Fernandez {
3627c3a6b7bSGatien Chevallier 	uint32_t ret = dflt_value;
363876826f3SGabriel Fernandez 
3647c3a6b7bSGatien Chevallier 	fdt_read_uint32_index(fdt, node, prop_name, 0, &ret);
365876826f3SGabriel Fernandez 
3667c3a6b7bSGatien Chevallier 	return ret;
367876826f3SGabriel Fernandez }
36807ced948SGatien Chevallier 
36907ced948SGatien Chevallier int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
37007ced948SGatien Chevallier 			       paddr_t *base, size_t *size)
37107ced948SGatien Chevallier {
37207ced948SGatien Chevallier 	const fdt32_t *prop = NULL;
37307ced948SGatien Chevallier 	int parent = 0;
37407ced948SGatien Chevallier 	int len = 0;
37507ced948SGatien Chevallier 	int address_cells = 0;
37607ced948SGatien Chevallier 	int size_cells = 0;
37707ced948SGatien Chevallier 	int cell = 0;
37807ced948SGatien Chevallier 
37907ced948SGatien Chevallier 	parent = fdt_parent_offset(fdt, node);
38007ced948SGatien Chevallier 	if (parent < 0)
38107ced948SGatien Chevallier 		return parent;
38207ced948SGatien Chevallier 
38307ced948SGatien Chevallier 	address_cells = fdt_address_cells(fdt, parent);
38407ced948SGatien Chevallier 	if (address_cells < 0)
38507ced948SGatien Chevallier 		return address_cells;
38607ced948SGatien Chevallier 
38707ced948SGatien Chevallier 	size_cells = fdt_size_cells(fdt, parent);
38807ced948SGatien Chevallier 	if (size_cells < 0)
38907ced948SGatien Chevallier 		return size_cells;
39007ced948SGatien Chevallier 
39107ced948SGatien Chevallier 	cell = index * (address_cells + size_cells);
39207ced948SGatien Chevallier 
39307ced948SGatien Chevallier 	prop = fdt_getprop(fdt, node, "reg", &len);
39407ced948SGatien Chevallier 	if (!prop)
39507ced948SGatien Chevallier 		return len;
39607ced948SGatien Chevallier 
39707ced948SGatien Chevallier 	if (((cell + address_cells + size_cells) * (int)sizeof(uint32_t)) > len)
39807ced948SGatien Chevallier 		return -FDT_ERR_BADVALUE;
39907ced948SGatien Chevallier 
40007ced948SGatien Chevallier 	if (base) {
40107ced948SGatien Chevallier 		*base = fdt_read_paddr(&prop[cell], address_cells);
40207ced948SGatien Chevallier 		if (*base == DT_INFO_INVALID_REG)
40307ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
40407ced948SGatien Chevallier 	}
40507ced948SGatien Chevallier 
40607ced948SGatien Chevallier 	if (size) {
40707ced948SGatien Chevallier 		*size = fdt_read_size(&prop[cell + address_cells], size_cells);
40807ced948SGatien Chevallier 		if (*size == DT_INFO_INVALID_REG_SIZE)
40907ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
41007ced948SGatien Chevallier 	}
41107ced948SGatien Chevallier 
41207ced948SGatien Chevallier 	return 0;
41307ced948SGatien Chevallier }
41407ced948SGatien Chevallier 
41507ced948SGatien Chevallier int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
41607ced948SGatien Chevallier 			      paddr_t *base, size_t *size)
41707ced948SGatien Chevallier {
41807ced948SGatien Chevallier 	int index = 0;
41907ced948SGatien Chevallier 
42007ced948SGatien Chevallier 	index = fdt_stringlist_search(fdt, node, "reg-names", name);
42107ced948SGatien Chevallier 	if (index < 0)
42207ced948SGatien Chevallier 		return index;
42307ced948SGatien Chevallier 
42407ced948SGatien Chevallier 	return fdt_get_reg_props_by_index(fdt, node, index, base, size);
42507ced948SGatien Chevallier }
4264e45454aSJens Wiklander 
4274e45454aSJens Wiklander int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name,
4284e45454aSJens Wiklander 			 uint64_t *num)
4294e45454aSJens Wiklander {
4304e45454aSJens Wiklander 	const void *prop = NULL;
4314e45454aSJens Wiklander 	int len = 0;
4324e45454aSJens Wiklander 
4334e45454aSJens Wiklander 	prop = fdt_getprop(fdt, nodeoffset, name, &len);
4344e45454aSJens Wiklander 	if (!prop)
4354e45454aSJens Wiklander 		return len;
4364e45454aSJens Wiklander 
4374e45454aSJens Wiklander 	switch (len) {
4384e45454aSJens Wiklander 	case sizeof(uint32_t):
4394e45454aSJens Wiklander 		*num = fdt32_ld(prop);
4404e45454aSJens Wiklander 		return 0;
4414e45454aSJens Wiklander 	case sizeof(uint64_t):
4424e45454aSJens Wiklander 		*num = fdt64_ld(prop);
4434e45454aSJens Wiklander 		return 0;
4444e45454aSJens Wiklander 	default:
4454e45454aSJens Wiklander 		return -FDT_ERR_BADVALUE;
4464e45454aSJens Wiklander 	}
4474e45454aSJens Wiklander }
448e6027f48SAlvin Chang 
449e6027f48SAlvin Chang void *get_dt(void)
450e6027f48SAlvin Chang {
451e6027f48SAlvin Chang 	void *fdt = get_embedded_dt();
452e6027f48SAlvin Chang 
453e6027f48SAlvin Chang 	if (!fdt)
454e6027f48SAlvin Chang 		fdt = get_external_dt();
455e6027f48SAlvin Chang 
456*c5e3e79fSSungbae Yoo 	if (!fdt)
457*c5e3e79fSSungbae Yoo 		fdt = get_manifest_dt();
458*c5e3e79fSSungbae Yoo 
459e6027f48SAlvin Chang 	return fdt;
460e6027f48SAlvin Chang }
461e6027f48SAlvin Chang 
462e6027f48SAlvin Chang void *get_secure_dt(void)
463e6027f48SAlvin Chang {
464e6027f48SAlvin Chang 	void *fdt = get_embedded_dt();
465e6027f48SAlvin Chang 
466e6027f48SAlvin Chang 	if (!fdt && IS_ENABLED(CFG_MAP_EXT_DT_SECURE))
467e6027f48SAlvin Chang 		fdt = get_external_dt();
468e6027f48SAlvin Chang 
469*c5e3e79fSSungbae Yoo 	if (!fdt)
470*c5e3e79fSSungbae Yoo 		fdt = get_manifest_dt();
471*c5e3e79fSSungbae Yoo 
472e6027f48SAlvin Chang 	return fdt;
473e6027f48SAlvin Chang }
474e6027f48SAlvin Chang 
475e6027f48SAlvin Chang #if defined(CFG_EMBED_DTB)
476e6027f48SAlvin Chang void *get_embedded_dt(void)
477e6027f48SAlvin Chang {
478e6027f48SAlvin Chang 	static bool checked;
479e6027f48SAlvin Chang 
480e6027f48SAlvin Chang 	assert(cpu_mmu_enabled());
481e6027f48SAlvin Chang 
482e6027f48SAlvin Chang 	if (!checked) {
483e6027f48SAlvin Chang 		IMSG("Embedded DTB found");
484e6027f48SAlvin Chang 
485e6027f48SAlvin Chang 		if (fdt_check_header(embedded_secure_dtb))
486e6027f48SAlvin Chang 			panic("Invalid embedded DTB");
487e6027f48SAlvin Chang 
488e6027f48SAlvin Chang 		checked = true;
489e6027f48SAlvin Chang 	}
490e6027f48SAlvin Chang 
491e6027f48SAlvin Chang 	return embedded_secure_dtb;
492e6027f48SAlvin Chang }
493e6027f48SAlvin Chang #else
494e6027f48SAlvin Chang void *get_embedded_dt(void)
495e6027f48SAlvin Chang {
496e6027f48SAlvin Chang 	return NULL;
497e6027f48SAlvin Chang }
498e6027f48SAlvin Chang #endif /*CFG_EMBED_DTB*/
499e6027f48SAlvin Chang 
500e6027f48SAlvin Chang #ifdef _CFG_USE_DTB_OVERLAY
501e6027f48SAlvin Chang static int add_dt_overlay_fragment(struct dt_descriptor *dt, int ioffs)
502e6027f48SAlvin Chang {
5030c49b6d6SAlvin Chang 	char frag[32] = { };
5040c49b6d6SAlvin Chang 	int offs = 0;
5050c49b6d6SAlvin Chang 	int ret = 0;
506e6027f48SAlvin Chang 
507a039ffc6SClement Faure 	ret = snprintf(frag, sizeof(frag), "fragment@%d", dt->frag_id);
508a039ffc6SClement Faure 	if (ret < 0 || (size_t)ret >= sizeof(frag))
509a039ffc6SClement Faure 		return -1;
510a039ffc6SClement Faure 
511e6027f48SAlvin Chang 	offs = fdt_add_subnode(dt->blob, ioffs, frag);
512e6027f48SAlvin Chang 	if (offs < 0)
513e6027f48SAlvin Chang 		return offs;
514e6027f48SAlvin Chang 
515e6027f48SAlvin Chang 	dt->frag_id += 1;
516e6027f48SAlvin Chang 
517e6027f48SAlvin Chang 	ret = fdt_setprop_string(dt->blob, offs, "target-path", "/");
518e6027f48SAlvin Chang 	if (ret < 0)
5190c49b6d6SAlvin Chang 		return ret;
520e6027f48SAlvin Chang 
521e6027f48SAlvin Chang 	return fdt_add_subnode(dt->blob, offs, "__overlay__");
522e6027f48SAlvin Chang }
523e6027f48SAlvin Chang 
524e6027f48SAlvin Chang static int init_dt_overlay(struct dt_descriptor *dt, int __maybe_unused dt_size)
525e6027f48SAlvin Chang {
5260c49b6d6SAlvin Chang 	int fragment = 0;
527e6027f48SAlvin Chang 
528e6027f48SAlvin Chang 	if (IS_ENABLED(CFG_EXTERNAL_DTB_OVERLAY)) {
529e6027f48SAlvin Chang 		if (!fdt_check_header(dt->blob)) {
530e6027f48SAlvin Chang 			fdt_for_each_subnode(fragment, dt->blob, 0)
531e6027f48SAlvin Chang 				dt->frag_id += 1;
532e6027f48SAlvin Chang 			return 0;
533e6027f48SAlvin Chang 		}
534e6027f48SAlvin Chang 	}
535e6027f48SAlvin Chang 
536e6027f48SAlvin Chang 	return fdt_create_empty_tree(dt->blob, dt_size);
537e6027f48SAlvin Chang }
538e6027f48SAlvin Chang #else
539e6027f48SAlvin Chang static int add_dt_overlay_fragment(struct dt_descriptor *dt __unused, int offs)
540e6027f48SAlvin Chang {
541e6027f48SAlvin Chang 	return offs;
542e6027f48SAlvin Chang }
543e6027f48SAlvin Chang 
544e6027f48SAlvin Chang static int init_dt_overlay(struct dt_descriptor *dt __unused,
545e6027f48SAlvin Chang 			   int dt_size __unused)
546e6027f48SAlvin Chang {
547e6027f48SAlvin Chang 	return 0;
548e6027f48SAlvin Chang }
549e6027f48SAlvin Chang #endif /* _CFG_USE_DTB_OVERLAY */
550e6027f48SAlvin Chang 
551e6027f48SAlvin Chang struct dt_descriptor *get_external_dt_desc(void)
552e6027f48SAlvin Chang {
553e6027f48SAlvin Chang 	if (!IS_ENABLED(CFG_EXTERNAL_DT))
554e6027f48SAlvin Chang 		return NULL;
555e6027f48SAlvin Chang 
556e6027f48SAlvin Chang 	return &external_dt;
557e6027f48SAlvin Chang }
558e6027f48SAlvin Chang 
559dcff802bSRaymond Mao void init_external_dt(unsigned long phys_dt, size_t dt_sz)
560e6027f48SAlvin Chang {
561e6027f48SAlvin Chang 	struct dt_descriptor *dt = &external_dt;
5620c49b6d6SAlvin Chang 	int ret = 0;
56366763721SRaymond Mao 	enum teecore_memtypes mtype = MEM_AREA_MAXTYPE;
564e6027f48SAlvin Chang 
565e6027f48SAlvin Chang 	if (!IS_ENABLED(CFG_EXTERNAL_DT))
566e6027f48SAlvin Chang 		return;
567e6027f48SAlvin Chang 
568dcff802bSRaymond Mao 	if (!phys_dt || !dt_sz) {
569e6027f48SAlvin Chang 		/*
570e6027f48SAlvin Chang 		 * No need to panic as we're not using the DT in OP-TEE
571e6027f48SAlvin Chang 		 * yet, we're only adding some nodes for normal world use.
572e6027f48SAlvin Chang 		 * This makes the switch to using DT easier as we can boot
573e6027f48SAlvin Chang 		 * a newer OP-TEE with older boot loaders. Once we start to
574e6027f48SAlvin Chang 		 * initialize devices based on DT we'll likely panic
575e6027f48SAlvin Chang 		 * instead of returning here.
576e6027f48SAlvin Chang 		 */
577e6027f48SAlvin Chang 		IMSG("No non-secure external DT");
578e6027f48SAlvin Chang 		return;
579e6027f48SAlvin Chang 	}
580e6027f48SAlvin Chang 
58166763721SRaymond Mao 	mtype = core_mmu_get_type_by_pa(phys_dt);
58266763721SRaymond Mao 	if (mtype == MEM_AREA_MAXTYPE) {
58366763721SRaymond Mao 		/* Map the DTB if it is not yet mapped */
58466763721SRaymond Mao 		dt->blob = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt,
585dcff802bSRaymond Mao 						dt_sz);
58666763721SRaymond Mao 		if (!dt->blob)
587e6027f48SAlvin Chang 			panic("Failed to map external DTB");
58866763721SRaymond Mao 	} else {
58966763721SRaymond Mao 		/* Get the DTB address if already mapped in a memory area */
590dcff802bSRaymond Mao 		dt->blob = phys_to_virt(phys_dt, mtype, dt_sz);
59166763721SRaymond Mao 		if (!dt->blob) {
59266763721SRaymond Mao 			EMSG("Failed to get a mapped external DTB for PA %#lx",
59366763721SRaymond Mao 			     phys_dt);
59466763721SRaymond Mao 			panic();
59566763721SRaymond Mao 		}
59666763721SRaymond Mao 	}
597e6027f48SAlvin Chang 
598dcff802bSRaymond Mao 	ret = init_dt_overlay(dt, dt_sz);
599e6027f48SAlvin Chang 	if (ret < 0) {
600e6027f48SAlvin Chang 		EMSG("Device Tree Overlay init fail @ %#lx: error %d", phys_dt,
601e6027f48SAlvin Chang 		     ret);
602e6027f48SAlvin Chang 		panic();
603e6027f48SAlvin Chang 	}
604e6027f48SAlvin Chang 
605dcff802bSRaymond Mao 	ret = fdt_open_into(dt->blob, dt->blob, dt_sz);
606e6027f48SAlvin Chang 	if (ret < 0) {
607e6027f48SAlvin Chang 		EMSG("Invalid Device Tree at %#lx: error %d", phys_dt, ret);
608e6027f48SAlvin Chang 		panic();
609e6027f48SAlvin Chang 	}
610e6027f48SAlvin Chang 
611e6027f48SAlvin Chang 	IMSG("Non-secure external DT found");
612e6027f48SAlvin Chang }
613e6027f48SAlvin Chang 
614e6027f48SAlvin Chang void *get_external_dt(void)
615e6027f48SAlvin Chang {
616e6027f48SAlvin Chang 	if (!IS_ENABLED(CFG_EXTERNAL_DT))
617e6027f48SAlvin Chang 		return NULL;
618e6027f48SAlvin Chang 
619e6027f48SAlvin Chang 	assert(cpu_mmu_enabled());
620e6027f48SAlvin Chang 	return external_dt.blob;
621e6027f48SAlvin Chang }
622e6027f48SAlvin Chang 
623e6027f48SAlvin Chang static TEE_Result release_external_dt(void)
624e6027f48SAlvin Chang {
625e6027f48SAlvin Chang 	int ret = 0;
62666763721SRaymond Mao 	paddr_t pa_dt = 0;
627e6027f48SAlvin Chang 
628e6027f48SAlvin Chang 	if (!IS_ENABLED(CFG_EXTERNAL_DT))
629e6027f48SAlvin Chang 		return TEE_SUCCESS;
630e6027f48SAlvin Chang 
631e6027f48SAlvin Chang 	if (!external_dt.blob)
632e6027f48SAlvin Chang 		return TEE_SUCCESS;
633e6027f48SAlvin Chang 
63466763721SRaymond Mao 	pa_dt = virt_to_phys(external_dt.blob);
63566763721SRaymond Mao 	/*
63666763721SRaymond Mao 	 * Skip packing and un-mapping operations if the external DTB is mapped
63766763721SRaymond Mao 	 * in a different memory area
63866763721SRaymond Mao 	 */
63966763721SRaymond Mao 	if (core_mmu_get_type_by_pa(pa_dt) != MEM_AREA_EXT_DT)
64066763721SRaymond Mao 		return TEE_SUCCESS;
64166763721SRaymond Mao 
642e6027f48SAlvin Chang 	ret = fdt_pack(external_dt.blob);
643e6027f48SAlvin Chang 	if (ret < 0) {
644e6027f48SAlvin Chang 		EMSG("Failed to pack Device Tree at 0x%" PRIxPA ": error %d",
645e6027f48SAlvin Chang 		     virt_to_phys(external_dt.blob), ret);
646e6027f48SAlvin Chang 		panic();
647e6027f48SAlvin Chang 	}
648e6027f48SAlvin Chang 
649e6027f48SAlvin Chang 	if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob,
650e6027f48SAlvin Chang 				    CFG_DTB_MAX_SIZE))
651e6027f48SAlvin Chang 		panic("Failed to remove temporary Device Tree mapping");
652e6027f48SAlvin Chang 
653e6027f48SAlvin Chang 	/* External DTB no more reached, reset pointer to invalid */
654e6027f48SAlvin Chang 	external_dt.blob = NULL;
655e6027f48SAlvin Chang 
656e6027f48SAlvin Chang 	return TEE_SUCCESS;
657e6027f48SAlvin Chang }
658e6027f48SAlvin Chang 
659e6027f48SAlvin Chang boot_final(release_external_dt);
660e6027f48SAlvin Chang 
661e6027f48SAlvin Chang int add_dt_path_subnode(struct dt_descriptor *dt, const char *path,
662e6027f48SAlvin Chang 			const char *subnode)
663e6027f48SAlvin Chang {
6640c49b6d6SAlvin Chang 	int offs = 0;
665e6027f48SAlvin Chang 
666e6027f48SAlvin Chang 	offs = fdt_path_offset(dt->blob, path);
667e6027f48SAlvin Chang 	if (offs < 0)
6680c49b6d6SAlvin Chang 		return offs;
669e6027f48SAlvin Chang 	offs = add_dt_overlay_fragment(dt, offs);
670e6027f48SAlvin Chang 	if (offs < 0)
671e6027f48SAlvin Chang 		return offs;
6720c49b6d6SAlvin Chang 	return fdt_add_subnode(dt->blob, offs, subnode);
673e6027f48SAlvin Chang }
674e6027f48SAlvin Chang 
675e6027f48SAlvin Chang static void set_dt_val(void *data, uint32_t cell_size, uint64_t val)
676e6027f48SAlvin Chang {
677e6027f48SAlvin Chang 	if (cell_size == 1) {
678e6027f48SAlvin Chang 		fdt32_t v = cpu_to_fdt32((uint32_t)val);
679e6027f48SAlvin Chang 
680e6027f48SAlvin Chang 		memcpy(data, &v, sizeof(v));
681e6027f48SAlvin Chang 	} else {
682e6027f48SAlvin Chang 		fdt64_t v = cpu_to_fdt64(val);
683e6027f48SAlvin Chang 
684e6027f48SAlvin Chang 		memcpy(data, &v, sizeof(v));
685e6027f48SAlvin Chang 	}
686e6027f48SAlvin Chang }
687e6027f48SAlvin Chang 
688e6027f48SAlvin Chang int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name,
689e6027f48SAlvin Chang 			paddr_t pa, size_t size)
690e6027f48SAlvin Chang {
691e6027f48SAlvin Chang 	int offs = 0;
692e6027f48SAlvin Chang 	int ret = 0;
693e6027f48SAlvin Chang 	int addr_size = -1;
694e6027f48SAlvin Chang 	int len_size = -1;
695e6027f48SAlvin Chang 	bool found = true;
6960c49b6d6SAlvin Chang 	char subnode_name[80] = { };
697e6027f48SAlvin Chang 
698e6027f48SAlvin Chang 	offs = fdt_path_offset(dt->blob, "/reserved-memory");
699e6027f48SAlvin Chang 
700e6027f48SAlvin Chang 	if (offs < 0) {
701e6027f48SAlvin Chang 		found = false;
702e6027f48SAlvin Chang 		offs = 0;
703e6027f48SAlvin Chang 	}
704e6027f48SAlvin Chang 
705e6027f48SAlvin Chang 	if (IS_ENABLED2(_CFG_USE_DTB_OVERLAY)) {
706e6027f48SAlvin Chang 		len_size = sizeof(paddr_t) / sizeof(uint32_t);
707e6027f48SAlvin Chang 		addr_size = sizeof(paddr_t) / sizeof(uint32_t);
708e6027f48SAlvin Chang 	} else {
709e6027f48SAlvin Chang 		len_size = fdt_size_cells(dt->blob, offs);
710e6027f48SAlvin Chang 		if (len_size < 0)
7110c49b6d6SAlvin Chang 			return len_size;
712e6027f48SAlvin Chang 		addr_size = fdt_address_cells(dt->blob, offs);
713e6027f48SAlvin Chang 		if (addr_size < 0)
7140c49b6d6SAlvin Chang 			return addr_size;
715e6027f48SAlvin Chang 	}
716e6027f48SAlvin Chang 
717e6027f48SAlvin Chang 	if (!found) {
718e6027f48SAlvin Chang 		offs = add_dt_path_subnode(dt, "/", "reserved-memory");
719e6027f48SAlvin Chang 		if (offs < 0)
7200c49b6d6SAlvin Chang 			return offs;
721e6027f48SAlvin Chang 		ret = fdt_setprop_cell(dt->blob, offs, "#address-cells",
722e6027f48SAlvin Chang 				       addr_size);
723e6027f48SAlvin Chang 		if (ret < 0)
7240c49b6d6SAlvin Chang 			return ret;
725e6027f48SAlvin Chang 		ret = fdt_setprop_cell(dt->blob, offs, "#size-cells", len_size);
726e6027f48SAlvin Chang 		if (ret < 0)
7270c49b6d6SAlvin Chang 			return ret;
728e6027f48SAlvin Chang 		ret = fdt_setprop(dt->blob, offs, "ranges", NULL, 0);
729e6027f48SAlvin Chang 		if (ret < 0)
7300c49b6d6SAlvin Chang 			return ret;
731e6027f48SAlvin Chang 	}
732e6027f48SAlvin Chang 
733e6027f48SAlvin Chang 	ret = snprintf(subnode_name, sizeof(subnode_name),
734e6027f48SAlvin Chang 		       "%s@%" PRIxPA, name, pa);
735e6027f48SAlvin Chang 	if (ret < 0 || ret >= (int)sizeof(subnode_name))
736e6027f48SAlvin Chang 		DMSG("truncated node \"%s@%" PRIxPA"\"", name, pa);
737e6027f48SAlvin Chang 	offs = fdt_add_subnode(dt->blob, offs, subnode_name);
738e6027f48SAlvin Chang 	if (offs >= 0) {
7390c49b6d6SAlvin Chang 		uint32_t data[FDT_MAX_NCELLS * 2] = { };
740e6027f48SAlvin Chang 
741e6027f48SAlvin Chang 		set_dt_val(data, addr_size, pa);
742e6027f48SAlvin Chang 		set_dt_val(data + addr_size, len_size, size);
743e6027f48SAlvin Chang 		ret = fdt_setprop(dt->blob, offs, "reg", data,
744e6027f48SAlvin Chang 				  sizeof(uint32_t) * (addr_size + len_size));
745e6027f48SAlvin Chang 		if (ret < 0)
7460c49b6d6SAlvin Chang 			return ret;
747e6027f48SAlvin Chang 		ret = fdt_setprop(dt->blob, offs, "no-map", NULL, 0);
748e6027f48SAlvin Chang 		if (ret < 0)
7490c49b6d6SAlvin Chang 			return ret;
750e6027f48SAlvin Chang 	} else {
7510c49b6d6SAlvin Chang 		return offs;
752e6027f48SAlvin Chang 	}
753e6027f48SAlvin Chang 	return 0;
754e6027f48SAlvin Chang }
7554bc2c5f0SSungbae Yoo 
7564bc2c5f0SSungbae Yoo #if defined(CFG_CORE_FFA)
7574bc2c5f0SSungbae Yoo void init_manifest_dt(void *fdt)
7584bc2c5f0SSungbae Yoo {
7594bc2c5f0SSungbae Yoo 	manifest_dt = fdt;
7604bc2c5f0SSungbae Yoo }
7614bc2c5f0SSungbae Yoo 
7624bc2c5f0SSungbae Yoo void reinit_manifest_dt(void)
7634bc2c5f0SSungbae Yoo {
7644bc2c5f0SSungbae Yoo 	paddr_t pa = (unsigned long)manifest_dt;
7654bc2c5f0SSungbae Yoo 	void *fdt = NULL;
7664bc2c5f0SSungbae Yoo 	int ret = 0;
7674bc2c5f0SSungbae Yoo 
7684bc2c5f0SSungbae Yoo 	if (!pa) {
7694bc2c5f0SSungbae Yoo 		EMSG("No manifest DT found");
7704bc2c5f0SSungbae Yoo 		return;
7714bc2c5f0SSungbae Yoo 	}
7724bc2c5f0SSungbae Yoo 
7734bc2c5f0SSungbae Yoo 	fdt = core_mmu_add_mapping(MEM_AREA_MANIFEST_DT, pa, CFG_DTB_MAX_SIZE);
7744bc2c5f0SSungbae Yoo 	if (!fdt)
7754bc2c5f0SSungbae Yoo 		panic("Failed to map manifest DT");
7764bc2c5f0SSungbae Yoo 
7774bc2c5f0SSungbae Yoo 	manifest_dt = fdt;
7784bc2c5f0SSungbae Yoo 
7794bc2c5f0SSungbae Yoo 	ret = fdt_check_full(fdt, CFG_DTB_MAX_SIZE);
7804bc2c5f0SSungbae Yoo 	if (ret < 0) {
7814bc2c5f0SSungbae Yoo 		EMSG("Invalid manifest Device Tree at %#lx: error %d", pa, ret);
7824bc2c5f0SSungbae Yoo 		panic();
7834bc2c5f0SSungbae Yoo 	}
7844bc2c5f0SSungbae Yoo 
7854bc2c5f0SSungbae Yoo 	IMSG("manifest DT found");
7864bc2c5f0SSungbae Yoo }
7874bc2c5f0SSungbae Yoo 
7884bc2c5f0SSungbae Yoo void *get_manifest_dt(void)
7894bc2c5f0SSungbae Yoo {
7904bc2c5f0SSungbae Yoo 	return manifest_dt;
7914bc2c5f0SSungbae Yoo }
7924bc2c5f0SSungbae Yoo 
7934bc2c5f0SSungbae Yoo static TEE_Result release_manifest_dt(void)
7944bc2c5f0SSungbae Yoo {
7954bc2c5f0SSungbae Yoo 	if (!manifest_dt)
7964bc2c5f0SSungbae Yoo 		return TEE_SUCCESS;
7974bc2c5f0SSungbae Yoo 
7984bc2c5f0SSungbae Yoo 	if (core_mmu_remove_mapping(MEM_AREA_MANIFEST_DT, manifest_dt,
7994bc2c5f0SSungbae Yoo 				    CFG_DTB_MAX_SIZE))
8004bc2c5f0SSungbae Yoo 		panic("Failed to remove temporary manifest DT mapping");
8014bc2c5f0SSungbae Yoo 	manifest_dt = NULL;
8024bc2c5f0SSungbae Yoo 
8034bc2c5f0SSungbae Yoo 	return TEE_SUCCESS;
8044bc2c5f0SSungbae Yoo }
8054bc2c5f0SSungbae Yoo 
8064bc2c5f0SSungbae Yoo boot_final(release_manifest_dt);
8074bc2c5f0SSungbae Yoo #else
8084bc2c5f0SSungbae Yoo void init_manifest_dt(void *fdt __unused)
8094bc2c5f0SSungbae Yoo {
8104bc2c5f0SSungbae Yoo }
8114bc2c5f0SSungbae Yoo 
8124bc2c5f0SSungbae Yoo void reinit_manifest_dt(void)
8134bc2c5f0SSungbae Yoo {
8144bc2c5f0SSungbae Yoo }
8154bc2c5f0SSungbae Yoo 
8164bc2c5f0SSungbae Yoo void *get_manifest_dt(void)
8174bc2c5f0SSungbae Yoo {
8184bc2c5f0SSungbae Yoo 	return NULL;
8194bc2c5f0SSungbae Yoo }
8204bc2c5f0SSungbae Yoo #endif /*CFG_CORE_FFA*/
821