Blame view

lib/fdtdec.c 16.2 KB
b5220bc6e   Simon Glass   fdt: add decode h...
1
2
  /*
   * Copyright (c) 2011 The Chromium OS Authors.
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
3
   * SPDX-License-Identifier:	GPL-2.0+
b5220bc6e   Simon Glass   fdt: add decode h...
4
5
6
7
8
9
   */
  
  #include <common.h>
  #include <serial.h>
  #include <libfdt.h>
  #include <fdtdec.h>
e46431e19   Michal Simek   fdt: Include arch...
10
  #include <asm/gpio.h>
ed3ee5cd0   Simon Glass   fdt: Add basic su...
11

b5220bc6e   Simon Glass   fdt: add decode h...
12
13
14
15
16
17
18
19
20
  DECLARE_GLOBAL_DATA_PTR;
  
  /*
   * Here are the type we know about. One day we might allow drivers to
   * register. For now we just put them here. The COMPAT macro allows us to
   * turn this into a sparse list later, and keeps the ID with the name.
   */
  #define COMPAT(id, name) name
  static const char * const compat_names[COMPAT_COUNT] = {
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
21
  	COMPAT(UNKNOWN, "<none>"),
87f938c9f   Simon Glass   tegra: usb: Add s...
22
  	COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
7e44d9320   Jim Lin   ARM: Tegra: USB: ...
23
24
  	COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"),
  	COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"),
e32624ef8   Tom Warren   Tegra: I2C: Add T...
25
  	COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
96a78ac0c   Yen Lin   tegra: i2c: Add I...
26
27
  	COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
  	COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
0e35ad053   Jimmy Zhang   tegra: Add EMC su...
28
29
  	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
  	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
6642a681e   Rakesh Iyer   tegra: Add tegra ...
30
  	COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
312693c3d   Jim Lin   tegra: nand: Add ...
31
  	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
e1ae0d1f7   Simon Glass   tegra: Add suppor...
32
  	COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
87540de3a   Wei Ni   tegra: Add SOC su...
33
  	COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
a73ca4789   Stephen Warren   mmc: tegra: suppo...
34
  	COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
f4e4e0b0e   Tom Warren   Tegra30: mmc: Add...
35
  	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
c9aa831ee   Tom Warren   Tegra: MMC: Add D...
36
  	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
8f1b46b10   Allen Martin   tegra: spi: add f...
37
  	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
b19f57491   Allen Martin   tegra: add SPI SL...
38
  	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
c3bb3c8bb   Allen Martin   tegra114: fdt: ad...
39
  	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
cc9fe33a3   Hatim RV   fdt: exynos5: Add...
40
41
  	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
  	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
c34253d1f   Rajeshwari Shinde   FDT: Add compatib...
42
  	COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
72dbff12a   Rajeshwari Shinde   EXYNOS5: FDT: Add...
43
44
  	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
  	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
5d50659db   Rajeshwari Shinde   EXYNOS5: FDT: Add...
45
  	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
88364387c   Hung-ying Tyan   cros: add cros_ec...
46
  	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
713cb6804   Hung-ying Tyan   cros: adds cros_e...
47
  	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
6abd1620b   Rajeshwari Shinde   EXYNOS5: FDT: Add...
48
  	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
108b85be2   Vivek Gautam   exynos5: dts: Add...
49
  	COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
6abd1620b   Rajeshwari Shinde   EXYNOS5: FDT: Add...
50
  	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
108b85be2   Vivek Gautam   exynos5: dts: Add...
51
  	COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
618766c09   Akshay Saraswat   Exynos5: FDT: Add...
52
  	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
d7377b519   Ajay Kumar   EXYNOS: FDT: Add ...
53
  	COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"),
1e4706a71   Ajay Kumar   EXYNOS5: FDT: Add...
54
  	COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"),
45a4d4d35   Amar   FDT: Add compatib...
55
  	COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"),
ee1e3c2f2   Rajeshwari Shinde   EXYNOS5: FDT: Add...
56
  	COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
cd577e2b5   Rajeshwari Shinde   EXYNOS5: FDT: Add...
57
  	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
bb8215f43   Simon Glass   sf: Enable FDT-ba...
58
  	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
7772bb787   Rajeshwari Shinde   EXYNOS5: FDT: Add...
59
  	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
f62679981   Rong Chang   tpm: Add Infineon...
60
  	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
ec34fa5e4   Vincent Palatin   tpm: Add support ...
61
  	COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"),
ecbd7e1ec   naveen krishna chatradhi   fdtdec: Add compa...
62
  	COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
b5220bc6e   Simon Glass   fdt: add decode h...
63
  };
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
64
65
66
67
68
69
  const char *fdtdec_get_compatible(enum fdt_compat_id id)
  {
  	/* We allow reading of the 'unknown' ID for testing purposes */
  	assert(id >= 0 && id < COMPAT_COUNT);
  	return compat_names[id];
  }
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
70
71
  fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
  		const char *prop_name, fdt_size_t *sizep)
b5220bc6e   Simon Glass   fdt: add decode h...
72
73
74
  {
  	const fdt_addr_t *cell;
  	int len;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
75
  	debug("%s: %s: ", __func__, prop_name);
b5220bc6e   Simon Glass   fdt: add decode h...
76
  	cell = fdt_getprop(blob, node, prop_name, &len);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
77
78
  	if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
  		     len == sizeof(fdt_addr_t) * 2)) {
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
79
  		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
80
81
  		if (sizep) {
  			const fdt_size_t *size;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
82

4397a2a80   Simon Glass   fdt: Add fdtdec_g...
83
84
85
  			size = (fdt_size_t *)((char *)cell +
  					sizeof(fdt_addr_t));
  			*sizep = fdt_size_to_cpu(*size);
370b6c5c4   Simon Glass   sandbox: Correct ...
86
87
88
  			debug("addr=%08lx, size=%08x
  ",
  			      (ulong)addr, *sizep);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
89
  		} else {
370b6c5c4   Simon Glass   sandbox: Correct ...
90
91
  			debug("%08lx
  ", (ulong)addr);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
92
  		}
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
93
94
95
96
  		return addr;
  	}
  	debug("(not found)
  ");
b5220bc6e   Simon Glass   fdt: add decode h...
97
98
  	return FDT_ADDR_T_NONE;
  }
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
99
100
101
102
103
  fdt_addr_t fdtdec_get_addr(const void *blob, int node,
  		const char *prop_name)
  {
  	return fdtdec_get_addr_size(blob, node, prop_name, NULL);
  }
b5220bc6e   Simon Glass   fdt: add decode h...
104
105
106
107
108
  s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
  		s32 default_val)
  {
  	const s32 *cell;
  	int len;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
109
  	debug("%s: %s: ", __func__, prop_name);
b5220bc6e   Simon Glass   fdt: add decode h...
110
  	cell = fdt_getprop(blob, node, prop_name, &len);
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
111
112
113
114
115
116
117
118
119
  	if (cell && len >= sizeof(s32)) {
  		s32 val = fdt32_to_cpu(cell[0]);
  
  		debug("%#x (%d)
  ", val, val);
  		return val;
  	}
  	debug("(not found)
  ");
b5220bc6e   Simon Glass   fdt: add decode h...
120
121
  	return default_val;
  }
aadef0a1b   Che-Liang Chiou   fdt: Add fdtdec_g...
122
123
124
125
126
127
128
129
130
131
132
133
  uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
  		uint64_t default_val)
  {
  	const uint64_t *cell64;
  	int length;
  
  	cell64 = fdt_getprop(blob, node, prop_name, &length);
  	if (!cell64 || length < sizeof(*cell64))
  		return default_val;
  
  	return fdt64_to_cpu(*cell64);
  }
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
134
  int fdtdec_get_is_enabled(const void *blob, int node)
b5220bc6e   Simon Glass   fdt: add decode h...
135
136
  {
  	const char *cell;
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
137
138
139
140
141
142
143
  	/*
  	 * It should say "okay", so only allow that. Some fdts use "ok" but
  	 * this is a bug. Please fix your device tree source file. See here
  	 * for discussion:
  	 *
  	 * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html
  	 */
b5220bc6e   Simon Glass   fdt: add decode h...
144
145
  	cell = fdt_getprop(blob, node, "status", NULL);
  	if (cell)
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
146
147
  		return 0 == strcmp(cell, "okay");
  	return 1;
b5220bc6e   Simon Glass   fdt: add decode h...
148
  }
7cde397b2   Gerald Van Baren   fdt: Export fdtde...
149
  enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
b5220bc6e   Simon Glass   fdt: add decode h...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  {
  	enum fdt_compat_id id;
  
  	/* Search our drivers */
  	for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++)
  		if (0 == fdt_node_check_compatible(blob, node,
  				compat_names[id]))
  			return id;
  	return COMPAT_UNKNOWN;
  }
  
  int fdtdec_next_compatible(const void *blob, int node,
  		enum fdt_compat_id id)
  {
  	return fdt_node_offset_by_compatible(blob, node, compat_names[id]);
  }
3ddecfc74   Simon Glass   fdt: Add function...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  int fdtdec_next_compatible_subnode(const void *blob, int node,
  		enum fdt_compat_id id, int *depthp)
  {
  	do {
  		node = fdt_next_node(blob, node, depthp);
  	} while (*depthp > 1);
  
  	/* If this is a direct subnode, and compatible, return it */
  	if (*depthp == 1 && 0 == fdt_node_check_compatible(
  						blob, node, compat_names[id]))
  		return node;
  
  	return -FDT_ERR_NOTFOUND;
  }
b5220bc6e   Simon Glass   fdt: add decode h...
180
181
182
183
184
185
186
187
188
189
  int fdtdec_next_alias(const void *blob, const char *name,
  		enum fdt_compat_id id, int *upto)
  {
  #define MAX_STR_LEN 20
  	char str[MAX_STR_LEN + 20];
  	int node, err;
  
  	/* snprintf() is not available */
  	assert(strlen(name) < MAX_STR_LEN);
  	sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
008784765   Simon Glass   fdt: Remove fdtde...
190
  	node = fdt_path_offset(blob, str);
b5220bc6e   Simon Glass   fdt: add decode h...
191
192
193
194
195
  	if (node < 0)
  		return node;
  	err = fdt_node_check_compatible(blob, node, compat_names[id]);
  	if (err < 0)
  		return err;
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
196
197
198
199
  	if (err)
  		return -FDT_ERR_NOTFOUND;
  	(*upto)++;
  	return node;
b5220bc6e   Simon Glass   fdt: add decode h...
200
  }
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
201
202
203
  int fdtdec_find_aliases_for_id(const void *blob, const char *name,
  			enum fdt_compat_id id, int *node_list, int maxcount)
  {
c67822704   Simon Glass   fdt: Add function...
204
205
206
207
208
209
210
211
212
  	memset(node_list, '\0', sizeof(*node_list) * maxcount);
  
  	return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount);
  }
  
  /* TODO: Can we tighten this code up a little? */
  int fdtdec_add_aliases_for_id(const void *blob, const char *name,
  			enum fdt_compat_id id, int *node_list, int maxcount)
  {
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  	int name_len = strlen(name);
  	int nodes[maxcount];
  	int num_found = 0;
  	int offset, node;
  	int alias_node;
  	int count;
  	int i, j;
  
  	/* find the alias node if present */
  	alias_node = fdt_path_offset(blob, "/aliases");
  
  	/*
  	 * start with nothing, and we can assume that the root node can't
  	 * match
  	 */
  	memset(nodes, '\0', sizeof(nodes));
  
  	/* First find all the compatible nodes */
  	for (node = count = 0; node >= 0 && count < maxcount;) {
  		node = fdtdec_next_compatible(blob, node, id);
  		if (node >= 0)
  			nodes[count++] = node;
  	}
  	if (node >= 0)
  		debug("%s: warning: maxcount exceeded with alias '%s'
  ",
  		       __func__, name);
  
  	/* Now find all the aliases */
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  	for (offset = fdt_first_property_offset(blob, alias_node);
  			offset > 0;
  			offset = fdt_next_property_offset(blob, offset)) {
  		const struct fdt_property *prop;
  		const char *path;
  		int number;
  		int found;
  
  		node = 0;
  		prop = fdt_get_property_by_offset(blob, offset, NULL);
  		path = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
  		if (prop->len && 0 == strncmp(path, name, name_len))
  			node = fdt_path_offset(blob, prop->data);
  		if (node <= 0)
  			continue;
  
  		/* Get the alias number */
  		number = simple_strtoul(path + name_len, NULL, 10);
  		if (number < 0 || number >= maxcount) {
  			debug("%s: warning: alias '%s' is out of range
  ",
  			       __func__, path);
  			continue;
  		}
  
  		/* Make sure the node we found is actually in our list! */
  		found = -1;
  		for (j = 0; j < count; j++)
  			if (nodes[j] == node) {
  				found = j;
  				break;
  			}
  
  		if (found == -1) {
  			debug("%s: warning: alias '%s' points to a node "
  				"'%s' that is missing or is not compatible "
  				" with '%s'
  ", __func__, path,
  				fdt_get_name(blob, node, NULL),
  			       compat_names[id]);
  			continue;
  		}
  
  		/*
  		 * Add this node to our list in the right place, and mark
  		 * it as done.
  		 */
  		if (fdtdec_get_is_enabled(blob, node)) {
c67822704   Simon Glass   fdt: Add function...
290
291
292
293
294
295
296
297
298
  			if (node_list[number]) {
  				debug("%s: warning: alias '%s' requires that "
  				      "a node be placed in the list in a "
  				      "position which is already filled by "
  				      "node '%s'
  ", __func__, path,
  				      fdt_get_name(blob, node, NULL));
  				continue;
  			}
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
299
300
301
302
  			node_list[number] = node;
  			if (number >= num_found)
  				num_found = number + 1;
  		}
c67822704   Simon Glass   fdt: Add function...
303
  		nodes[found] = 0;
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	}
  
  	/* Add any nodes not mentioned by an alias */
  	for (i = j = 0; i < maxcount; i++) {
  		if (!node_list[i]) {
  			for (; j < maxcount; j++)
  				if (nodes[j] &&
  					fdtdec_get_is_enabled(blob, nodes[j]))
  					break;
  
  			/* Have we run out of nodes to add? */
  			if (j == maxcount)
  				break;
  
  			assert(!node_list[i]);
  			node_list[i] = nodes[j++];
  			if (i >= num_found)
  				num_found = i + 1;
  		}
  	}
  
  	return num_found;
  }
9a263e55d   Simon Glass   fdt: Avoid early ...
327
328
329
330
331
332
333
334
335
336
337
  int fdtdec_check_fdt(void)
  {
  	/*
  	 * We must have an FDT, but we cannot panic() yet since the console
  	 * is not ready. So for now, just assert(). Boards which need an early
  	 * FDT (prior to console ready) will need to make their own
  	 * arrangements and do their own checks.
  	 */
  	assert(!fdtdec_prepare_fdt());
  	return 0;
  }
b5220bc6e   Simon Glass   fdt: add decode h...
338
339
340
341
342
  /*
   * This function is a little odd in that it accesses global data. At some
   * point if the architecture board.c files merge this will make more sense.
   * Even now, it is common code.
   */
9a263e55d   Simon Glass   fdt: Avoid early ...
343
  int fdtdec_prepare_fdt(void)
b5220bc6e   Simon Glass   fdt: add decode h...
344
  {
c309c2da1   Simon Glass   fdt: Skip checkin...
345
346
  	if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
  	    fdt_check_header(gd->fdt_blob)) {
9a263e55d   Simon Glass   fdt: Avoid early ...
347
348
  		printf("No valid FDT found - please append one to U-Boot "
  			"binary, use u-boot-dtb.bin or define "
a733b06b6   Simon Glass   sandbox: Switch o...
349
350
  			"CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>
  ");
9a263e55d   Simon Glass   fdt: Avoid early ...
351
352
  		return -1;
  	}
b5220bc6e   Simon Glass   fdt: add decode h...
353
354
  	return 0;
  }
d17da6556   Simon Glass   fdt: Add function...
355
356
357
358
359
  
  int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
  {
  	const u32 *phandle;
  	int lookup;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
360
361
  	debug("%s: %s
  ", __func__, prop_name);
d17da6556   Simon Glass   fdt: Add function...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  	phandle = fdt_getprop(blob, node, prop_name, NULL);
  	if (!phandle)
  		return -FDT_ERR_NOTFOUND;
  
  	lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle));
  	return lookup;
  }
  
  /**
   * Look up a property in a node and check that it has a minimum length.
   *
   * @param blob		FDT blob
   * @param node		node to examine
   * @param prop_name	name of property to find
   * @param min_len	minimum property length in bytes
   * @param err		0 if ok, or -FDT_ERR_NOTFOUND if the property is not
  			found, or -FDT_ERR_BADLAYOUT if not enough data
   * @return pointer to cell, which is only valid if err == 0
   */
  static const void *get_prop_check_min_len(const void *blob, int node,
  		const char *prop_name, int min_len, int *err)
  {
  	const void *cell;
  	int len;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	cell = fdt_getprop(blob, node, prop_name, &len);
  	if (!cell)
  		*err = -FDT_ERR_NOTFOUND;
  	else if (len < min_len)
  		*err = -FDT_ERR_BADLAYOUT;
  	else
  		*err = 0;
  	return cell;
  }
  
  int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
  		u32 *array, int count)
  {
  	const u32 *cell;
  	int i, err = 0;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	cell = get_prop_check_min_len(blob, node, prop_name,
  				      sizeof(u32) * count, &err);
  	if (!err) {
  		for (i = 0; i < count; i++)
  			array[i] = fdt32_to_cpu(cell[i]);
  	}
  	return err;
  }
96875e7d3   Simon Glass   fdt: Add function...
415
416
417
418
419
420
421
422
423
424
  const u32 *fdtdec_locate_array(const void *blob, int node,
  			       const char *prop_name, int count)
  {
  	const u32 *cell;
  	int err;
  
  	cell = get_prop_check_min_len(blob, node, prop_name,
  				      sizeof(u32) * count, &err);
  	return err ? NULL : cell;
  }
d17da6556   Simon Glass   fdt: Add function...
425
426
427
428
429
430
431
432
433
434
  int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
  {
  	const s32 *cell;
  	int len;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	cell = fdt_getprop(blob, node, prop_name, &len);
  	return cell != NULL;
  }
ed3ee5cd0   Simon Glass   fdt: Add basic su...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  
  /**
   * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
   * terminating item.
   *
   * @param blob		FDT blob to use
   * @param node		Node to look at
   * @param prop_name	Node property name
   * @param gpio		Array of gpio elements to fill from FDT. This will be
   *			untouched if either 0 or an error is returned
   * @param max_count	Maximum number of elements allowed
   * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
   * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
   */
5921f6a29   Abhilash Kesavan   fdt: Add function...
449
450
  int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
  		struct fdt_gpio_state *gpio, int max_count)
ed3ee5cd0   Simon Glass   fdt: Add basic su...
451
452
453
454
455
456
457
458
459
460
461
  {
  	const struct fdt_property *prop;
  	const u32 *cell;
  	const char *name;
  	int len, i;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	assert(max_count > 0);
  	prop = fdt_get_property(blob, node, prop_name, &len);
  	if (!prop) {
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
462
463
  		debug("%s: property '%s' missing
  ", __func__, prop_name);
ed3ee5cd0   Simon Glass   fdt: Add basic su...
464
465
466
467
468
469
470
471
  		return -FDT_ERR_NOTFOUND;
  	}
  
  	/* We will use the name to tag the GPIO */
  	name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
  	cell = (u32 *)prop->data;
  	len /= sizeof(u32) * 3;		/* 3 cells per GPIO record */
  	if (len > max_count) {
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
472
  		debug(" %s: too many GPIOs / cells for "
ed3ee5cd0   Simon Glass   fdt: Add basic su...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  			"property '%s'
  ", __func__, prop_name);
  		return -FDT_ERR_BADLAYOUT;
  	}
  
  	/* Read out the GPIO data from the cells */
  	for (i = 0; i < len; i++, cell += 3) {
  		gpio[i].gpio = fdt32_to_cpu(cell[1]);
  		gpio[i].flags = fdt32_to_cpu(cell[2]);
  		gpio[i].name = name;
  	}
  
  	return len;
  }
  
  int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
  		struct fdt_gpio_state *gpio)
  {
  	int err;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	gpio->gpio = FDT_GPIO_NONE;
  	gpio->name = NULL;
  	err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1);
  	return err == 1 ? 0 : err;
  }
202ff7537   Sean Paul   fdt: Add polarity...
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
  {
  	int val;
  
  	if (!fdt_gpio_isvalid(gpio))
  		return -1;
  
  	val = gpio_get_value(gpio->gpio);
  	return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
  }
  
  int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
  {
  	if (!fdt_gpio_isvalid(gpio))
  		return -1;
  
  	val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
  	return gpio_set_value(gpio->gpio, val);
  }
ed3ee5cd0   Simon Glass   fdt: Add basic su...
519
520
521
522
523
524
525
526
527
528
529
530
531
  int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
  {
  	/*
  	 * Return success if there is no GPIO defined. This is used for
  	 * optional GPIOs)
  	 */
  	if (!fdt_gpio_isvalid(gpio))
  		return 0;
  
  	if (gpio_request(gpio->gpio, gpio->name))
  		return -1;
  	return 0;
  }
bed4d8927   Anton Staff   fdt: Add fdtdec f...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  
  int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
  		u8 *array, int count)
  {
  	const u8 *cell;
  	int err;
  
  	cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
  	if (!err)
  		memcpy(array, cell, count);
  	return err;
  }
  
  const u8 *fdtdec_locate_byte_array(const void *blob, int node,
  			     const char *prop_name, int count)
  {
  	const u8 *cell;
  	int err;
  
  	cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
  	if (err)
  		return NULL;
  	return cell;
  }
09258f1e8   Abhilash Kesavan   fdt: Add function...
556

09258f1e8   Abhilash Kesavan   fdt: Add function...
557
558
559
560
561
562
563
564
565
566
567
568
  int fdtdec_get_config_int(const void *blob, const char *prop_name,
  		int default_val)
  {
  	int config_node;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	config_node = fdt_path_offset(blob, "/config");
  	if (config_node < 0)
  		return default_val;
  	return fdtdec_get_int(blob, config_node, prop_name, default_val);
  }
332ab0d54   Simon Glass   fdt: Add function...
569

79289c0b5   Gabe Black   fdt: Add function...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  int fdtdec_get_config_bool(const void *blob, const char *prop_name)
  {
  	int config_node;
  	const void *prop;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	config_node = fdt_path_offset(blob, "/config");
  	if (config_node < 0)
  		return 0;
  	prop = fdt_get_property(blob, config_node, prop_name, NULL);
  
  	return prop != NULL;
  }
332ab0d54   Simon Glass   fdt: Add function...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  char *fdtdec_get_config_string(const void *blob, const char *prop_name)
  {
  	const char *nodep;
  	int nodeoffset;
  	int len;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	nodeoffset = fdt_path_offset(blob, "/config");
  	if (nodeoffset < 0)
  		return NULL;
  
  	nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
  	if (!nodep)
  		return NULL;
  
  	return (char *)nodep;
  }
f20c46198   Simon Glass   fdt: Add fdtdec_d...
602
603
604
605
606
607
608
609
610
611
612
613
  
  int fdtdec_decode_region(const void *blob, int node,
  		const char *prop_name, void **ptrp, size_t *size)
  {
  	const fdt_addr_t *cell;
  	int len;
  
  	debug("%s: %s
  ", __func__, prop_name);
  	cell = fdt_getprop(blob, node, prop_name, &len);
  	if (!cell || (len != sizeof(fdt_addr_t) * 2))
  		return -1;
370b6c5c4   Simon Glass   sandbox: Correct ...
614
  	*ptrp = map_sysmem(fdt_addr_to_cpu(*cell), *size);
f20c46198   Simon Glass   fdt: Add fdtdec_d...
615
616
617
618
619
  	*size = fdt_size_to_cpu(cell[1]);
  	debug("%s: size=%zx
  ", __func__, *size);
  	return 0;
  }