Blame view

lib/fdtdec.c 16 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"),
f4e4e0b0e   Tom Warren   Tegra30: mmc: Add...
34
  	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
c9aa831ee   Tom Warren   Tegra: MMC: Add D...
35
  	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
8f1b46b10   Allen Martin   tegra: spi: add f...
36
  	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
b19f57491   Allen Martin   tegra: add SPI SL...
37
  	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
c3bb3c8bb   Allen Martin   tegra114: fdt: ad...
38
  	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
cc9fe33a3   Hatim RV   fdt: exynos5: Add...
39
40
  	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
  	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
c34253d1f   Rajeshwari Shinde   FDT: Add compatib...
41
  	COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
72dbff12a   Rajeshwari Shinde   EXYNOS5: FDT: Add...
42
43
  	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
  	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
5d50659db   Rajeshwari Shinde   EXYNOS5: FDT: Add...
44
  	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
88364387c   Hung-ying Tyan   cros: add cros_ec...
45
  	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
713cb6804   Hung-ying Tyan   cros: adds cros_e...
46
  	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
6abd1620b   Rajeshwari Shinde   EXYNOS5: FDT: Add...
47
48
  	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
  	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
618766c09   Akshay Saraswat   Exynos5: FDT: Add...
49
  	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
d7377b519   Ajay Kumar   EXYNOS: FDT: Add ...
50
  	COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"),
1e4706a71   Ajay Kumar   EXYNOS5: FDT: Add...
51
  	COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"),
45a4d4d35   Amar   FDT: Add compatib...
52
  	COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"),
ee1e3c2f2   Rajeshwari Shinde   EXYNOS5: FDT: Add...
53
  	COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
cd577e2b5   Rajeshwari Shinde   EXYNOS5: FDT: Add...
54
  	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
bb8215f43   Simon Glass   sf: Enable FDT-ba...
55
  	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
7772bb787   Rajeshwari Shinde   EXYNOS5: FDT: Add...
56
  	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
f62679981   Rong Chang   tpm: Add Infineon...
57
  	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
ec34fa5e4   Vincent Palatin   tpm: Add support ...
58
  	COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"),
ecbd7e1ec   naveen krishna chatradhi   fdtdec: Add compa...
59
  	COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
b5220bc6e   Simon Glass   fdt: add decode h...
60
  };
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
61
62
63
64
65
66
  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...
67
68
  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...
69
70
71
  {
  	const fdt_addr_t *cell;
  	int len;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
72
  	debug("%s: %s: ", __func__, prop_name);
b5220bc6e   Simon Glass   fdt: add decode h...
73
  	cell = fdt_getprop(blob, node, prop_name, &len);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
74
75
  	if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
  		     len == sizeof(fdt_addr_t) * 2)) {
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
76
  		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
77
78
  		if (sizep) {
  			const fdt_size_t *size;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
79

4397a2a80   Simon Glass   fdt: Add fdtdec_g...
80
81
82
83
84
85
86
87
88
89
  			size = (fdt_size_t *)((char *)cell +
  					sizeof(fdt_addr_t));
  			*sizep = fdt_size_to_cpu(*size);
  			debug("addr=%p, size=%p
  ", (void *)addr,
  			      (void *)*sizep);
  		} else {
  			debug("%p
  ", (void *)addr);
  		}
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
90
91
92
93
  		return addr;
  	}
  	debug("(not found)
  ");
b5220bc6e   Simon Glass   fdt: add decode h...
94
95
  	return FDT_ADDR_T_NONE;
  }
4397a2a80   Simon Glass   fdt: Add fdtdec_g...
96
97
98
99
100
  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...
101
102
103
104
105
  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...
106
  	debug("%s: %s: ", __func__, prop_name);
b5220bc6e   Simon Glass   fdt: add decode h...
107
  	cell = fdt_getprop(blob, node, prop_name, &len);
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
108
109
110
111
112
113
114
115
116
  	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...
117
118
  	return default_val;
  }
aadef0a1b   Che-Liang Chiou   fdt: Add fdtdec_g...
119
120
121
122
123
124
125
126
127
128
129
130
  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...
131
  int fdtdec_get_is_enabled(const void *blob, int node)
b5220bc6e   Simon Glass   fdt: add decode h...
132
133
  {
  	const char *cell;
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
134
135
136
137
138
139
140
  	/*
  	 * 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...
141
142
  	cell = fdt_getprop(blob, node, "status", NULL);
  	if (cell)
f88fe2ded   Simon Glass   fdt: Tidy up a fe...
143
144
  		return 0 == strcmp(cell, "okay");
  	return 1;
b5220bc6e   Simon Glass   fdt: add decode h...
145
  }
7cde397b2   Gerald Van Baren   fdt: Export fdtde...
146
  enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
b5220bc6e   Simon Glass   fdt: add decode h...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  {
  	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...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  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...
177
178
179
180
181
182
183
184
185
186
  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...
187
  	node = fdt_path_offset(blob, str);
b5220bc6e   Simon Glass   fdt: add decode h...
188
189
190
191
192
  	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...
193
194
195
196
  	if (err)
  		return -FDT_ERR_NOTFOUND;
  	(*upto)++;
  	return node;
b5220bc6e   Simon Glass   fdt: add decode h...
197
  }
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
198
199
200
  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...
201
202
203
204
205
206
207
208
209
  	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...
210
211
212
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
  	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...
239
240
241
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
  	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...
287
288
289
290
291
292
293
294
295
  			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...
296
297
298
299
  			node_list[number] = node;
  			if (number >= num_found)
  				num_found = number + 1;
  		}
c67822704   Simon Glass   fdt: Add function...
300
  		nodes[found] = 0;
a53f4a29a   Simon Glass   fdt: Add fdtdec_f...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  	}
  
  	/* 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 ...
324
325
326
327
328
329
330
331
332
333
334
  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...
335
336
337
338
339
  /*
   * 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 ...
340
  int fdtdec_prepare_fdt(void)
b5220bc6e   Simon Glass   fdt: add decode h...
341
  {
c309c2da1   Simon Glass   fdt: Skip checkin...
342
343
  	if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
  	    fdt_check_header(gd->fdt_blob)) {
9a263e55d   Simon Glass   fdt: Avoid early ...
344
345
  		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...
346
347
  			"CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>
  ");
9a263e55d   Simon Glass   fdt: Avoid early ...
348
349
  		return -1;
  	}
b5220bc6e   Simon Glass   fdt: add decode h...
350
351
  	return 0;
  }
d17da6556   Simon Glass   fdt: Add function...
352
353
354
355
356
  
  int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
  {
  	const u32 *phandle;
  	int lookup;
1cb2323b8   Simon Glass   fdt: Tidy debuggi...
357
358
  	debug("%s: %s
  ", __func__, prop_name);
d17da6556   Simon Glass   fdt: Add function...
359
360
361
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
  	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...
412
413
414
415
416
417
418
419
420
421
  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...
422
423
424
425
426
427
428
429
430
431
  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...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  
  /**
   * 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...
446
447
  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...
448
449
450
451
452
453
454
455
456
457
458
  {
  	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...
459
460
  		debug("%s: property '%s' missing
  ", __func__, prop_name);
ed3ee5cd0   Simon Glass   fdt: Add basic su...
461
462
463
464
465
466
467
468
  		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...
469
  		debug(" %s: too many GPIOs / cells for "
ed3ee5cd0   Simon Glass   fdt: Add basic su...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  			"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...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  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...
516
517
518
519
520
521
522
523
524
525
526
527
528
  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...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  
  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...
553

09258f1e8   Abhilash Kesavan   fdt: Add function...
554
555
556
557
558
559
560
561
562
563
564
565
  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...
566

79289c0b5   Gabe Black   fdt: Add function...
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  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...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
  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...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  
  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;
  
  	*ptrp = (void *)fdt_addr_to_cpu(*cell);
  	*size = fdt_size_to_cpu(cell[1]);
  	debug("%s: size=%zx
  ", __func__, *size);
  	return 0;
  }