xref: /rk3399_rockchip-uboot/lib/fdtdec.c (revision 0bd4e39d2ba477f3c274aa233f5c2e1d25dbaa74)
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  * SPDX-License-Identifier:	GPL-2.0+
4  */
5 
6 #ifndef USE_HOSTCC
7 #include <common.h>
8 #include <errno.h>
9 #include <serial.h>
10 #include <libfdt.h>
11 #include <fdtdec.h>
12 #include <linux/ctype.h>
13 
14 #include <asm/gpio.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 /*
19  * Here are the type we know about. One day we might allow drivers to
20  * register. For now we just put them here. The COMPAT macro allows us to
21  * turn this into a sparse list later, and keeps the ID with the name.
22  */
23 #define COMPAT(id, name) name
24 static const char * const compat_names[COMPAT_COUNT] = {
25 	COMPAT(UNKNOWN, "<none>"),
26 	COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
27 	COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"),
28 	COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"),
29 	COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
30 	COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
31 	COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
32 	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
33 	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
34 	COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
35 	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
36 	COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
37 	COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
38 	COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
39 	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
40 	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
41 	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
42 	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
43 	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
44 	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
45 	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
46 	COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
47 	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
48 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
49 	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
50 	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
51 	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
52 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
53 	COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
54 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
55 	COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
56 	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
57 	COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"),
58 	COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"),
59 	COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"),
60 	COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
61 	COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"),
62 	COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
63 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
64 	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
65 	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
66 	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
67 	COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"),
68 	COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
69 	COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"),
70 	COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
71 	COMPAT(TI_TPS65090, "ti,tps65090"),
72 	COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"),
73 	COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
74 	COMPAT(PARADE_PS8625, "parade,ps8625"),
75 	COMPAT(COMPAT_INTEL_LPC, "intel,lpc"),
76 	COMPAT(INTEL_MICROCODE, "intel,microcode"),
77 	COMPAT(MEMORY_SPD, "memory-spd"),
78 };
79 
80 const char *fdtdec_get_compatible(enum fdt_compat_id id)
81 {
82 	/* We allow reading of the 'unknown' ID for testing purposes */
83 	assert(id >= 0 && id < COMPAT_COUNT);
84 	return compat_names[id];
85 }
86 
87 fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
88 		const char *prop_name, fdt_size_t *sizep)
89 {
90 	const fdt_addr_t *cell;
91 	int len;
92 
93 	debug("%s: %s: ", __func__, prop_name);
94 	cell = fdt_getprop(blob, node, prop_name, &len);
95 	if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
96 		     len == sizeof(fdt_addr_t) * 2)) {
97 		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
98 		if (sizep) {
99 			const fdt_size_t *size;
100 
101 			size = (fdt_size_t *)((char *)cell +
102 					sizeof(fdt_addr_t));
103 			*sizep = fdt_size_to_cpu(*size);
104 			debug("addr=%08lx, size=%08x\n",
105 			      (ulong)addr, *sizep);
106 		} else {
107 			debug("%08lx\n", (ulong)addr);
108 		}
109 		return addr;
110 	}
111 	debug("(not found)\n");
112 	return FDT_ADDR_T_NONE;
113 }
114 
115 fdt_addr_t fdtdec_get_addr(const void *blob, int node,
116 		const char *prop_name)
117 {
118 	return fdtdec_get_addr_size(blob, node, prop_name, NULL);
119 }
120 
121 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
122 		uint64_t default_val)
123 {
124 	const uint64_t *cell64;
125 	int length;
126 
127 	cell64 = fdt_getprop(blob, node, prop_name, &length);
128 	if (!cell64 || length < sizeof(*cell64))
129 		return default_val;
130 
131 	return fdt64_to_cpu(*cell64);
132 }
133 
134 int fdtdec_get_is_enabled(const void *blob, int node)
135 {
136 	const char *cell;
137 
138 	/*
139 	 * It should say "okay", so only allow that. Some fdts use "ok" but
140 	 * this is a bug. Please fix your device tree source file. See here
141 	 * for discussion:
142 	 *
143 	 * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html
144 	 */
145 	cell = fdt_getprop(blob, node, "status", NULL);
146 	if (cell)
147 		return 0 == strcmp(cell, "okay");
148 	return 1;
149 }
150 
151 enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
152 {
153 	enum fdt_compat_id id;
154 
155 	/* Search our drivers */
156 	for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++)
157 		if (0 == fdt_node_check_compatible(blob, node,
158 				compat_names[id]))
159 			return id;
160 	return COMPAT_UNKNOWN;
161 }
162 
163 int fdtdec_next_compatible(const void *blob, int node,
164 		enum fdt_compat_id id)
165 {
166 	return fdt_node_offset_by_compatible(blob, node, compat_names[id]);
167 }
168 
169 int fdtdec_next_compatible_subnode(const void *blob, int node,
170 		enum fdt_compat_id id, int *depthp)
171 {
172 	do {
173 		node = fdt_next_node(blob, node, depthp);
174 	} while (*depthp > 1);
175 
176 	/* If this is a direct subnode, and compatible, return it */
177 	if (*depthp == 1 && 0 == fdt_node_check_compatible(
178 						blob, node, compat_names[id]))
179 		return node;
180 
181 	return -FDT_ERR_NOTFOUND;
182 }
183 
184 int fdtdec_next_alias(const void *blob, const char *name,
185 		enum fdt_compat_id id, int *upto)
186 {
187 #define MAX_STR_LEN 20
188 	char str[MAX_STR_LEN + 20];
189 	int node, err;
190 
191 	/* snprintf() is not available */
192 	assert(strlen(name) < MAX_STR_LEN);
193 	sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
194 	node = fdt_path_offset(blob, str);
195 	if (node < 0)
196 		return node;
197 	err = fdt_node_check_compatible(blob, node, compat_names[id]);
198 	if (err < 0)
199 		return err;
200 	if (err)
201 		return -FDT_ERR_NOTFOUND;
202 	(*upto)++;
203 	return node;
204 }
205 
206 int fdtdec_find_aliases_for_id(const void *blob, const char *name,
207 			enum fdt_compat_id id, int *node_list, int maxcount)
208 {
209 	memset(node_list, '\0', sizeof(*node_list) * maxcount);
210 
211 	return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount);
212 }
213 
214 /* TODO: Can we tighten this code up a little? */
215 int fdtdec_add_aliases_for_id(const void *blob, const char *name,
216 			enum fdt_compat_id id, int *node_list, int maxcount)
217 {
218 	int name_len = strlen(name);
219 	int nodes[maxcount];
220 	int num_found = 0;
221 	int offset, node;
222 	int alias_node;
223 	int count;
224 	int i, j;
225 
226 	/* find the alias node if present */
227 	alias_node = fdt_path_offset(blob, "/aliases");
228 
229 	/*
230 	 * start with nothing, and we can assume that the root node can't
231 	 * match
232 	 */
233 	memset(nodes, '\0', sizeof(nodes));
234 
235 	/* First find all the compatible nodes */
236 	for (node = count = 0; node >= 0 && count < maxcount;) {
237 		node = fdtdec_next_compatible(blob, node, id);
238 		if (node >= 0)
239 			nodes[count++] = node;
240 	}
241 	if (node >= 0)
242 		debug("%s: warning: maxcount exceeded with alias '%s'\n",
243 		       __func__, name);
244 
245 	/* Now find all the aliases */
246 	for (offset = fdt_first_property_offset(blob, alias_node);
247 			offset > 0;
248 			offset = fdt_next_property_offset(blob, offset)) {
249 		const struct fdt_property *prop;
250 		const char *path;
251 		int number;
252 		int found;
253 
254 		node = 0;
255 		prop = fdt_get_property_by_offset(blob, offset, NULL);
256 		path = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
257 		if (prop->len && 0 == strncmp(path, name, name_len))
258 			node = fdt_path_offset(blob, prop->data);
259 		if (node <= 0)
260 			continue;
261 
262 		/* Get the alias number */
263 		number = simple_strtoul(path + name_len, NULL, 10);
264 		if (number < 0 || number >= maxcount) {
265 			debug("%s: warning: alias '%s' is out of range\n",
266 			       __func__, path);
267 			continue;
268 		}
269 
270 		/* Make sure the node we found is actually in our list! */
271 		found = -1;
272 		for (j = 0; j < count; j++)
273 			if (nodes[j] == node) {
274 				found = j;
275 				break;
276 			}
277 
278 		if (found == -1) {
279 			debug("%s: warning: alias '%s' points to a node "
280 				"'%s' that is missing or is not compatible "
281 				" with '%s'\n", __func__, path,
282 				fdt_get_name(blob, node, NULL),
283 			       compat_names[id]);
284 			continue;
285 		}
286 
287 		/*
288 		 * Add this node to our list in the right place, and mark
289 		 * it as done.
290 		 */
291 		if (fdtdec_get_is_enabled(blob, node)) {
292 			if (node_list[number]) {
293 				debug("%s: warning: alias '%s' requires that "
294 				      "a node be placed in the list in a "
295 				      "position which is already filled by "
296 				      "node '%s'\n", __func__, path,
297 				      fdt_get_name(blob, node, NULL));
298 				continue;
299 			}
300 			node_list[number] = node;
301 			if (number >= num_found)
302 				num_found = number + 1;
303 		}
304 		nodes[found] = 0;
305 	}
306 
307 	/* Add any nodes not mentioned by an alias */
308 	for (i = j = 0; i < maxcount; i++) {
309 		if (!node_list[i]) {
310 			for (; j < maxcount; j++)
311 				if (nodes[j] &&
312 					fdtdec_get_is_enabled(blob, nodes[j]))
313 					break;
314 
315 			/* Have we run out of nodes to add? */
316 			if (j == maxcount)
317 				break;
318 
319 			assert(!node_list[i]);
320 			node_list[i] = nodes[j++];
321 			if (i >= num_found)
322 				num_found = i + 1;
323 		}
324 	}
325 
326 	return num_found;
327 }
328 
329 int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
330 			 int *seqp)
331 {
332 	int base_len = strlen(base);
333 	const char *find_name;
334 	int find_namelen;
335 	int prop_offset;
336 	int aliases;
337 
338 	find_name = fdt_get_name(blob, offset, &find_namelen);
339 	debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);
340 
341 	aliases = fdt_path_offset(blob, "/aliases");
342 	for (prop_offset = fdt_first_property_offset(blob, aliases);
343 	     prop_offset > 0;
344 	     prop_offset = fdt_next_property_offset(blob, prop_offset)) {
345 		const char *prop;
346 		const char *name;
347 		const char *slash;
348 		const char *p;
349 		int len;
350 
351 		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
352 		debug("   - %s, %s\n", name, prop);
353 		if (len < find_namelen || *prop != '/' || prop[len - 1] ||
354 		    strncmp(name, base, base_len))
355 			continue;
356 
357 		slash = strrchr(prop, '/');
358 		if (strcmp(slash + 1, find_name))
359 			continue;
360 		for (p = name + strlen(name) - 1; p > name; p--) {
361 			if (!isdigit(*p)) {
362 				*seqp = simple_strtoul(p + 1, NULL, 10);
363 				debug("Found seq %d\n", *seqp);
364 				return 0;
365 			}
366 		}
367 	}
368 
369 	debug("Not found\n");
370 	return -ENOENT;
371 }
372 
373 int fdtdec_get_chosen_node(const void *blob, const char *name)
374 {
375 	const char *prop;
376 	int chosen_node;
377 	int len;
378 
379 	if (!blob)
380 		return -FDT_ERR_NOTFOUND;
381 	chosen_node = fdt_path_offset(blob, "/chosen");
382 	prop = fdt_getprop(blob, chosen_node, name, &len);
383 	if (!prop)
384 		return -FDT_ERR_NOTFOUND;
385 	return fdt_path_offset(blob, prop);
386 }
387 
388 int fdtdec_check_fdt(void)
389 {
390 	/*
391 	 * We must have an FDT, but we cannot panic() yet since the console
392 	 * is not ready. So for now, just assert(). Boards which need an early
393 	 * FDT (prior to console ready) will need to make their own
394 	 * arrangements and do their own checks.
395 	 */
396 	assert(!fdtdec_prepare_fdt());
397 	return 0;
398 }
399 
400 /*
401  * This function is a little odd in that it accesses global data. At some
402  * point if the architecture board.c files merge this will make more sense.
403  * Even now, it is common code.
404  */
405 int fdtdec_prepare_fdt(void)
406 {
407 	if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
408 	    fdt_check_header(gd->fdt_blob)) {
409 		printf("No valid FDT found - please append one to U-Boot "
410 			"binary, use u-boot-dtb.bin or define "
411 			"CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
412 		return -1;
413 	}
414 	return 0;
415 }
416 
417 int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
418 {
419 	const u32 *phandle;
420 	int lookup;
421 
422 	debug("%s: %s\n", __func__, prop_name);
423 	phandle = fdt_getprop(blob, node, prop_name, NULL);
424 	if (!phandle)
425 		return -FDT_ERR_NOTFOUND;
426 
427 	lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle));
428 	return lookup;
429 }
430 
431 /**
432  * Look up a property in a node and check that it has a minimum length.
433  *
434  * @param blob		FDT blob
435  * @param node		node to examine
436  * @param prop_name	name of property to find
437  * @param min_len	minimum property length in bytes
438  * @param err		0 if ok, or -FDT_ERR_NOTFOUND if the property is not
439 			found, or -FDT_ERR_BADLAYOUT if not enough data
440  * @return pointer to cell, which is only valid if err == 0
441  */
442 static const void *get_prop_check_min_len(const void *blob, int node,
443 		const char *prop_name, int min_len, int *err)
444 {
445 	const void *cell;
446 	int len;
447 
448 	debug("%s: %s\n", __func__, prop_name);
449 	cell = fdt_getprop(blob, node, prop_name, &len);
450 	if (!cell)
451 		*err = -FDT_ERR_NOTFOUND;
452 	else if (len < min_len)
453 		*err = -FDT_ERR_BADLAYOUT;
454 	else
455 		*err = 0;
456 	return cell;
457 }
458 
459 int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
460 		u32 *array, int count)
461 {
462 	const u32 *cell;
463 	int i, err = 0;
464 
465 	debug("%s: %s\n", __func__, prop_name);
466 	cell = get_prop_check_min_len(blob, node, prop_name,
467 				      sizeof(u32) * count, &err);
468 	if (!err) {
469 		for (i = 0; i < count; i++)
470 			array[i] = fdt32_to_cpu(cell[i]);
471 	}
472 	return err;
473 }
474 
475 int fdtdec_get_int_array_count(const void *blob, int node,
476 			       const char *prop_name, u32 *array, int count)
477 {
478 	const u32 *cell;
479 	int len, elems;
480 	int i;
481 
482 	debug("%s: %s\n", __func__, prop_name);
483 	cell = fdt_getprop(blob, node, prop_name, &len);
484 	if (!cell)
485 		return -FDT_ERR_NOTFOUND;
486 	elems = len / sizeof(u32);
487 	if (count > elems)
488 		count = elems;
489 	for (i = 0; i < count; i++)
490 		array[i] = fdt32_to_cpu(cell[i]);
491 
492 	return count;
493 }
494 
495 const u32 *fdtdec_locate_array(const void *blob, int node,
496 			       const char *prop_name, int count)
497 {
498 	const u32 *cell;
499 	int err;
500 
501 	cell = get_prop_check_min_len(blob, node, prop_name,
502 				      sizeof(u32) * count, &err);
503 	return err ? NULL : cell;
504 }
505 
506 int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
507 {
508 	const s32 *cell;
509 	int len;
510 
511 	debug("%s: %s\n", __func__, prop_name);
512 	cell = fdt_getprop(blob, node, prop_name, &len);
513 	return cell != NULL;
514 }
515 
516 /**
517  * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
518  * terminating item.
519  *
520  * @param blob		FDT blob to use
521  * @param node		Node to look at
522  * @param prop_name	Node property name
523  * @param gpio		Array of gpio elements to fill from FDT. This will be
524  *			untouched if either 0 or an error is returned
525  * @param max_count	Maximum number of elements allowed
526  * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
527  * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
528  */
529 int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
530 		struct fdt_gpio_state *gpio, int max_count)
531 {
532 	const struct fdt_property *prop;
533 	const u32 *cell;
534 	const char *name;
535 	int len, i;
536 
537 	debug("%s: %s\n", __func__, prop_name);
538 	assert(max_count > 0);
539 	prop = fdt_get_property(blob, node, prop_name, &len);
540 	if (!prop) {
541 		debug("%s: property '%s' missing\n", __func__, prop_name);
542 		return -FDT_ERR_NOTFOUND;
543 	}
544 
545 	/* We will use the name to tag the GPIO */
546 	name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
547 	cell = (u32 *)prop->data;
548 	len /= sizeof(u32) * 3;		/* 3 cells per GPIO record */
549 	if (len > max_count) {
550 		debug(" %s: too many GPIOs / cells for "
551 			"property '%s'\n", __func__, prop_name);
552 		return -FDT_ERR_BADLAYOUT;
553 	}
554 
555 	/* Read out the GPIO data from the cells */
556 	for (i = 0; i < len; i++, cell += 3) {
557 		gpio[i].gpio = fdt32_to_cpu(cell[1]);
558 		gpio[i].flags = fdt32_to_cpu(cell[2]);
559 		gpio[i].name = name;
560 	}
561 
562 	return len;
563 }
564 
565 int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
566 		struct fdt_gpio_state *gpio)
567 {
568 	int err;
569 
570 	debug("%s: %s\n", __func__, prop_name);
571 	gpio->gpio = FDT_GPIO_NONE;
572 	gpio->name = NULL;
573 	err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1);
574 	return err == 1 ? 0 : err;
575 }
576 
577 int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
578 {
579 	int val;
580 
581 	if (!fdt_gpio_isvalid(gpio))
582 		return -1;
583 
584 	val = gpio_get_value(gpio->gpio);
585 	return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
586 }
587 
588 int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
589 {
590 	if (!fdt_gpio_isvalid(gpio))
591 		return -1;
592 
593 	val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
594 	return gpio_set_value(gpio->gpio, val);
595 }
596 
597 int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
598 {
599 	/*
600 	 * Return success if there is no GPIO defined. This is used for
601 	 * optional GPIOs)
602 	 */
603 	if (!fdt_gpio_isvalid(gpio))
604 		return 0;
605 
606 	if (gpio_request(gpio->gpio, gpio->name))
607 		return -1;
608 	return 0;
609 }
610 
611 int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
612 		u8 *array, int count)
613 {
614 	const u8 *cell;
615 	int err;
616 
617 	cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
618 	if (!err)
619 		memcpy(array, cell, count);
620 	return err;
621 }
622 
623 const u8 *fdtdec_locate_byte_array(const void *blob, int node,
624 			     const char *prop_name, int count)
625 {
626 	const u8 *cell;
627 	int err;
628 
629 	cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
630 	if (err)
631 		return NULL;
632 	return cell;
633 }
634 
635 int fdtdec_get_config_int(const void *blob, const char *prop_name,
636 		int default_val)
637 {
638 	int config_node;
639 
640 	debug("%s: %s\n", __func__, prop_name);
641 	config_node = fdt_path_offset(blob, "/config");
642 	if (config_node < 0)
643 		return default_val;
644 	return fdtdec_get_int(blob, config_node, prop_name, default_val);
645 }
646 
647 int fdtdec_get_config_bool(const void *blob, const char *prop_name)
648 {
649 	int config_node;
650 	const void *prop;
651 
652 	debug("%s: %s\n", __func__, prop_name);
653 	config_node = fdt_path_offset(blob, "/config");
654 	if (config_node < 0)
655 		return 0;
656 	prop = fdt_get_property(blob, config_node, prop_name, NULL);
657 
658 	return prop != NULL;
659 }
660 
661 char *fdtdec_get_config_string(const void *blob, const char *prop_name)
662 {
663 	const char *nodep;
664 	int nodeoffset;
665 	int len;
666 
667 	debug("%s: %s\n", __func__, prop_name);
668 	nodeoffset = fdt_path_offset(blob, "/config");
669 	if (nodeoffset < 0)
670 		return NULL;
671 
672 	nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
673 	if (!nodep)
674 		return NULL;
675 
676 	return (char *)nodep;
677 }
678 
679 int fdtdec_decode_region(const void *blob, int node, const char *prop_name,
680 			 fdt_addr_t *basep, fdt_size_t *sizep)
681 {
682 	const fdt_addr_t *cell;
683 	int len;
684 
685 	debug("%s: %s: %s\n", __func__, fdt_get_name(blob, node, NULL),
686 	      prop_name);
687 	cell = fdt_getprop(blob, node, prop_name, &len);
688 	if (!cell || (len < sizeof(fdt_addr_t) * 2)) {
689 		debug("cell=%p, len=%d\n", cell, len);
690 		return -1;
691 	}
692 
693 	*basep = fdt_addr_to_cpu(*cell);
694 	*sizep = fdt_size_to_cpu(cell[1]);
695 	debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep,
696 	      (ulong)*sizep);
697 
698 	return 0;
699 }
700 
701 /**
702  * Read a flash entry from the fdt
703  *
704  * @param blob		FDT blob
705  * @param node		Offset of node to read
706  * @param name		Name of node being read
707  * @param entry		Place to put offset and size of this node
708  * @return 0 if ok, -ve on error
709  */
710 int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
711 			   struct fmap_entry *entry)
712 {
713 	const char *prop;
714 	u32 reg[2];
715 
716 	if (fdtdec_get_int_array(blob, node, "reg", reg, 2)) {
717 		debug("Node '%s' has bad/missing 'reg' property\n", name);
718 		return -FDT_ERR_NOTFOUND;
719 	}
720 	entry->offset = reg[0];
721 	entry->length = reg[1];
722 	entry->used = fdtdec_get_int(blob, node, "used", entry->length);
723 	prop = fdt_getprop(blob, node, "compress", NULL);
724 	entry->compress_algo = prop && !strcmp(prop, "lzo") ?
725 		FMAP_COMPRESS_LZO : FMAP_COMPRESS_NONE;
726 	prop = fdt_getprop(blob, node, "hash", &entry->hash_size);
727 	entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
728 	entry->hash = (uint8_t *)prop;
729 
730 	return 0;
731 }
732 
733 static u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
734 {
735 	u64 number = 0;
736 
737 	while (cells--)
738 		number = (number << 32) | fdt32_to_cpu(*ptr++);
739 
740 	return number;
741 }
742 
743 int fdt_get_resource(const void *fdt, int node, const char *property,
744 		     unsigned int index, struct fdt_resource *res)
745 {
746 	const fdt32_t *ptr, *end;
747 	int na, ns, len, parent;
748 	unsigned int i = 0;
749 
750 	parent = fdt_parent_offset(fdt, node);
751 	if (parent < 0)
752 		return parent;
753 
754 	na = fdt_address_cells(fdt, parent);
755 	ns = fdt_size_cells(fdt, parent);
756 
757 	ptr = fdt_getprop(fdt, node, property, &len);
758 	if (!ptr)
759 		return len;
760 
761 	end = ptr + len / sizeof(*ptr);
762 
763 	while (ptr + na + ns <= end) {
764 		if (i == index) {
765 			res->start = res->end = fdtdec_get_number(ptr, na);
766 			res->end += fdtdec_get_number(&ptr[na], ns) - 1;
767 			return 0;
768 		}
769 
770 		ptr += na + ns;
771 		i++;
772 	}
773 
774 	return -FDT_ERR_NOTFOUND;
775 }
776 
777 int fdt_get_named_resource(const void *fdt, int node, const char *property,
778 			   const char *prop_names, const char *name,
779 			   struct fdt_resource *res)
780 {
781 	int index;
782 
783 	index = fdt_find_string(fdt, node, prop_names, name);
784 	if (index < 0)
785 		return index;
786 
787 	return fdt_get_resource(fdt, node, property, index, res);
788 }
789 
790 int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf)
791 {
792 	const fdt32_t *prop;
793 	int len;
794 
795 	prop = fdt_getprop(fdt, node, "reg", &len);
796 	if (!prop)
797 		return len;
798 
799 	*bdf = fdt32_to_cpu(*prop) & 0xffffff;
800 
801 	return 0;
802 }
803 
804 int fdtdec_decode_memory_region(const void *blob, int config_node,
805 				const char *mem_type, const char *suffix,
806 				fdt_addr_t *basep, fdt_size_t *sizep)
807 {
808 	char prop_name[50];
809 	const char *mem;
810 	fdt_size_t size, offset_size;
811 	fdt_addr_t base, offset;
812 	int node;
813 
814 	if (config_node == -1) {
815 		config_node = fdt_path_offset(blob, "/config");
816 		if (config_node < 0) {
817 			debug("%s: Cannot find /config node\n", __func__);
818 			return -ENOENT;
819 		}
820 	}
821 	if (!suffix)
822 		suffix = "";
823 
824 	snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type,
825 		 suffix);
826 	mem = fdt_getprop(blob, config_node, prop_name, NULL);
827 	if (!mem) {
828 		debug("%s: No memory type for '%s', using /memory\n", __func__,
829 		      prop_name);
830 		mem = "/memory";
831 	}
832 
833 	node = fdt_path_offset(blob, mem);
834 	if (node < 0) {
835 		debug("%s: Failed to find node '%s': %s\n", __func__, mem,
836 		      fdt_strerror(node));
837 		return -ENOENT;
838 	}
839 
840 	/*
841 	 * Not strictly correct - the memory may have multiple banks. We just
842 	 * use the first
843 	 */
844 	if (fdtdec_decode_region(blob, node, "reg", &base, &size)) {
845 		debug("%s: Failed to decode memory region %s\n", __func__,
846 		      mem);
847 		return -EINVAL;
848 	}
849 
850 	snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type,
851 		 suffix);
852 	if (fdtdec_decode_region(blob, config_node, prop_name, &offset,
853 				 &offset_size)) {
854 		debug("%s: Failed to decode memory region '%s'\n", __func__,
855 		      prop_name);
856 		return -EINVAL;
857 	}
858 
859 	*basep = base + offset;
860 	*sizep = offset_size;
861 
862 	return 0;
863 }
864 #endif
865