xref: /optee_os/core/kernel/dt.c (revision 9e3c57c88b0cdd41de57107725621c8c0857a838)
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>
7a4f139d7SJerome Forissier #include <kernel/dt.h>
8*9e3c57c8SEtienne Carriere #include <kernel/dt_driver.h>
97acb3a47SLudovic Barre #include <kernel/interrupt.h>
10bce4951cSJens Wiklander #include <kernel/linker.h>
119fe4c797SJerome Forissier #include <libfdt.h>
127ba16abbSJerome Forissier #include <mm/core_memprot.h>
137ba16abbSJerome Forissier #include <mm/core_mmu.h>
14a4f139d7SJerome Forissier #include <string.h>
157ba16abbSJerome Forissier #include <trace.h>
16a4f139d7SJerome Forissier 
17a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
18a4f139d7SJerome Forissier {
19a4f139d7SJerome Forissier 	const struct dt_device_match *dm;
20a4f139d7SJerome Forissier 	const struct dt_driver *drv;
21a4f139d7SJerome Forissier 
22db783ff8SEtienne Carriere 	for_each_dt_driver(drv) {
23db783ff8SEtienne Carriere 		for (dm = drv->match_table; dm; dm++) {
24db783ff8SEtienne Carriere 			if (!dm->compatible) {
25db783ff8SEtienne Carriere 				break;
26db783ff8SEtienne Carriere 			}
27a4f139d7SJerome Forissier 			if (!fdt_node_check_compatible(fdt, offs,
28db783ff8SEtienne Carriere 						       dm->compatible)) {
29a4f139d7SJerome Forissier 				return drv;
30db783ff8SEtienne Carriere 			}
31db783ff8SEtienne Carriere 		}
32db783ff8SEtienne Carriere 	}
33a4f139d7SJerome Forissier 
34a4f139d7SJerome Forissier 	return NULL;
35a4f139d7SJerome Forissier }
36a4f139d7SJerome Forissier 
3750f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname)
3850f3b323SPeng Fan {
3950f3b323SPeng Fan 	const void *prop;
4050f3b323SPeng Fan 
4150f3b323SPeng Fan 	prop = fdt_getprop(fdt, offs, propname, NULL);
4250f3b323SPeng Fan 
4350f3b323SPeng Fan 	return prop;
4450f3b323SPeng Fan }
4550f3b323SPeng Fan 
4695cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node)
4795cdc5e0SCedric Neveux {
4895cdc5e0SCedric Neveux 	const char *prop = NULL;
4995cdc5e0SCedric Neveux 	int len = 0;
5095cdc5e0SCedric Neveux 
5195cdc5e0SCedric Neveux 	prop = fdt_getprop(fdt, node, "status", &len);
5295cdc5e0SCedric Neveux 	if (!prop) {
5395cdc5e0SCedric Neveux 		if (fdt_setprop_string(fdt, node, "status", "disabled"))
5495cdc5e0SCedric Neveux 			return -1;
5595cdc5e0SCedric Neveux 	} else {
5695cdc5e0SCedric Neveux 		/*
5795cdc5e0SCedric Neveux 		 * Status is there, modify it.
5895cdc5e0SCedric Neveux 		 * Ask to set "disabled" value to the property. The value
5995cdc5e0SCedric Neveux 		 * will be automatically truncated with "len" size by the
6095cdc5e0SCedric Neveux 		 * fdt_setprop_inplace function.
6195cdc5e0SCedric Neveux 		 * Setting a value different from "ok" or "okay" will disable
6295cdc5e0SCedric Neveux 		 * the property.
6395cdc5e0SCedric Neveux 		 * Setting a truncated value of "disabled" with the original
6495cdc5e0SCedric Neveux 		 * property "len" is preferred to not increase the DT size and
6595cdc5e0SCedric Neveux 		 * losing time in recalculating the overall DT offsets.
6695cdc5e0SCedric Neveux 		 * If original length of the status property is larger than
6795cdc5e0SCedric Neveux 		 * "disabled", the property will start with "disabled" and be
6895cdc5e0SCedric Neveux 		 * completed with the rest of the original property.
6995cdc5e0SCedric Neveux 		 */
7095cdc5e0SCedric Neveux 		if (fdt_setprop_inplace(fdt, node, "status", "disabled", len))
7195cdc5e0SCedric Neveux 			return -1;
7295cdc5e0SCedric Neveux 	}
7395cdc5e0SCedric Neveux 
7495cdc5e0SCedric Neveux 	return 0;
7595cdc5e0SCedric Neveux }
7695cdc5e0SCedric Neveux 
7795cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node)
7895cdc5e0SCedric Neveux {
7995cdc5e0SCedric Neveux 	if (dt_disable_status(fdt, node)) {
8095cdc5e0SCedric Neveux 		EMSG("Unable to disable Normal Status");
8195cdc5e0SCedric Neveux 		return -1;
8295cdc5e0SCedric Neveux 	}
8395cdc5e0SCedric Neveux 
8495cdc5e0SCedric Neveux 	if (fdt_setprop_string(fdt, node, "secure-status", "okay"))
8595cdc5e0SCedric Neveux 		return -1;
8695cdc5e0SCedric Neveux 
8795cdc5e0SCedric Neveux 	return 0;
8895cdc5e0SCedric Neveux }
8995cdc5e0SCedric Neveux 
90a5d5bbc8SVesa Jääskeläinen int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size,
91a5d5bbc8SVesa Jääskeläinen 	       enum dt_map_dev_directive mapping)
927ba16abbSJerome Forissier {
937ba16abbSJerome Forissier 	enum teecore_memtypes mtype;
947ba16abbSJerome Forissier 	paddr_t pbase;
957ba16abbSJerome Forissier 	vaddr_t vbase;
96df7cecc0SLionel Debieve 	size_t sz;
977ba16abbSJerome Forissier 	int st;
987ba16abbSJerome Forissier 
997ba16abbSJerome Forissier 	assert(cpu_mmu_enabled());
1007ba16abbSJerome Forissier 
101f354a5d8SGatien Chevallier 	st = fdt_get_status(fdt, offs);
1027ba16abbSJerome Forissier 	if (st == DT_STATUS_DISABLED)
1037ba16abbSJerome Forissier 		return -1;
1047ba16abbSJerome Forissier 
105f354a5d8SGatien Chevallier 	pbase = fdt_reg_base_address(fdt, offs);
106c0cfb36cSEtienne Carriere 	if (pbase == DT_INFO_INVALID_REG)
1077ba16abbSJerome Forissier 		return -1;
108f354a5d8SGatien Chevallier 	sz = fdt_reg_size(fdt, offs);
109df7cecc0SLionel Debieve 	if (sz == DT_INFO_INVALID_REG_SIZE)
1107ba16abbSJerome Forissier 		return -1;
1117ba16abbSJerome Forissier 
112a5d5bbc8SVesa Jääskeläinen 	switch (mapping) {
113a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_AUTO:
1147ba16abbSJerome Forissier 		if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC))
1157ba16abbSJerome Forissier 			mtype = MEM_AREA_IO_SEC;
1167ba16abbSJerome Forissier 		else
1177ba16abbSJerome Forissier 			mtype = MEM_AREA_IO_NSEC;
118a5d5bbc8SVesa Jääskeläinen 		break;
119a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_SECURE:
120a5d5bbc8SVesa Jääskeläinen 		mtype = MEM_AREA_IO_SEC;
121a5d5bbc8SVesa Jääskeläinen 		break;
122a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_NON_SECURE:
123a5d5bbc8SVesa Jääskeläinen 		mtype = MEM_AREA_IO_NSEC;
124a5d5bbc8SVesa Jääskeläinen 		break;
125a5d5bbc8SVesa Jääskeläinen 	default:
126a5d5bbc8SVesa Jääskeläinen 		panic("Invalid mapping specified");
127a5d5bbc8SVesa Jääskeläinen 		break;
128a5d5bbc8SVesa Jääskeläinen 	}
1297ba16abbSJerome Forissier 
1307ba16abbSJerome Forissier 	/* Check if we have a mapping, create one if needed */
131bc9618c0SAnton Rybakov 	vbase = (vaddr_t)core_mmu_add_mapping(mtype, pbase, sz);
132bc9618c0SAnton Rybakov 	if (!vbase) {
1337ba16abbSJerome Forissier 		EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA,
13423b1daf4SPeng Fan 		     (size_t)sz, pbase);
1357ba16abbSJerome Forissier 		return -1;
1367ba16abbSJerome Forissier 	}
1377ba16abbSJerome Forissier 
1387ba16abbSJerome Forissier 	*base = vbase;
1397ba16abbSJerome Forissier 	*size = sz;
1407ba16abbSJerome Forissier 	return 0;
1417ba16abbSJerome Forissier }
1427ba16abbSJerome Forissier 
1439fe4c797SJerome Forissier /* Read a physical address (n=1 or 2 cells) */
144f354a5d8SGatien Chevallier static paddr_t fdt_read_paddr(const uint32_t *cell, int n)
1459fe4c797SJerome Forissier {
1469fe4c797SJerome Forissier 	paddr_t addr;
1479fe4c797SJerome Forissier 
1489fe4c797SJerome Forissier 	if (n < 1 || n > 2)
1499fe4c797SJerome Forissier 		goto bad;
1509fe4c797SJerome Forissier 
1519fe4c797SJerome Forissier 	addr = fdt32_to_cpu(*cell);
1529fe4c797SJerome Forissier 	cell++;
1539fe4c797SJerome Forissier 	if (n == 2) {
1549fe4c797SJerome Forissier #ifdef ARM32
1559fe4c797SJerome Forissier 		if (addr) {
1569fe4c797SJerome Forissier 			/* High order 32 bits can't be nonzero */
1579fe4c797SJerome Forissier 			goto bad;
1589fe4c797SJerome Forissier 		}
1599fe4c797SJerome Forissier 		addr = fdt32_to_cpu(*cell);
1609fe4c797SJerome Forissier #else
1619fe4c797SJerome Forissier 		addr = (addr << 32) | fdt32_to_cpu(*cell);
1629fe4c797SJerome Forissier #endif
1639fe4c797SJerome Forissier 	}
1649fe4c797SJerome Forissier 
1659fe4c797SJerome Forissier 	return addr;
1669fe4c797SJerome Forissier bad:
167c0cfb36cSEtienne Carriere 	return DT_INFO_INVALID_REG;
1689fe4c797SJerome Forissier 
1699fe4c797SJerome Forissier }
1709fe4c797SJerome Forissier 
171f354a5d8SGatien Chevallier paddr_t fdt_reg_base_address(const void *fdt, int offs)
1729fe4c797SJerome Forissier {
1739fe4c797SJerome Forissier 	const void *reg;
1749fe4c797SJerome Forissier 	int ncells;
1759fe4c797SJerome Forissier 	int len;
17634deb103SPeng Fan 	int parent;
17734deb103SPeng Fan 
17834deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
17934deb103SPeng Fan 	if (parent < 0)
180c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1819fe4c797SJerome Forissier 
1829fe4c797SJerome Forissier 	reg = fdt_getprop(fdt, offs, "reg", &len);
1839fe4c797SJerome Forissier 	if (!reg)
184c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1859fe4c797SJerome Forissier 
18634deb103SPeng Fan 	ncells = fdt_address_cells(fdt, parent);
1879fe4c797SJerome Forissier 	if (ncells < 0)
188c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1899fe4c797SJerome Forissier 
190f354a5d8SGatien Chevallier 	return fdt_read_paddr(reg, ncells);
1919fe4c797SJerome Forissier }
1929fe4c797SJerome Forissier 
193a2e8c036SGatien Chevallier static size_t fdt_read_size(const uint32_t *cell, int n)
194a2e8c036SGatien Chevallier {
195a2e8c036SGatien Chevallier 	uint32_t sz = 0;
196a2e8c036SGatien Chevallier 
197a2e8c036SGatien Chevallier 	sz = fdt32_to_cpu(*cell);
198a2e8c036SGatien Chevallier 	if (n == 2) {
199a2e8c036SGatien Chevallier 		if (sz)
200a2e8c036SGatien Chevallier 			return DT_INFO_INVALID_REG_SIZE;
201a2e8c036SGatien Chevallier 
202a2e8c036SGatien Chevallier 		cell++;
203a2e8c036SGatien Chevallier 		sz = fdt32_to_cpu(*cell);
204a2e8c036SGatien Chevallier 	}
205a2e8c036SGatien Chevallier 
206a2e8c036SGatien Chevallier 	return sz;
207a2e8c036SGatien Chevallier }
208a2e8c036SGatien Chevallier 
209f354a5d8SGatien Chevallier size_t fdt_reg_size(const void *fdt, int offs)
2109fe4c797SJerome Forissier {
2119fe4c797SJerome Forissier 	const uint32_t *reg;
2129fe4c797SJerome Forissier 	int n;
2139fe4c797SJerome Forissier 	int len;
21434deb103SPeng Fan 	int parent;
21534deb103SPeng Fan 
21634deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
21734deb103SPeng Fan 	if (parent < 0)
2181527e616SMarek Vasut 		return DT_INFO_INVALID_REG_SIZE;
2199fe4c797SJerome Forissier 
2209fe4c797SJerome Forissier 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
2219fe4c797SJerome Forissier 	if (!reg)
222df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2239fe4c797SJerome Forissier 
22434deb103SPeng Fan 	n = fdt_address_cells(fdt, parent);
2259fe4c797SJerome Forissier 	if (n < 1 || n > 2)
226df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2279fe4c797SJerome Forissier 
2289fe4c797SJerome Forissier 	reg += n;
2299fe4c797SJerome Forissier 
23034deb103SPeng Fan 	n = fdt_size_cells(fdt, parent);
2319fe4c797SJerome Forissier 	if (n < 1 || n > 2)
232df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2339fe4c797SJerome Forissier 
234a2e8c036SGatien Chevallier 	return fdt_read_size(reg, n);
2359fe4c797SJerome Forissier }
2369fe4c797SJerome Forissier 
2379fe4c797SJerome Forissier static bool is_okay(const char *st, int len)
2389fe4c797SJerome Forissier {
2399fe4c797SJerome Forissier 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
2409fe4c797SJerome Forissier }
2419fe4c797SJerome Forissier 
242f354a5d8SGatien Chevallier int fdt_get_status(const void *fdt, int offs)
2439fe4c797SJerome Forissier {
2449fe4c797SJerome Forissier 	const char *prop;
2459fe4c797SJerome Forissier 	int st = 0;
2469fe4c797SJerome Forissier 	int len;
2479fe4c797SJerome Forissier 
2489fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "status", &len);
2499fe4c797SJerome Forissier 	if (!prop || is_okay(prop, len)) {
2509fe4c797SJerome Forissier 		/* If status is not specified, it defaults to "okay" */
2519fe4c797SJerome Forissier 		st |= DT_STATUS_OK_NSEC;
2529fe4c797SJerome Forissier 	}
2539fe4c797SJerome Forissier 
2549fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
2559fe4c797SJerome Forissier 	if (!prop) {
2569fe4c797SJerome Forissier 		/*
2579fe4c797SJerome Forissier 		 * When secure-status is not specified it defaults to the same
2589fe4c797SJerome Forissier 		 * value as status
2599fe4c797SJerome Forissier 		 */
2609fe4c797SJerome Forissier 		if (st & DT_STATUS_OK_NSEC)
2619fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2629fe4c797SJerome Forissier 	} else {
2639fe4c797SJerome Forissier 		if (is_okay(prop, len))
2649fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2659fe4c797SJerome Forissier 	}
2669fe4c797SJerome Forissier 
2679fe4c797SJerome Forissier 	return st;
2689fe4c797SJerome Forissier }
269c0cfb36cSEtienne Carriere 
270f354a5d8SGatien Chevallier void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs)
271c0cfb36cSEtienne Carriere {
272c0cfb36cSEtienne Carriere 	struct dt_node_info dinfo = {
273c0cfb36cSEtienne Carriere 		.reg = DT_INFO_INVALID_REG,
27406fd21ddSLionel Debieve 		.reg_size = DT_INFO_INVALID_REG_SIZE,
275c0cfb36cSEtienne Carriere 		.clock = DT_INFO_INVALID_CLOCK,
276c0cfb36cSEtienne Carriere 		.reset = DT_INFO_INVALID_RESET,
2777acb3a47SLudovic Barre 		.interrupt = DT_INFO_INVALID_INTERRUPT,
278c0cfb36cSEtienne Carriere 	};
279c0cfb36cSEtienne Carriere 	const fdt32_t *cuint;
280c0cfb36cSEtienne Carriere 
281f354a5d8SGatien Chevallier 	dinfo.reg = fdt_reg_base_address(fdt, offs);
282f354a5d8SGatien Chevallier 	dinfo.reg_size = fdt_reg_size(fdt, offs);
283c0cfb36cSEtienne Carriere 
284c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "clocks", NULL);
285c0cfb36cSEtienne Carriere 	if (cuint) {
286c0cfb36cSEtienne Carriere 		cuint++;
287c0cfb36cSEtienne Carriere 		dinfo.clock = (int)fdt32_to_cpu(*cuint);
288c0cfb36cSEtienne Carriere 	}
289c0cfb36cSEtienne Carriere 
290c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "resets", NULL);
291c0cfb36cSEtienne Carriere 	if (cuint) {
292c0cfb36cSEtienne Carriere 		cuint++;
293c0cfb36cSEtienne Carriere 		dinfo.reset = (int)fdt32_to_cpu(*cuint);
294c0cfb36cSEtienne Carriere 	}
295c0cfb36cSEtienne Carriere 
296702fe5a7SClément Léger 	dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type,
297702fe5a7SClément Léger 					       &dinfo.prio);
2987acb3a47SLudovic Barre 
299f354a5d8SGatien Chevallier 	dinfo.status = fdt_get_status(fdt, offs);
300c0cfb36cSEtienne Carriere 
301c0cfb36cSEtienne Carriere 	*info = dinfo;
302c0cfb36cSEtienne Carriere }
303876826f3SGabriel Fernandez 
304f354a5d8SGatien Chevallier int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
305876826f3SGabriel Fernandez 			  uint32_t *array, size_t count)
306876826f3SGabriel Fernandez {
307876826f3SGabriel Fernandez 	const fdt32_t *cuint = NULL;
308876826f3SGabriel Fernandez 	int len = 0;
309876826f3SGabriel Fernandez 	uint32_t i = 0;
310876826f3SGabriel Fernandez 
311876826f3SGabriel Fernandez 	cuint = fdt_getprop(fdt, node, prop_name, &len);
312876826f3SGabriel Fernandez 	if (!cuint)
31373e27bfaSGatien Chevallier 		return len;
314876826f3SGabriel Fernandez 
315876826f3SGabriel Fernandez 	if ((uint32_t)len != (count * sizeof(uint32_t)))
316876826f3SGabriel Fernandez 		return -FDT_ERR_BADLAYOUT;
317876826f3SGabriel Fernandez 
318876826f3SGabriel Fernandez 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
319876826f3SGabriel Fernandez 		*array = fdt32_to_cpu(*cuint);
320876826f3SGabriel Fernandez 		array++;
321876826f3SGabriel Fernandez 		cuint++;
322876826f3SGabriel Fernandez 	}
323876826f3SGabriel Fernandez 
324876826f3SGabriel Fernandez 	return 0;
325876826f3SGabriel Fernandez }
326876826f3SGabriel Fernandez 
3277c3a6b7bSGatien Chevallier int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
3287c3a6b7bSGatien Chevallier 			  int index, uint32_t *value)
3297c3a6b7bSGatien Chevallier {
3307c3a6b7bSGatien Chevallier 	const fdt32_t *cuint = NULL;
3317c3a6b7bSGatien Chevallier 	int len = 0;
3327c3a6b7bSGatien Chevallier 
3337c3a6b7bSGatien Chevallier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
3347c3a6b7bSGatien Chevallier 	if (!cuint)
3357c3a6b7bSGatien Chevallier 		return len;
3367c3a6b7bSGatien Chevallier 
3377c3a6b7bSGatien Chevallier 	if ((uint32_t)len < (sizeof(uint32_t) * (index + 1)))
3387c3a6b7bSGatien Chevallier 		return -FDT_ERR_BADLAYOUT;
3397c3a6b7bSGatien Chevallier 
3407c3a6b7bSGatien Chevallier 	*value = fdt32_to_cpu(cuint[index]);
3417c3a6b7bSGatien Chevallier 
3427c3a6b7bSGatien Chevallier 	return 0;
3437c3a6b7bSGatien Chevallier }
3447c3a6b7bSGatien Chevallier 
345f354a5d8SGatien Chevallier int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
346876826f3SGabriel Fernandez 		    uint32_t *value)
347876826f3SGabriel Fernandez {
348f354a5d8SGatien Chevallier 	return fdt_read_uint32_array(fdt, node, prop_name, value, 1);
349876826f3SGabriel Fernandez }
350876826f3SGabriel Fernandez 
351f354a5d8SGatien Chevallier uint32_t fdt_read_uint32_default(const void *fdt, int node,
352876826f3SGabriel Fernandez 				 const char *prop_name, uint32_t dflt_value)
353876826f3SGabriel Fernandez {
3547c3a6b7bSGatien Chevallier 	uint32_t ret = dflt_value;
355876826f3SGabriel Fernandez 
3567c3a6b7bSGatien Chevallier 	fdt_read_uint32_index(fdt, node, prop_name, 0, &ret);
357876826f3SGabriel Fernandez 
3587c3a6b7bSGatien Chevallier 	return ret;
359876826f3SGabriel Fernandez }
36007ced948SGatien Chevallier 
36107ced948SGatien Chevallier int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
36207ced948SGatien Chevallier 			       paddr_t *base, size_t *size)
36307ced948SGatien Chevallier {
36407ced948SGatien Chevallier 	const fdt32_t *prop = NULL;
36507ced948SGatien Chevallier 	int parent = 0;
36607ced948SGatien Chevallier 	int len = 0;
36707ced948SGatien Chevallier 	int address_cells = 0;
36807ced948SGatien Chevallier 	int size_cells = 0;
36907ced948SGatien Chevallier 	int cell = 0;
37007ced948SGatien Chevallier 
37107ced948SGatien Chevallier 	parent = fdt_parent_offset(fdt, node);
37207ced948SGatien Chevallier 	if (parent < 0)
37307ced948SGatien Chevallier 		return parent;
37407ced948SGatien Chevallier 
37507ced948SGatien Chevallier 	address_cells = fdt_address_cells(fdt, parent);
37607ced948SGatien Chevallier 	if (address_cells < 0)
37707ced948SGatien Chevallier 		return address_cells;
37807ced948SGatien Chevallier 
37907ced948SGatien Chevallier 	size_cells = fdt_size_cells(fdt, parent);
38007ced948SGatien Chevallier 	if (size_cells < 0)
38107ced948SGatien Chevallier 		return size_cells;
38207ced948SGatien Chevallier 
38307ced948SGatien Chevallier 	cell = index * (address_cells + size_cells);
38407ced948SGatien Chevallier 
38507ced948SGatien Chevallier 	prop = fdt_getprop(fdt, node, "reg", &len);
38607ced948SGatien Chevallier 	if (!prop)
38707ced948SGatien Chevallier 		return len;
38807ced948SGatien Chevallier 
38907ced948SGatien Chevallier 	if (((cell + address_cells + size_cells) * (int)sizeof(uint32_t)) > len)
39007ced948SGatien Chevallier 		return -FDT_ERR_BADVALUE;
39107ced948SGatien Chevallier 
39207ced948SGatien Chevallier 	if (base) {
39307ced948SGatien Chevallier 		*base = fdt_read_paddr(&prop[cell], address_cells);
39407ced948SGatien Chevallier 		if (*base == DT_INFO_INVALID_REG)
39507ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
39607ced948SGatien Chevallier 	}
39707ced948SGatien Chevallier 
39807ced948SGatien Chevallier 	if (size) {
39907ced948SGatien Chevallier 		*size = fdt_read_size(&prop[cell + address_cells], size_cells);
40007ced948SGatien Chevallier 		if (*size == DT_INFO_INVALID_REG_SIZE)
40107ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
40207ced948SGatien Chevallier 	}
40307ced948SGatien Chevallier 
40407ced948SGatien Chevallier 	return 0;
40507ced948SGatien Chevallier }
40607ced948SGatien Chevallier 
40707ced948SGatien Chevallier int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
40807ced948SGatien Chevallier 			      paddr_t *base, size_t *size)
40907ced948SGatien Chevallier {
41007ced948SGatien Chevallier 	int index = 0;
41107ced948SGatien Chevallier 
41207ced948SGatien Chevallier 	index = fdt_stringlist_search(fdt, node, "reg-names", name);
41307ced948SGatien Chevallier 	if (index < 0)
41407ced948SGatien Chevallier 		return index;
41507ced948SGatien Chevallier 
41607ced948SGatien Chevallier 	return fdt_get_reg_props_by_index(fdt, node, index, base, size);
41707ced948SGatien Chevallier }
418