xref: /optee_os/core/kernel/dt.c (revision 07ced9486d6f4d74af18695d63881a6ad1a56e93)
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>
87acb3a47SLudovic Barre #include <kernel/interrupt.h>
9bce4951cSJens Wiklander #include <kernel/linker.h>
109fe4c797SJerome Forissier #include <libfdt.h>
117ba16abbSJerome Forissier #include <mm/core_memprot.h>
127ba16abbSJerome Forissier #include <mm/core_mmu.h>
13a4f139d7SJerome Forissier #include <string.h>
147ba16abbSJerome Forissier #include <trace.h>
15a4f139d7SJerome Forissier 
16a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
17a4f139d7SJerome Forissier {
18a4f139d7SJerome Forissier 	const struct dt_device_match *dm;
19a4f139d7SJerome Forissier 	const struct dt_driver *drv;
20a4f139d7SJerome Forissier 
21db783ff8SEtienne Carriere 	for_each_dt_driver(drv) {
22db783ff8SEtienne Carriere 		for (dm = drv->match_table; dm; dm++) {
23db783ff8SEtienne Carriere 			if (!dm->compatible) {
24db783ff8SEtienne Carriere 				break;
25db783ff8SEtienne Carriere 			}
26a4f139d7SJerome Forissier 			if (!fdt_node_check_compatible(fdt, offs,
27db783ff8SEtienne Carriere 						       dm->compatible)) {
28a4f139d7SJerome Forissier 				return drv;
29db783ff8SEtienne Carriere 			}
30db783ff8SEtienne Carriere 		}
31db783ff8SEtienne Carriere 	}
32a4f139d7SJerome Forissier 
33a4f139d7SJerome Forissier 	return NULL;
34a4f139d7SJerome Forissier }
35a4f139d7SJerome Forissier 
3650f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname)
3750f3b323SPeng Fan {
3850f3b323SPeng Fan 	const void *prop;
3950f3b323SPeng Fan 
4050f3b323SPeng Fan 	prop = fdt_getprop(fdt, offs, propname, NULL);
4150f3b323SPeng Fan 
4250f3b323SPeng Fan 	return prop;
4350f3b323SPeng Fan }
4450f3b323SPeng Fan 
4595cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node)
4695cdc5e0SCedric Neveux {
4795cdc5e0SCedric Neveux 	const char *prop = NULL;
4895cdc5e0SCedric Neveux 	int len = 0;
4995cdc5e0SCedric Neveux 
5095cdc5e0SCedric Neveux 	prop = fdt_getprop(fdt, node, "status", &len);
5195cdc5e0SCedric Neveux 	if (!prop) {
5295cdc5e0SCedric Neveux 		if (fdt_setprop_string(fdt, node, "status", "disabled"))
5395cdc5e0SCedric Neveux 			return -1;
5495cdc5e0SCedric Neveux 	} else {
5595cdc5e0SCedric Neveux 		/*
5695cdc5e0SCedric Neveux 		 * Status is there, modify it.
5795cdc5e0SCedric Neveux 		 * Ask to set "disabled" value to the property. The value
5895cdc5e0SCedric Neveux 		 * will be automatically truncated with "len" size by the
5995cdc5e0SCedric Neveux 		 * fdt_setprop_inplace function.
6095cdc5e0SCedric Neveux 		 * Setting a value different from "ok" or "okay" will disable
6195cdc5e0SCedric Neveux 		 * the property.
6295cdc5e0SCedric Neveux 		 * Setting a truncated value of "disabled" with the original
6395cdc5e0SCedric Neveux 		 * property "len" is preferred to not increase the DT size and
6495cdc5e0SCedric Neveux 		 * losing time in recalculating the overall DT offsets.
6595cdc5e0SCedric Neveux 		 * If original length of the status property is larger than
6695cdc5e0SCedric Neveux 		 * "disabled", the property will start with "disabled" and be
6795cdc5e0SCedric Neveux 		 * completed with the rest of the original property.
6895cdc5e0SCedric Neveux 		 */
6995cdc5e0SCedric Neveux 		if (fdt_setprop_inplace(fdt, node, "status", "disabled", len))
7095cdc5e0SCedric Neveux 			return -1;
7195cdc5e0SCedric Neveux 	}
7295cdc5e0SCedric Neveux 
7395cdc5e0SCedric Neveux 	return 0;
7495cdc5e0SCedric Neveux }
7595cdc5e0SCedric Neveux 
7695cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node)
7795cdc5e0SCedric Neveux {
7895cdc5e0SCedric Neveux 	if (dt_disable_status(fdt, node)) {
7995cdc5e0SCedric Neveux 		EMSG("Unable to disable Normal Status");
8095cdc5e0SCedric Neveux 		return -1;
8195cdc5e0SCedric Neveux 	}
8295cdc5e0SCedric Neveux 
8395cdc5e0SCedric Neveux 	if (fdt_setprop_string(fdt, node, "secure-status", "okay"))
8495cdc5e0SCedric Neveux 		return -1;
8595cdc5e0SCedric Neveux 
8695cdc5e0SCedric Neveux 	return 0;
8795cdc5e0SCedric Neveux }
8895cdc5e0SCedric Neveux 
89a5d5bbc8SVesa Jääskeläinen int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size,
90a5d5bbc8SVesa Jääskeläinen 	       enum dt_map_dev_directive mapping)
917ba16abbSJerome Forissier {
927ba16abbSJerome Forissier 	enum teecore_memtypes mtype;
937ba16abbSJerome Forissier 	paddr_t pbase;
947ba16abbSJerome Forissier 	vaddr_t vbase;
95df7cecc0SLionel Debieve 	size_t sz;
967ba16abbSJerome Forissier 	int st;
977ba16abbSJerome Forissier 
987ba16abbSJerome Forissier 	assert(cpu_mmu_enabled());
997ba16abbSJerome Forissier 
100f354a5d8SGatien Chevallier 	st = fdt_get_status(fdt, offs);
1017ba16abbSJerome Forissier 	if (st == DT_STATUS_DISABLED)
1027ba16abbSJerome Forissier 		return -1;
1037ba16abbSJerome Forissier 
104f354a5d8SGatien Chevallier 	pbase = fdt_reg_base_address(fdt, offs);
105c0cfb36cSEtienne Carriere 	if (pbase == DT_INFO_INVALID_REG)
1067ba16abbSJerome Forissier 		return -1;
107f354a5d8SGatien Chevallier 	sz = fdt_reg_size(fdt, offs);
108df7cecc0SLionel Debieve 	if (sz == DT_INFO_INVALID_REG_SIZE)
1097ba16abbSJerome Forissier 		return -1;
1107ba16abbSJerome Forissier 
111a5d5bbc8SVesa Jääskeläinen 	switch (mapping) {
112a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_AUTO:
1137ba16abbSJerome Forissier 		if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC))
1147ba16abbSJerome Forissier 			mtype = MEM_AREA_IO_SEC;
1157ba16abbSJerome Forissier 		else
1167ba16abbSJerome Forissier 			mtype = MEM_AREA_IO_NSEC;
117a5d5bbc8SVesa Jääskeläinen 		break;
118a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_SECURE:
119a5d5bbc8SVesa Jääskeläinen 		mtype = MEM_AREA_IO_SEC;
120a5d5bbc8SVesa Jääskeläinen 		break;
121a5d5bbc8SVesa Jääskeläinen 	case DT_MAP_NON_SECURE:
122a5d5bbc8SVesa Jääskeläinen 		mtype = MEM_AREA_IO_NSEC;
123a5d5bbc8SVesa Jääskeläinen 		break;
124a5d5bbc8SVesa Jääskeläinen 	default:
125a5d5bbc8SVesa Jääskeläinen 		panic("Invalid mapping specified");
126a5d5bbc8SVesa Jääskeläinen 		break;
127a5d5bbc8SVesa Jääskeläinen 	}
1287ba16abbSJerome Forissier 
1297ba16abbSJerome Forissier 	/* Check if we have a mapping, create one if needed */
130bc9618c0SAnton Rybakov 	vbase = (vaddr_t)core_mmu_add_mapping(mtype, pbase, sz);
131bc9618c0SAnton Rybakov 	if (!vbase) {
1327ba16abbSJerome Forissier 		EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA,
13323b1daf4SPeng Fan 		     (size_t)sz, pbase);
1347ba16abbSJerome Forissier 		return -1;
1357ba16abbSJerome Forissier 	}
1367ba16abbSJerome Forissier 
1377ba16abbSJerome Forissier 	*base = vbase;
1387ba16abbSJerome Forissier 	*size = sz;
1397ba16abbSJerome Forissier 	return 0;
1407ba16abbSJerome Forissier }
1417ba16abbSJerome Forissier 
1429fe4c797SJerome Forissier /* Read a physical address (n=1 or 2 cells) */
143f354a5d8SGatien Chevallier static paddr_t fdt_read_paddr(const uint32_t *cell, int n)
1449fe4c797SJerome Forissier {
1459fe4c797SJerome Forissier 	paddr_t addr;
1469fe4c797SJerome Forissier 
1479fe4c797SJerome Forissier 	if (n < 1 || n > 2)
1489fe4c797SJerome Forissier 		goto bad;
1499fe4c797SJerome Forissier 
1509fe4c797SJerome Forissier 	addr = fdt32_to_cpu(*cell);
1519fe4c797SJerome Forissier 	cell++;
1529fe4c797SJerome Forissier 	if (n == 2) {
1539fe4c797SJerome Forissier #ifdef ARM32
1549fe4c797SJerome Forissier 		if (addr) {
1559fe4c797SJerome Forissier 			/* High order 32 bits can't be nonzero */
1569fe4c797SJerome Forissier 			goto bad;
1579fe4c797SJerome Forissier 		}
1589fe4c797SJerome Forissier 		addr = fdt32_to_cpu(*cell);
1599fe4c797SJerome Forissier #else
1609fe4c797SJerome Forissier 		addr = (addr << 32) | fdt32_to_cpu(*cell);
1619fe4c797SJerome Forissier #endif
1629fe4c797SJerome Forissier 	}
1639fe4c797SJerome Forissier 
1649fe4c797SJerome Forissier 	return addr;
1659fe4c797SJerome Forissier bad:
166c0cfb36cSEtienne Carriere 	return DT_INFO_INVALID_REG;
1679fe4c797SJerome Forissier 
1689fe4c797SJerome Forissier }
1699fe4c797SJerome Forissier 
170f354a5d8SGatien Chevallier paddr_t fdt_reg_base_address(const void *fdt, int offs)
1719fe4c797SJerome Forissier {
1729fe4c797SJerome Forissier 	const void *reg;
1739fe4c797SJerome Forissier 	int ncells;
1749fe4c797SJerome Forissier 	int len;
17534deb103SPeng Fan 	int parent;
17634deb103SPeng Fan 
17734deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
17834deb103SPeng Fan 	if (parent < 0)
179c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1809fe4c797SJerome Forissier 
1819fe4c797SJerome Forissier 	reg = fdt_getprop(fdt, offs, "reg", &len);
1829fe4c797SJerome Forissier 	if (!reg)
183c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1849fe4c797SJerome Forissier 
18534deb103SPeng Fan 	ncells = fdt_address_cells(fdt, parent);
1869fe4c797SJerome Forissier 	if (ncells < 0)
187c0cfb36cSEtienne Carriere 		return DT_INFO_INVALID_REG;
1889fe4c797SJerome Forissier 
189f354a5d8SGatien Chevallier 	return fdt_read_paddr(reg, ncells);
1909fe4c797SJerome Forissier }
1919fe4c797SJerome Forissier 
192a2e8c036SGatien Chevallier static size_t fdt_read_size(const uint32_t *cell, int n)
193a2e8c036SGatien Chevallier {
194a2e8c036SGatien Chevallier 	uint32_t sz = 0;
195a2e8c036SGatien Chevallier 
196a2e8c036SGatien Chevallier 	sz = fdt32_to_cpu(*cell);
197a2e8c036SGatien Chevallier 	if (n == 2) {
198a2e8c036SGatien Chevallier 		if (sz)
199a2e8c036SGatien Chevallier 			return DT_INFO_INVALID_REG_SIZE;
200a2e8c036SGatien Chevallier 
201a2e8c036SGatien Chevallier 		cell++;
202a2e8c036SGatien Chevallier 		sz = fdt32_to_cpu(*cell);
203a2e8c036SGatien Chevallier 	}
204a2e8c036SGatien Chevallier 
205a2e8c036SGatien Chevallier 	return sz;
206a2e8c036SGatien Chevallier }
207a2e8c036SGatien Chevallier 
208f354a5d8SGatien Chevallier size_t fdt_reg_size(const void *fdt, int offs)
2099fe4c797SJerome Forissier {
2109fe4c797SJerome Forissier 	const uint32_t *reg;
2119fe4c797SJerome Forissier 	int n;
2129fe4c797SJerome Forissier 	int len;
21334deb103SPeng Fan 	int parent;
21434deb103SPeng Fan 
21534deb103SPeng Fan 	parent = fdt_parent_offset(fdt, offs);
21634deb103SPeng Fan 	if (parent < 0)
2171527e616SMarek Vasut 		return DT_INFO_INVALID_REG_SIZE;
2189fe4c797SJerome Forissier 
2199fe4c797SJerome Forissier 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
2209fe4c797SJerome Forissier 	if (!reg)
221df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2229fe4c797SJerome Forissier 
22334deb103SPeng Fan 	n = fdt_address_cells(fdt, parent);
2249fe4c797SJerome Forissier 	if (n < 1 || n > 2)
225df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2269fe4c797SJerome Forissier 
2279fe4c797SJerome Forissier 	reg += n;
2289fe4c797SJerome Forissier 
22934deb103SPeng Fan 	n = fdt_size_cells(fdt, parent);
2309fe4c797SJerome Forissier 	if (n < 1 || n > 2)
231df7cecc0SLionel Debieve 		return DT_INFO_INVALID_REG_SIZE;
2329fe4c797SJerome Forissier 
233a2e8c036SGatien Chevallier 	return fdt_read_size(reg, n);
2349fe4c797SJerome Forissier }
2359fe4c797SJerome Forissier 
2369fe4c797SJerome Forissier static bool is_okay(const char *st, int len)
2379fe4c797SJerome Forissier {
2389fe4c797SJerome Forissier 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
2399fe4c797SJerome Forissier }
2409fe4c797SJerome Forissier 
241f354a5d8SGatien Chevallier int fdt_get_status(const void *fdt, int offs)
2429fe4c797SJerome Forissier {
2439fe4c797SJerome Forissier 	const char *prop;
2449fe4c797SJerome Forissier 	int st = 0;
2459fe4c797SJerome Forissier 	int len;
2469fe4c797SJerome Forissier 
2479fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "status", &len);
2489fe4c797SJerome Forissier 	if (!prop || is_okay(prop, len)) {
2499fe4c797SJerome Forissier 		/* If status is not specified, it defaults to "okay" */
2509fe4c797SJerome Forissier 		st |= DT_STATUS_OK_NSEC;
2519fe4c797SJerome Forissier 	}
2529fe4c797SJerome Forissier 
2539fe4c797SJerome Forissier 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
2549fe4c797SJerome Forissier 	if (!prop) {
2559fe4c797SJerome Forissier 		/*
2569fe4c797SJerome Forissier 		 * When secure-status is not specified it defaults to the same
2579fe4c797SJerome Forissier 		 * value as status
2589fe4c797SJerome Forissier 		 */
2599fe4c797SJerome Forissier 		if (st & DT_STATUS_OK_NSEC)
2609fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2619fe4c797SJerome Forissier 	} else {
2629fe4c797SJerome Forissier 		if (is_okay(prop, len))
2639fe4c797SJerome Forissier 			st |= DT_STATUS_OK_SEC;
2649fe4c797SJerome Forissier 	}
2659fe4c797SJerome Forissier 
2669fe4c797SJerome Forissier 	return st;
2679fe4c797SJerome Forissier }
268c0cfb36cSEtienne Carriere 
269f354a5d8SGatien Chevallier void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, int offs)
270c0cfb36cSEtienne Carriere {
271c0cfb36cSEtienne Carriere 	struct dt_node_info dinfo = {
272c0cfb36cSEtienne Carriere 		.reg = DT_INFO_INVALID_REG,
27306fd21ddSLionel Debieve 		.reg_size = DT_INFO_INVALID_REG_SIZE,
274c0cfb36cSEtienne Carriere 		.clock = DT_INFO_INVALID_CLOCK,
275c0cfb36cSEtienne Carriere 		.reset = DT_INFO_INVALID_RESET,
2767acb3a47SLudovic Barre 		.interrupt = DT_INFO_INVALID_INTERRUPT,
277c0cfb36cSEtienne Carriere 	};
278c0cfb36cSEtienne Carriere 	const fdt32_t *cuint;
279c0cfb36cSEtienne Carriere 
280f354a5d8SGatien Chevallier 	dinfo.reg = fdt_reg_base_address(fdt, offs);
281f354a5d8SGatien Chevallier 	dinfo.reg_size = fdt_reg_size(fdt, offs);
282c0cfb36cSEtienne Carriere 
283c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "clocks", NULL);
284c0cfb36cSEtienne Carriere 	if (cuint) {
285c0cfb36cSEtienne Carriere 		cuint++;
286c0cfb36cSEtienne Carriere 		dinfo.clock = (int)fdt32_to_cpu(*cuint);
287c0cfb36cSEtienne Carriere 	}
288c0cfb36cSEtienne Carriere 
289c0cfb36cSEtienne Carriere 	cuint = fdt_getprop(fdt, offs, "resets", NULL);
290c0cfb36cSEtienne Carriere 	if (cuint) {
291c0cfb36cSEtienne Carriere 		cuint++;
292c0cfb36cSEtienne Carriere 		dinfo.reset = (int)fdt32_to_cpu(*cuint);
293c0cfb36cSEtienne Carriere 	}
294c0cfb36cSEtienne Carriere 
295702fe5a7SClément Léger 	dinfo.interrupt = dt_get_irq_type_prio(fdt, offs, &dinfo.type,
296702fe5a7SClément Léger 					       &dinfo.prio);
2977acb3a47SLudovic Barre 
298f354a5d8SGatien Chevallier 	dinfo.status = fdt_get_status(fdt, offs);
299c0cfb36cSEtienne Carriere 
300c0cfb36cSEtienne Carriere 	*info = dinfo;
301c0cfb36cSEtienne Carriere }
302876826f3SGabriel Fernandez 
303f354a5d8SGatien Chevallier int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
304876826f3SGabriel Fernandez 			  uint32_t *array, size_t count)
305876826f3SGabriel Fernandez {
306876826f3SGabriel Fernandez 	const fdt32_t *cuint = NULL;
307876826f3SGabriel Fernandez 	int len = 0;
308876826f3SGabriel Fernandez 	uint32_t i = 0;
309876826f3SGabriel Fernandez 
310876826f3SGabriel Fernandez 	cuint = fdt_getprop(fdt, node, prop_name, &len);
311876826f3SGabriel Fernandez 	if (!cuint)
312876826f3SGabriel Fernandez 		return -FDT_ERR_NOTFOUND;
313876826f3SGabriel Fernandez 
314876826f3SGabriel Fernandez 	if ((uint32_t)len != (count * sizeof(uint32_t)))
315876826f3SGabriel Fernandez 		return -FDT_ERR_BADLAYOUT;
316876826f3SGabriel Fernandez 
317876826f3SGabriel Fernandez 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
318876826f3SGabriel Fernandez 		*array = fdt32_to_cpu(*cuint);
319876826f3SGabriel Fernandez 		array++;
320876826f3SGabriel Fernandez 		cuint++;
321876826f3SGabriel Fernandez 	}
322876826f3SGabriel Fernandez 
323876826f3SGabriel Fernandez 	return 0;
324876826f3SGabriel Fernandez }
325876826f3SGabriel Fernandez 
3267c3a6b7bSGatien Chevallier int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
3277c3a6b7bSGatien Chevallier 			  int index, uint32_t *value)
3287c3a6b7bSGatien Chevallier {
3297c3a6b7bSGatien Chevallier 	const fdt32_t *cuint = NULL;
3307c3a6b7bSGatien Chevallier 	int len = 0;
3317c3a6b7bSGatien Chevallier 
3327c3a6b7bSGatien Chevallier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
3337c3a6b7bSGatien Chevallier 	if (!cuint)
3347c3a6b7bSGatien Chevallier 		return len;
3357c3a6b7bSGatien Chevallier 
3367c3a6b7bSGatien Chevallier 	if ((uint32_t)len < (sizeof(uint32_t) * (index + 1)))
3377c3a6b7bSGatien Chevallier 		return -FDT_ERR_BADLAYOUT;
3387c3a6b7bSGatien Chevallier 
3397c3a6b7bSGatien Chevallier 	*value = fdt32_to_cpu(cuint[index]);
3407c3a6b7bSGatien Chevallier 
3417c3a6b7bSGatien Chevallier 	return 0;
3427c3a6b7bSGatien Chevallier }
3437c3a6b7bSGatien Chevallier 
344f354a5d8SGatien Chevallier int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
345876826f3SGabriel Fernandez 		    uint32_t *value)
346876826f3SGabriel Fernandez {
347f354a5d8SGatien Chevallier 	return fdt_read_uint32_array(fdt, node, prop_name, value, 1);
348876826f3SGabriel Fernandez }
349876826f3SGabriel Fernandez 
350f354a5d8SGatien Chevallier uint32_t fdt_read_uint32_default(const void *fdt, int node,
351876826f3SGabriel Fernandez 				 const char *prop_name, uint32_t dflt_value)
352876826f3SGabriel Fernandez {
3537c3a6b7bSGatien Chevallier 	uint32_t ret = dflt_value;
354876826f3SGabriel Fernandez 
3557c3a6b7bSGatien Chevallier 	fdt_read_uint32_index(fdt, node, prop_name, 0, &ret);
356876826f3SGabriel Fernandez 
3577c3a6b7bSGatien Chevallier 	return ret;
358876826f3SGabriel Fernandez }
359*07ced948SGatien Chevallier 
360*07ced948SGatien Chevallier int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
361*07ced948SGatien Chevallier 			       paddr_t *base, size_t *size)
362*07ced948SGatien Chevallier {
363*07ced948SGatien Chevallier 	const fdt32_t *prop = NULL;
364*07ced948SGatien Chevallier 	int parent = 0;
365*07ced948SGatien Chevallier 	int len = 0;
366*07ced948SGatien Chevallier 	int address_cells = 0;
367*07ced948SGatien Chevallier 	int size_cells = 0;
368*07ced948SGatien Chevallier 	int cell = 0;
369*07ced948SGatien Chevallier 
370*07ced948SGatien Chevallier 	parent = fdt_parent_offset(fdt, node);
371*07ced948SGatien Chevallier 	if (parent < 0)
372*07ced948SGatien Chevallier 		return parent;
373*07ced948SGatien Chevallier 
374*07ced948SGatien Chevallier 	address_cells = fdt_address_cells(fdt, parent);
375*07ced948SGatien Chevallier 	if (address_cells < 0)
376*07ced948SGatien Chevallier 		return address_cells;
377*07ced948SGatien Chevallier 
378*07ced948SGatien Chevallier 	size_cells = fdt_size_cells(fdt, parent);
379*07ced948SGatien Chevallier 	if (size_cells < 0)
380*07ced948SGatien Chevallier 		return size_cells;
381*07ced948SGatien Chevallier 
382*07ced948SGatien Chevallier 	cell = index * (address_cells + size_cells);
383*07ced948SGatien Chevallier 
384*07ced948SGatien Chevallier 	prop = fdt_getprop(fdt, node, "reg", &len);
385*07ced948SGatien Chevallier 	if (!prop)
386*07ced948SGatien Chevallier 		return len;
387*07ced948SGatien Chevallier 
388*07ced948SGatien Chevallier 	if (((cell + address_cells + size_cells) * (int)sizeof(uint32_t)) > len)
389*07ced948SGatien Chevallier 		return -FDT_ERR_BADVALUE;
390*07ced948SGatien Chevallier 
391*07ced948SGatien Chevallier 	if (base) {
392*07ced948SGatien Chevallier 		*base = fdt_read_paddr(&prop[cell], address_cells);
393*07ced948SGatien Chevallier 		if (*base == DT_INFO_INVALID_REG)
394*07ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
395*07ced948SGatien Chevallier 	}
396*07ced948SGatien Chevallier 
397*07ced948SGatien Chevallier 	if (size) {
398*07ced948SGatien Chevallier 		*size = fdt_read_size(&prop[cell + address_cells], size_cells);
399*07ced948SGatien Chevallier 		if (*size == DT_INFO_INVALID_REG_SIZE)
400*07ced948SGatien Chevallier 			return -FDT_ERR_BADVALUE;
401*07ced948SGatien Chevallier 	}
402*07ced948SGatien Chevallier 
403*07ced948SGatien Chevallier 	return 0;
404*07ced948SGatien Chevallier }
405*07ced948SGatien Chevallier 
406*07ced948SGatien Chevallier int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
407*07ced948SGatien Chevallier 			      paddr_t *base, size_t *size)
408*07ced948SGatien Chevallier {
409*07ced948SGatien Chevallier 	int index = 0;
410*07ced948SGatien Chevallier 
411*07ced948SGatien Chevallier 	index = fdt_stringlist_search(fdt, node, "reg-names", name);
412*07ced948SGatien Chevallier 	if (index < 0)
413*07ced948SGatien Chevallier 		return index;
414*07ced948SGatien Chevallier 
415*07ced948SGatien Chevallier 	return fdt_get_reg_props_by_index(fdt, node, index, base, size);
416*07ced948SGatien Chevallier }
417