Blame view

drivers/of/fdt.c 31.6 KB
af6074fc9   Rob Herring   of: Use SPDX lice...
1
  // SPDX-License-Identifier: GPL-2.0
e169cfbef   Grant Likely   of/flattree: merg...
2
3
4
5
6
  /*
   * Functions for working with the Flattened Device Tree data format
   *
   * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
   * benh@kernel.crashing.org
e169cfbef   Grant Likely   of/flattree: merg...
7
   */
bd0096d74   Frank Rowand   of: Add missing s...
8
  #define pr_fmt(fmt)	"OF: fdt: " fmt
606ad42aa   Rob Herring   of: use pr_fmt pr...
9

08d53aa58   Ard Biesheuvel   of/fdt: export fd...
10
  #include <linux/crc32.h>
41f880091   Grant Likely   of/flattree: Merg...
11
  #include <linux/kernel.h>
f7b3a8355   Grant Likely   of/flattree: Merg...
12
  #include <linux/initrd.h>
a1727da59   Grant Likely   of: consolidate d...
13
  #include <linux/memblock.h>
f80623866   Guenter Roeck   of/fdt: Add mutex...
14
  #include <linux/mutex.h>
e169cfbef   Grant Likely   of/flattree: merg...
15
16
  #include <linux/of.h>
  #include <linux/of_fdt.h>
3f0c82066   Marek Szyprowski   drivers: of: add ...
17
  #include <linux/of_reserved_mem.h>
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
18
  #include <linux/sizes.h>
4ef7b373d   Jeremy Kerr   of/flattree: Don'...
19
20
  #include <linux/string.h>
  #include <linux/errno.h>
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
21
  #include <linux/slab.h>
e6a6928c3   Rob Herring   of/fdt: Convert F...
22
  #include <linux/libfdt.h>
b0a6fb36a   Rob Herring   of/fdt: create co...
23
  #include <linux/debugfs.h>
fb11ffe74   Rob Herring   of/fdt: add FDT s...
24
  #include <linux/serial_core.h>
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
25
  #include <linux/sysfs.h>
428826f53   Hsin-Yi Wang   fdt: add support ...
26
  #include <linux/random.h>
51975db0b   Grant Likely   of/flattree: merg...
27

c89810acb   Fabio Estevam   ARM: prom.h: Fix ...
28
  #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
4ef7b373d   Jeremy Kerr   of/flattree: Don'...
29
  #include <asm/page.h>
81d0848fc   Frank Rowand   of: Add unit test...
30
  #include "of_private.h"
704033cee   Laura Abbott   of: Add memory li...
31
32
33
34
35
36
37
38
  /*
   * of_fdt_limit_memory - limit the number of regions in the /memory node
   * @limit: maximum entries
   *
   * Adjust the flattened device tree to have at most 'limit' number of
   * memory entries in the /memory node. This function may be called
   * any time after initial_boot_param is set.
   */
9b4d2b635   Stephen Boyd   of/fdt: Remove de...
39
  void __init of_fdt_limit_memory(int limit)
704033cee   Laura Abbott   of: Add memory li...
40
41
42
43
44
45
  {
  	int memory;
  	int len;
  	const void *val;
  	int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
  	int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
17a70355e   Rob Herring   of: fix sparse wa...
46
47
  	const __be32 *addr_prop;
  	const __be32 *size_prop;
704033cee   Laura Abbott   of: Add memory li...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  	int root_offset;
  	int cell_size;
  
  	root_offset = fdt_path_offset(initial_boot_params, "/");
  	if (root_offset < 0)
  		return;
  
  	addr_prop = fdt_getprop(initial_boot_params, root_offset,
  				"#address-cells", NULL);
  	if (addr_prop)
  		nr_address_cells = fdt32_to_cpu(*addr_prop);
  
  	size_prop = fdt_getprop(initial_boot_params, root_offset,
  				"#size-cells", NULL);
  	if (size_prop)
  		nr_size_cells = fdt32_to_cpu(*size_prop);
  
  	cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells);
  
  	memory = fdt_path_offset(initial_boot_params, "/memory");
  	if (memory > 0) {
  		val = fdt_getprop(initial_boot_params, memory, "reg", &len);
  		if (len > limit*cell_size) {
  			len = limit*cell_size;
  			pr_debug("Limiting number of entries to %d
  ", limit);
  			fdt_setprop(initial_boot_params, memory, "reg", val,
  					len);
  		}
  	}
  }
ecc8a96e2   Rob Herring   of/fdt: add of_fd...
79
80
81
82
83
84
85
86
87
88
89
90
  static bool of_fdt_device_is_available(const void *blob, unsigned long node)
  {
  	const char *status = fdt_getprop(blob, node, "status", NULL);
  
  	if (!status)
  		return true;
  
  	if (!strcmp(status, "ok") || !strcmp(status, "okay"))
  		return true;
  
  	return false;
  }
448568193   Grant Likely   of/fdt: Clean up ...
91
  static void *unflatten_dt_alloc(void **mem, unsigned long size,
bbd33931a   Grant Likely   of/flattree: Merg...
92
93
94
  				       unsigned long align)
  {
  	void *res;
448568193   Grant Likely   of/fdt: Clean up ...
95
96
  	*mem = PTR_ALIGN(*mem, align);
  	res = *mem;
bbd33931a   Grant Likely   of/flattree: Merg...
97
98
99
100
  	*mem += size;
  
  	return res;
  }
dfbd4c6ef   Gavin Shan   drivers/of: Split...
101
102
103
104
105
  static void populate_properties(const void *blob,
  				int offset,
  				void **mem,
  				struct device_node *np,
  				const char *nodename,
5063e25a3   Grant Likely   of: Eliminate of_...
106
  				bool dryrun)
bbd33931a   Grant Likely   of/flattree: Merg...
107
  {
dfbd4c6ef   Gavin Shan   drivers/of: Split...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  	struct property *pp, **pprev = NULL;
  	int cur;
  	bool has_name = false;
  
  	pprev = &np->properties;
  	for (cur = fdt_first_property_offset(blob, offset);
  	     cur >= 0;
  	     cur = fdt_next_property_offset(blob, cur)) {
  		const __be32 *val;
  		const char *pname;
  		u32 sz;
  
  		val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
  		if (!val) {
606ad42aa   Rob Herring   of: use pr_fmt pr...
122
123
  			pr_warn("Cannot locate property at 0x%x
  ", cur);
dfbd4c6ef   Gavin Shan   drivers/of: Split...
124
125
126
127
  			continue;
  		}
  
  		if (!pname) {
606ad42aa   Rob Herring   of: use pr_fmt pr...
128
129
  			pr_warn("Cannot find property name at 0x%x
  ", cur);
dfbd4c6ef   Gavin Shan   drivers/of: Split...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  			continue;
  		}
  
  		if (!strcmp(pname, "name"))
  			has_name = true;
  
  		pp = unflatten_dt_alloc(mem, sizeof(struct property),
  					__alignof__(struct property));
  		if (dryrun)
  			continue;
  
  		/* We accept flattened tree phandles either in
  		 * ePAPR-style "phandle" properties, or the
  		 * legacy "linux,phandle" properties.  If both
  		 * appear and have different values, things
  		 * will get weird. Don't do that.
  		 */
  		if (!strcmp(pname, "phandle") ||
  		    !strcmp(pname, "linux,phandle")) {
  			if (!np->phandle)
  				np->phandle = be32_to_cpup(val);
  		}
  
  		/* And we process the "ibm,phandle" property
  		 * used in pSeries dynamic device tree
  		 * stuff
  		 */
  		if (!strcmp(pname, "ibm,phandle"))
  			np->phandle = be32_to_cpup(val);
  
  		pp->name   = (char *)pname;
  		pp->length = sz;
  		pp->value  = (__be32 *)val;
  		*pprev     = pp;
  		pprev      = &pp->next;
  	}
  
  	/* With version 0x10 we may not have the name property,
  	 * recreate it here from the unit name if absent
  	 */
  	if (!has_name) {
  		const char *p = nodename, *ps = p, *pa = NULL;
  		int len;
  
  		while (*p) {
  			if ((*p) == '@')
  				pa = p;
  			else if ((*p) == '/')
  				ps = p + 1;
  			p++;
  		}
  
  		if (pa < ps)
  			pa = p;
  		len = (pa - ps) + 1;
  		pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
  					__alignof__(struct property));
  		if (!dryrun) {
  			pp->name   = "name";
  			pp->length = len;
  			pp->value  = pp + 1;
  			*pprev     = pp;
  			pprev      = &pp->next;
  			memcpy(pp->value, ps, len - 1);
  			((char *)pp->value)[len - 1] = 0;
  			pr_debug("fixed up name for %s -> %s
  ",
  				 nodename, (char *)pp->value);
  		}
  	}
  
  	if (!dryrun)
  		*pprev = NULL;
  }
a7e4cfb0a   Rob Herring   of/fdt: only stor...
204
205
206
207
208
209
  static bool populate_node(const void *blob,
  			  int offset,
  			  void **mem,
  			  struct device_node *dad,
  			  struct device_node **pnp,
  			  bool dryrun)
dfbd4c6ef   Gavin Shan   drivers/of: Split...
210
  {
bbd33931a   Grant Likely   of/flattree: Merg...
211
  	struct device_node *np;
e6a6928c3   Rob Herring   of/fdt: Convert F...
212
  	const char *pathp;
bbd33931a   Grant Likely   of/flattree: Merg...
213
  	unsigned int l, allocl;
bbd33931a   Grant Likely   of/flattree: Merg...
214

dfbd4c6ef   Gavin Shan   drivers/of: Split...
215
216
217
  	pathp = fdt_get_name(blob, offset, &l);
  	if (!pathp) {
  		*pnp = NULL;
a7e4cfb0a   Rob Herring   of/fdt: only stor...
218
  		return false;
dfbd4c6ef   Gavin Shan   drivers/of: Split...
219
  	}
e6a6928c3   Rob Herring   of/fdt: Convert F...
220

05f4647b1   Ricky Liang   of/fdt: fix alloc...
221
  	allocl = ++l;
bbd33931a   Grant Likely   of/flattree: Merg...
222

dfbd4c6ef   Gavin Shan   drivers/of: Split...
223
  	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
bbd33931a   Grant Likely   of/flattree: Merg...
224
  				__alignof__(struct device_node));
5063e25a3   Grant Likely   of: Eliminate of_...
225
  	if (!dryrun) {
c22618a11   Grant Likely   drivers/of: Const...
226
  		char *fn;
0829f6d1f   Pantelis Antoniou   of: device_node k...
227
  		of_node_init(np);
c22618a11   Grant Likely   drivers/of: Const...
228
  		np->full_name = fn = ((char *)np) + sizeof(*np);
a7e4cfb0a   Rob Herring   of/fdt: only stor...
229

c22618a11   Grant Likely   drivers/of: Const...
230
  		memcpy(fn, pathp, l);
bbd33931a   Grant Likely   of/flattree: Merg...
231
232
  		if (dad != NULL) {
  			np->parent = dad;
70161ff33   Grant Likely   of: Drop ->next p...
233
234
  			np->sibling = dad->child;
  			dad->child = np;
bbd33931a   Grant Likely   of/flattree: Merg...
235
  		}
bbd33931a   Grant Likely   of/flattree: Merg...
236
  	}
e6a6928c3   Rob Herring   of/fdt: Convert F...
237

dfbd4c6ef   Gavin Shan   drivers/of: Split...
238
  	populate_properties(blob, offset, mem, np, pathp, dryrun);
5063e25a3   Grant Likely   of: Eliminate of_...
239
  	if (!dryrun) {
bbd33931a   Grant Likely   of/flattree: Merg...
240
  		np->name = of_get_property(np, "name", NULL);
bbd33931a   Grant Likely   of/flattree: Merg...
241
242
  		if (!np->name)
  			np->name = "<NULL>";
bbd33931a   Grant Likely   of/flattree: Merg...
243
  	}
e6a6928c3   Rob Herring   of/fdt: Convert F...
244

dfbd4c6ef   Gavin Shan   drivers/of: Split...
245
  	*pnp = np;
a7e4cfb0a   Rob Herring   of/fdt: only stor...
246
  	return true;
dfbd4c6ef   Gavin Shan   drivers/of: Split...
247
  }
50800082f   Gavin Shan   drivers/of: Avoid...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  static void reverse_nodes(struct device_node *parent)
  {
  	struct device_node *child, *next;
  
  	/* In-depth first */
  	child = parent->child;
  	while (child) {
  		reverse_nodes(child);
  
  		child = child->sibling;
  	}
  
  	/* Reverse the nodes in the child list */
  	child = parent->child;
  	parent->child = NULL;
  	while (child) {
  		next = child->sibling;
  
  		child->sibling = parent->child;
  		parent->child = child;
  		child = next;
  	}
  }
dfbd4c6ef   Gavin Shan   drivers/of: Split...
271
  /**
947c82cbf   Gavin Shan   drivers/of: Renam...
272
   * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree
dfbd4c6ef   Gavin Shan   drivers/of: Split...
273
274
   * @blob: The parent device tree blob
   * @mem: Memory chunk to use for allocating device nodes and properties
dfbd4c6ef   Gavin Shan   drivers/of: Split...
275
276
   * @dad: Parent struct device_node
   * @nodepp: The device_node tree created by the call
50800082f   Gavin Shan   drivers/of: Avoid...
277
278
   *
   * It returns the size of unflattened device tree or error code
dfbd4c6ef   Gavin Shan   drivers/of: Split...
279
   */
947c82cbf   Gavin Shan   drivers/of: Renam...
280
281
282
283
  static int unflatten_dt_nodes(const void *blob,
  			      void *mem,
  			      struct device_node *dad,
  			      struct device_node **nodepp)
dfbd4c6ef   Gavin Shan   drivers/of: Split...
284
  {
50800082f   Gavin Shan   drivers/of: Avoid...
285
  	struct device_node *root;
8c237cd0c   Gavin Shan   drivers/of: Fix d...
286
  	int offset = 0, depth = 0, initial_depth = 0;
50800082f   Gavin Shan   drivers/of: Avoid...
287
  #define FDT_MAX_DEPTH	64
50800082f   Gavin Shan   drivers/of: Avoid...
288
289
290
  	struct device_node *nps[FDT_MAX_DEPTH];
  	void *base = mem;
  	bool dryrun = !base;
dfbd4c6ef   Gavin Shan   drivers/of: Split...
291

50800082f   Gavin Shan   drivers/of: Avoid...
292
293
  	if (nodepp)
  		*nodepp = NULL;
8c237cd0c   Gavin Shan   drivers/of: Fix d...
294
295
296
297
298
299
300
301
302
  	/*
  	 * We're unflattening device sub-tree if @dad is valid. There are
  	 * possibly multiple nodes in the first level of depth. We need
  	 * set @depth to 1 to make fdt_next_node() happy as it bails
  	 * immediately when negative @depth is found. Otherwise, the device
  	 * nodes except the first one won't be unflattened successfully.
  	 */
  	if (dad)
  		depth = initial_depth = 1;
50800082f   Gavin Shan   drivers/of: Avoid...
303
  	root = dad;
78c44d910   Rhyland Klein   drivers/of: Fix d...
304
  	nps[depth] = dad;
8c237cd0c   Gavin Shan   drivers/of: Fix d...
305

50800082f   Gavin Shan   drivers/of: Avoid...
306
  	for (offset = 0;
8c237cd0c   Gavin Shan   drivers/of: Fix d...
307
  	     offset >= 0 && depth >= initial_depth;
50800082f   Gavin Shan   drivers/of: Avoid...
308
309
310
  	     offset = fdt_next_node(blob, offset, &depth)) {
  		if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
  			continue;
dfbd4c6ef   Gavin Shan   drivers/of: Split...
311

77ea8a68c   Rob Herring   of/fdt: skip unfl...
312
313
314
  		if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
  		    !of_fdt_device_is_available(blob, offset))
  			continue;
a7e4cfb0a   Rob Herring   of/fdt: only stor...
315
316
  		if (!populate_node(blob, offset, &mem, nps[depth],
  				   &nps[depth+1], dryrun))
50800082f   Gavin Shan   drivers/of: Avoid...
317
318
319
  			return mem - base;
  
  		if (!dryrun && nodepp && !*nodepp)
78c44d910   Rhyland Klein   drivers/of: Fix d...
320
  			*nodepp = nps[depth+1];
50800082f   Gavin Shan   drivers/of: Avoid...
321
  		if (!dryrun && !root)
78c44d910   Rhyland Klein   drivers/of: Fix d...
322
  			root = nps[depth+1];
50800082f   Gavin Shan   drivers/of: Avoid...
323
  	}
e6a6928c3   Rob Herring   of/fdt: Convert F...
324

50800082f   Gavin Shan   drivers/of: Avoid...
325
  	if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
606ad42aa   Rob Herring   of: use pr_fmt pr...
326
327
  		pr_err("Error %d processing FDT
  ", offset);
50800082f   Gavin Shan   drivers/of: Avoid...
328
329
  		return -EINVAL;
  	}
e6a6928c3   Rob Herring   of/fdt: Convert F...
330

70161ff33   Grant Likely   of: Drop ->next p...
331
332
333
334
  	/*
  	 * Reverse the child list. Some drivers assumes node order matches .dts
  	 * node order
  	 */
50800082f   Gavin Shan   drivers/of: Avoid...
335
336
  	if (!dryrun)
  		reverse_nodes(root);
e6a6928c3   Rob Herring   of/fdt: Convert F...
337

50800082f   Gavin Shan   drivers/of: Avoid...
338
  	return mem - base;
bbd33931a   Grant Likely   of/flattree: Merg...
339
  }
41f880091   Grant Likely   of/flattree: Merg...
340

fe1404235   Stephen Neuendorffer   of/flattree: Refa...
341
342
343
344
345
346
347
348
  /**
   * __unflatten_device_tree - create tree of device_nodes from flat blob
   *
   * unflattens a device-tree, creating the
   * tree of struct device_node. It also fills the "name" and "type"
   * pointers of the nodes so the normal device-tree walking functions
   * can be used.
   * @blob: The blob to expand
c4263233f   Gavin Shan   drivers/of: Speci...
349
   * @dad: Parent device node
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
350
351
352
   * @mynodes: The device_node tree created by the call
   * @dt_alloc: An allocator that provides a virtual address to memory
   * for the resulting tree
f5d2da677   Stephen Boyd   of/fdt: Document ...
353
   * @detached: if true set OF_DETACHED on @mynodes
83262418b   Gavin Shan   drivers/of: Retur...
354
355
356
   *
   * Returns NULL on failure or the memory chunk containing the unflattened
   * device tree on success.
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
357
   */
81d0848fc   Frank Rowand   of: Add unit test...
358
359
360
361
362
  void *__unflatten_device_tree(const void *blob,
  			      struct device_node *dad,
  			      struct device_node **mynodes,
  			      void *(*dt_alloc)(u64 size, u64 align),
  			      bool detached)
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
363
  {
50800082f   Gavin Shan   drivers/of: Avoid...
364
  	int size;
e6a6928c3   Rob Herring   of/fdt: Convert F...
365
  	void *mem;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
366
367
368
369
370
371
372
  
  	pr_debug(" -> unflatten_device_tree()
  ");
  
  	if (!blob) {
  		pr_debug("No device tree pointer
  ");
83262418b   Gavin Shan   drivers/of: Retur...
373
  		return NULL;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
374
375
376
377
  	}
  
  	pr_debug("Unflattening device tree:
  ");
c972de149   Rob Herring   of/fdt: use libfd...
378
379
380
381
382
383
  	pr_debug("magic: %08x
  ", fdt_magic(blob));
  	pr_debug("size: %08x
  ", fdt_totalsize(blob));
  	pr_debug("version: %08x
  ", fdt_version(blob));
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
384

c972de149   Rob Herring   of/fdt: use libfd...
385
  	if (fdt_check_header(blob)) {
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
386
387
  		pr_err("Invalid device tree blob header
  ");
83262418b   Gavin Shan   drivers/of: Retur...
388
  		return NULL;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
389
390
391
  	}
  
  	/* First pass, scan for size */
c4263233f   Gavin Shan   drivers/of: Speci...
392
  	size = unflatten_dt_nodes(blob, NULL, dad, NULL);
50800082f   Gavin Shan   drivers/of: Avoid...
393
  	if (size < 0)
83262418b   Gavin Shan   drivers/of: Retur...
394
  		return NULL;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
395

50800082f   Gavin Shan   drivers/of: Avoid...
396
397
398
  	size = ALIGN(size, 4);
  	pr_debug("  size is %d, allocating...
  ", size);
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
399
400
  
  	/* Allocate memory for the expanded device tree */
448568193   Grant Likely   of/fdt: Clean up ...
401
  	mem = dt_alloc(size + 4, __alignof__(struct device_node));
49e67dd17   Johan Hovold   of: fdt: add miss...
402
403
  	if (!mem)
  		return NULL;
448568193   Grant Likely   of/fdt: Clean up ...
404
  	memset(mem, 0, size);
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
405

448568193   Grant Likely   of/fdt: Clean up ...
406
  	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
9e4012752   Wladislav Wiebe   of: fdt: fix memo...
407

448568193   Grant Likely   of/fdt: Clean up ...
408
409
  	pr_debug("  unflattening %p...
  ", mem);
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
410
411
  
  	/* Second pass, do actual unflattening */
c4263233f   Gavin Shan   drivers/of: Speci...
412
  	unflatten_dt_nodes(blob, mem, dad, mynodes);
448568193   Grant Likely   of/fdt: Clean up ...
413
  	if (be32_to_cpup(mem + size) != 0xdeadbeef)
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
414
415
  		pr_warning("End of tree marker overwritten: %08x
  ",
448568193   Grant Likely   of/fdt: Clean up ...
416
  			   be32_to_cpup(mem + size));
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
417

89c67752a   Gavin Shan   drivers/of: Valid...
418
  	if (detached && mynodes) {
1d1bde550   Michal Suchanek   of: fdt: mark unf...
419
420
421
422
  		of_node_set_flag(*mynodes, OF_DETACHED);
  		pr_debug("unflattened tree is detached
  ");
  	}
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
423
424
  	pr_debug(" <- unflatten_device_tree()
  ");
83262418b   Gavin Shan   drivers/of: Retur...
425
  	return mem;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
426
427
428
429
430
431
  }
  
  static void *kernel_tree_alloc(u64 size, u64 align)
  {
  	return kzalloc(size, GFP_KERNEL);
  }
f80623866   Guenter Roeck   of/fdt: Add mutex...
432
  static DEFINE_MUTEX(of_fdt_unflatten_mutex);
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
433
434
  /**
   * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
c4263233f   Gavin Shan   drivers/of: Speci...
435
436
437
   * @blob: Flat device tree blob
   * @dad: Parent device node
   * @mynodes: The device tree created by the call
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
438
439
440
441
442
   *
   * unflattens the device-tree passed by the firmware, creating the
   * tree of struct device_node. It also fills the "name" and "type"
   * pointers of the nodes so the normal device-tree walking functions
   * can be used.
83262418b   Gavin Shan   drivers/of: Retur...
443
444
445
   *
   * Returns NULL on failure or the memory chunk containing the unflattened
   * device tree on success.
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
446
   */
83262418b   Gavin Shan   drivers/of: Retur...
447
448
449
  void *of_fdt_unflatten_tree(const unsigned long *blob,
  			    struct device_node *dad,
  			    struct device_node **mynodes)
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
450
  {
83262418b   Gavin Shan   drivers/of: Retur...
451
  	void *mem;
f80623866   Guenter Roeck   of/fdt: Add mutex...
452
  	mutex_lock(&of_fdt_unflatten_mutex);
1d1bde550   Michal Suchanek   of: fdt: mark unf...
453
454
  	mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc,
  				      true);
f80623866   Guenter Roeck   of/fdt: Add mutex...
455
  	mutex_unlock(&of_fdt_unflatten_mutex);
83262418b   Gavin Shan   drivers/of: Retur...
456
457
  
  	return mem;
fe1404235   Stephen Neuendorffer   of/flattree: Refa...
458
459
  }
  EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
460
461
462
  /* Everything below here references initial_boot_params directly. */
  int __initdata dt_root_addr_cells;
  int __initdata dt_root_size_cells;
7c71650f9   Stephen Boyd   of/fdt: Mark init...
463
  void *initial_boot_params __ro_after_init;
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
464
465
  
  #ifdef CONFIG_OF_EARLY_FLATTREE
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
466
  static u32 of_fdt_crc32;
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
467
  /**
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
468
469
470
471
472
473
474
   * res_mem_reserve_reg() - reserve all memory described in 'reg' property
   */
  static int __init __reserved_mem_reserve_reg(unsigned long node,
  					     const char *uname)
  {
  	int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
  	phys_addr_t base, size;
9d0c4dfed   Rob Herring   of/fdt: update of...
475
476
  	int len;
  	const __be32 *prop;
5c68b8231   Masahiro Yamada   of/fdt: pass earl...
477
478
  	int first = 1;
  	bool nomap;
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  
  	prop = of_get_flat_dt_prop(node, "reg", &len);
  	if (!prop)
  		return -ENOENT;
  
  	if (len && len % t_len != 0) {
  		pr_err("Reserved memory: invalid reg property in '%s', skipping node.
  ",
  		       uname);
  		return -EINVAL;
  	}
  
  	nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
  
  	while (len >= t_len) {
  		base = dt_mem_next_cell(dt_root_addr_cells, &prop);
  		size = dt_mem_next_cell(dt_root_size_cells, &prop);
b5f2a8c02   Al Cooper   of: Allow mem_res...
496
  		if (size &&
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
497
498
499
500
501
502
503
504
505
506
  		    early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
  			pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB
  ",
  				uname, &base, (unsigned long)size / SZ_1M);
  		else
  			pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB
  ",
  				uname, &base, (unsigned long)size / SZ_1M);
  
  		len -= t_len;
3f0c82066   Marek Szyprowski   drivers: of: add ...
507
508
509
510
  		if (first) {
  			fdt_reserved_mem_save_node(node, uname, base, size);
  			first = 0;
  		}
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
511
512
513
514
515
516
517
518
519
  	}
  	return 0;
  }
  
  /**
   * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
   * in /reserved-memory matches the values supported by the current implementation,
   * also check if ranges property has been provided
   */
5b6241185   Xiubo Li   of: Fix the secti...
520
  static int __init __reserved_mem_check_root(unsigned long node)
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
521
  {
9d0c4dfed   Rob Herring   of/fdt: update of...
522
  	const __be32 *prop;
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  
  	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
  	if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
  		return -EINVAL;
  
  	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
  	if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
  		return -EINVAL;
  
  	prop = of_get_flat_dt_prop(node, "ranges", NULL);
  	if (!prop)
  		return -EINVAL;
  	return 0;
  }
  
  /**
   * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
   */
  static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
  					  int depth, void *data)
  {
  	static int found;
3f0c82066   Marek Szyprowski   drivers: of: add ...
545
  	int err;
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  
  	if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
  		if (__reserved_mem_check_root(node) != 0) {
  			pr_err("Reserved memory: unsupported node format, ignoring
  ");
  			/* break scan */
  			return 1;
  		}
  		found = 1;
  		/* scan next node */
  		return 0;
  	} else if (!found) {
  		/* scan next node */
  		return 0;
  	} else if (found && depth < 2) {
  		/* scanning of /reserved-memory has been finished */
  		return 1;
  	}
ecc8a96e2   Rob Herring   of/fdt: add of_fd...
564
  	if (!of_fdt_device_is_available(initial_boot_params, node))
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
565
  		return 0;
3f0c82066   Marek Szyprowski   drivers: of: add ...
566
567
568
  	err = __reserved_mem_reserve_reg(node, uname);
  	if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
  		fdt_reserved_mem_save_node(node, uname, 0, 0);
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  
  	/* scan next node */
  	return 0;
  }
  
  /**
   * early_init_fdt_scan_reserved_mem() - create reserved memory regions
   *
   * This function grabs memory from early allocator for device exclusive use
   * defined in device tree structures. It should be called by arch specific code
   * once the early allocator (i.e. memblock) has been fully activated.
   */
  void __init early_init_fdt_scan_reserved_mem(void)
  {
d1552ce44   Rob Herring   of/fdt: move memr...
583
584
  	int n;
  	u64 base, size;
2040b5276   Josh Cartwright   of: only scan for...
585
586
  	if (!initial_boot_params)
  		return;
d1552ce44   Rob Herring   of/fdt: move memr...
587
588
589
590
591
  	/* Process header /memreserve/ fields */
  	for (n = 0; ; n++) {
  		fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
  		if (!size)
  			break;
5c68b8231   Masahiro Yamada   of/fdt: pass earl...
592
  		early_init_dt_reserve_memory_arch(base, size, false);
d1552ce44   Rob Herring   of/fdt: move memr...
593
  	}
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
594
  	of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
3f0c82066   Marek Szyprowski   drivers: of: add ...
595
  	fdt_init_reserved_mem();
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
596
597
598
  }
  
  /**
24bbd929e   Ard Biesheuvel   of/fdt: split off...
599
600
601
602
603
604
605
606
607
608
   * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob
   */
  void __init early_init_fdt_reserve_self(void)
  {
  	if (!initial_boot_params)
  		return;
  
  	/* Reserve the dtb region */
  	early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
  					  fdt_totalsize(initial_boot_params),
5c68b8231   Masahiro Yamada   of/fdt: pass earl...
609
  					  false);
24bbd929e   Ard Biesheuvel   of/fdt: split off...
610
611
612
  }
  
  /**
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
613
614
615
616
617
618
619
620
621
622
623
624
625
   * of_scan_flat_dt - scan flattened tree blob and call callback on each.
   * @it: callback function
   * @data: context data pointer
   *
   * This function is used to scan the flattened device-tree, it is
   * used to extract the memory information at boot before we can
   * unflatten the tree
   */
  int __init of_scan_flat_dt(int (*it)(unsigned long node,
  				     const char *uname, int depth,
  				     void *data),
  			   void *data)
  {
e6a6928c3   Rob Herring   of/fdt: Convert F...
626
627
628
  	const void *blob = initial_boot_params;
  	const char *pathp;
  	int offset, rc = 0, depth = -1;
3ec754410   Tobias Wolf   of: Add check to ...
629
630
631
632
633
634
  	if (!blob)
  		return 0;
  
  	for (offset = fdt_next_node(blob, -1, &depth);
  	     offset >= 0 && depth >= 0 && !rc;
  	     offset = fdt_next_node(blob, offset, &depth)) {
e6a6928c3   Rob Herring   of/fdt: Convert F...
635
636
  
  		pathp = fdt_get_name(blob, offset, NULL);
375da3a76   Andy Shevchenko   drivers/of/fdt.c:...
637
638
  		if (*pathp == '/')
  			pathp = kbasename(pathp);
e6a6928c3   Rob Herring   of/fdt: Convert F...
639
640
  		rc = it(offset, pathp, depth, data);
  	}
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
641
642
643
644
  	return rc;
  }
  
  /**
ea47dd191   Nicholas Piggin   of/fdt: introduce...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
   * of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each.
   * @it: callback function
   * @data: context data pointer
   *
   * This function is used to scan sub-nodes of a node.
   */
  int __init of_scan_flat_dt_subnodes(unsigned long parent,
  				    int (*it)(unsigned long node,
  					      const char *uname,
  					      void *data),
  				    void *data)
  {
  	const void *blob = initial_boot_params;
  	int node;
  
  	fdt_for_each_subnode(node, blob, parent) {
  		const char *pathp;
  		int rc;
  
  		pathp = fdt_get_name(blob, node, NULL);
  		if (*pathp == '/')
  			pathp = kbasename(pathp);
  		rc = it(node, pathp, data);
  		if (rc)
  			return rc;
  	}
  	return 0;
  }
  
  /**
9c6098685   Shannon Zhao   FDT: Add a helper...
675
676
677
678
679
680
   * of_get_flat_dt_subnode_by_name - get the subnode by given name
   *
   * @node: the parent node
   * @uname: the name of subnode
   * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none
   */
9b4d2b635   Stephen Boyd   of/fdt: Remove de...
681
  int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
9c6098685   Shannon Zhao   FDT: Add a helper...
682
683
684
685
686
  {
  	return fdt_subnode_offset(initial_boot_params, node, uname);
  }
  
  /**
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
687
688
689
690
   * of_get_flat_dt_root - find the root node in the flat blob
   */
  unsigned long __init of_get_flat_dt_root(void)
  {
e6a6928c3   Rob Herring   of/fdt: Convert F...
691
  	return 0;
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
692
693
694
695
696
697
698
699
  }
  
  /**
   * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
   *
   * This function can be used within scan_flattened_dt callback to get
   * access to properties
   */
9d0c4dfed   Rob Herring   of/fdt: update of...
700
701
  const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
  				       int *size)
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
702
  {
e6a6928c3   Rob Herring   of/fdt: Convert F...
703
  	return fdt_getprop(initial_boot_params, node, name, size);
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
704
705
706
  }
  
  /**
5d9c4e959   Kefeng Wang   of/fdt: Fix ‘of_f...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
   * of_fdt_is_compatible - Return true if given node from the given blob has
   * compat in its compatible list
   * @blob: A device tree blob
   * @node: node to test
   * @compat: compatible string to compare with compatible list.
   *
   * On match, returns a non-zero value with smaller values returned for more
   * specific compatible values.
   */
  static int of_fdt_is_compatible(const void *blob,
  		      unsigned long node, const char *compat)
  {
  	const char *cp;
  	int cplen;
  	unsigned long l, score = 0;
  
  	cp = fdt_getprop(blob, node, "compatible", &cplen);
  	if (cp == NULL)
  		return 0;
  	while (cplen > 0) {
  		score++;
  		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
  			return score;
  		l = strlen(cp) + 1;
  		cp += l;
  		cplen -= l;
  	}
  
  	return 0;
  }
  
  /**
57d00ecf9   Stephen Neuendorffer   of/flattree: Reor...
739
740
741
742
743
744
745
746
   * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
   * @node: node to test
   * @compat: compatible string to compare with compatible list.
   */
  int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
  {
  	return of_fdt_is_compatible(initial_boot_params, node, compat);
  }
a4f740cf3   Grant Likely   of/flattree: Add ...
747
748
749
  /**
   * of_flat_dt_match - Return true if node matches a list of compatible values
   */
9b4d2b635   Stephen Boyd   of/fdt: Remove de...
750
  static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
a4f740cf3   Grant Likely   of/flattree: Add ...
751
  {
5d9c4e959   Kefeng Wang   of/fdt: Fix ‘of_f...
752
753
754
755
756
757
758
759
760
761
762
763
764
  	unsigned int tmp, score = 0;
  
  	if (!compat)
  		return 0;
  
  	while (*compat) {
  		tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
  		if (tmp && (score == 0 || (tmp < score)))
  			score = tmp;
  		compat++;
  	}
  
  	return score;
a4f740cf3   Grant Likely   of/flattree: Add ...
765
  }
ea47dd191   Nicholas Piggin   of/fdt: introduce...
766
767
768
769
770
771
772
  /**
   * of_get_flat_dt_prop - Given a node in the flat blob, return the phandle
   */
  uint32_t __init of_get_flat_dt_phandle(unsigned long node)
  {
  	return fdt_get_phandle(initial_boot_params, node);
  }
57d74bcf3   Marek Szyprowski   drivers: of: add ...
773
774
775
776
777
778
779
780
  struct fdt_scan_status {
  	const char *name;
  	int namelen;
  	int depth;
  	int found;
  	int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
  	void *data;
  };
6a903a255   Rob Herring   of: introduce com...
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  const char * __init of_flat_dt_get_machine_name(void)
  {
  	const char *name;
  	unsigned long dt_root = of_get_flat_dt_root();
  
  	name = of_get_flat_dt_prop(dt_root, "model", NULL);
  	if (!name)
  		name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
  	return name;
  }
  
  /**
   * of_flat_dt_match_machine - Iterate match tables to find matching machine.
   *
   * @default_match: A machine specific ptr to return in case of no match.
   * @get_next_compat: callback function to return next compatible match table.
   *
   * Iterate through machine match tables to find the best match for the machine
   * compatible string in the FDT.
   */
  const void * __init of_flat_dt_match_machine(const void *default_match,
  		const void * (*get_next_compat)(const char * const**))
  {
  	const void *data = NULL;
  	const void *best_data = default_match;
  	const char *const *compat;
  	unsigned long dt_root;
  	unsigned int best_score = ~1, score = 0;
  
  	dt_root = of_get_flat_dt_root();
  	while ((data = get_next_compat(&compat))) {
  		score = of_flat_dt_match(dt_root, compat);
  		if (score > 0 && score < best_score) {
  			best_data = data;
  			best_score = score;
  		}
  	}
  	if (!best_data) {
  		const char *prop;
9d0c4dfed   Rob Herring   of/fdt: update of...
820
  		int size;
6a903a255   Rob Herring   of: introduce com...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  
  		pr_err("
   unrecognized device tree list:
  [ ");
  
  		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
  		if (prop) {
  			while (size > 0) {
  				printk("'%s' ", prop);
  				size -= strlen(prop) + 1;
  				prop += strlen(prop) + 1;
  			}
  		}
  		printk("]
  
  ");
  		return NULL;
  	}
  
  	pr_info("Machine model: %s
  ", of_flat_dt_get_machine_name());
  
  	return best_data;
  }
f7b3a8355   Grant Likely   of/flattree: Merg...
845
  #ifdef CONFIG_BLK_DEV_INITRD
369bc9abf   Ard Biesheuvel   of/fdt: factor ou...
846
847
848
  static void __early_init_dt_declare_initrd(unsigned long start,
  					   unsigned long end)
  {
cdbc848b0   Florian Fainelli   of/fdt: Remove cu...
849
850
851
852
853
854
855
856
857
858
  	/* ARM64 would cause a BUG to occur here when CONFIG_DEBUG_VM is
  	 * enabled since __va() is called too early. ARM64 does make use
  	 * of phys_initrd_start/phys_initrd_size so we can skip this
  	 * conversion.
  	 */
  	if (!IS_ENABLED(CONFIG_ARM64)) {
  		initrd_start = (unsigned long)__va(start);
  		initrd_end = (unsigned long)__va(end);
  		initrd_below_start_ok = 1;
  	}
369bc9abf   Ard Biesheuvel   of/fdt: factor ou...
859
  }
369bc9abf   Ard Biesheuvel   of/fdt: factor ou...
860

f7b3a8355   Grant Likely   of/flattree: Merg...
861
862
863
864
  /**
   * early_init_dt_check_for_initrd - Decode initrd location from flat tree
   * @node: reference to node containing initrd location ('chosen')
   */
29eb45a9a   Rob Herring   of: remove early_...
865
  static void __init early_init_dt_check_for_initrd(unsigned long node)
f7b3a8355   Grant Likely   of/flattree: Merg...
866
  {
374d5c996   Santosh Shilimkar   of: Specify initr...
867
  	u64 start, end;
9d0c4dfed   Rob Herring   of/fdt: update of...
868
869
  	int len;
  	const __be32 *prop;
f7b3a8355   Grant Likely   of/flattree: Merg...
870
871
872
873
  
  	pr_debug("Looking for initrd properties... ");
  
  	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
1406bc2f5   Jeremy Kerr   of/flattree: use ...
874
875
  	if (!prop)
  		return;
374d5c996   Santosh Shilimkar   of: Specify initr...
876
  	start = of_read_number(prop, len/4);
1406bc2f5   Jeremy Kerr   of/flattree: use ...
877
878
879
880
  
  	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
  	if (!prop)
  		return;
374d5c996   Santosh Shilimkar   of: Specify initr...
881
  	end = of_read_number(prop, len/4);
f7b3a8355   Grant Likely   of/flattree: Merg...
882

369bc9abf   Ard Biesheuvel   of/fdt: factor ou...
883
  	__early_init_dt_declare_initrd(start, end);
fe7db7570   Florian Fainelli   of/fdt: Populate ...
884
885
  	phys_initrd_start = start;
  	phys_initrd_size = end - start;
29eb45a9a   Rob Herring   of: remove early_...
886

374d5c996   Santosh Shilimkar   of: Specify initr...
887
888
889
  	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx
  ",
  		 (unsigned long long)start, (unsigned long long)end);
f7b3a8355   Grant Likely   of/flattree: Merg...
890
891
  }
  #else
29eb45a9a   Rob Herring   of: remove early_...
892
  static inline void early_init_dt_check_for_initrd(unsigned long node)
f7b3a8355   Grant Likely   of/flattree: Merg...
893
894
895
  {
  }
  #endif /* CONFIG_BLK_DEV_INITRD */
fb11ffe74   Rob Herring   of/fdt: add FDT s...
896
  #ifdef CONFIG_SERIAL_EARLYCON
fb11ffe74   Rob Herring   of/fdt: add FDT s...
897

d503187b6   Leif Lindholm   of/serial: move e...
898
  int __init early_init_dt_scan_chosen_stdout(void)
fb11ffe74   Rob Herring   of/fdt: add FDT s...
899
900
  {
  	int offset;
4d118c9a8   Peter Hurley   of: earlycon: Add...
901
  	const char *p, *q, *options = NULL;
fb11ffe74   Rob Herring   of/fdt: add FDT s...
902
  	int l;
dd709e72c   Daniel Kurtz   earlycon: Use a p...
903
  	const struct earlycon_id **p_match;
fb11ffe74   Rob Herring   of/fdt: add FDT s...
904
905
906
907
908
909
910
911
912
913
914
915
916
  	const void *fdt = initial_boot_params;
  
  	offset = fdt_path_offset(fdt, "/chosen");
  	if (offset < 0)
  		offset = fdt_path_offset(fdt, "/chosen@0");
  	if (offset < 0)
  		return -ENOENT;
  
  	p = fdt_getprop(fdt, offset, "stdout-path", &l);
  	if (!p)
  		p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
  	if (!p || !l)
  		return -ENOENT;
4d118c9a8   Peter Hurley   of: earlycon: Add...
917
918
919
  	q = strchrnul(p, ':');
  	if (*q != '\0')
  		options = q + 1;
0fcc286f6   Peter Hurley   of: earlycon: Log...
920
  	l = q - p;
6296ad9e3   Stefan Agner   of/fdt: fix alias...
921

fb11ffe74   Rob Herring   of/fdt: add FDT s...
922
  	/* Get the node specified by stdout-path */
0fcc286f6   Peter Hurley   of: earlycon: Log...
923
924
925
926
927
928
  	offset = fdt_path_offset_namelen(fdt, p, l);
  	if (offset < 0) {
  		pr_warn("earlycon: stdout-path %.*s not found
  ", l, p);
  		return 0;
  	}
fb11ffe74   Rob Herring   of/fdt: add FDT s...
929

dd709e72c   Daniel Kurtz   earlycon: Use a p...
930
931
932
  	for (p_match = __earlycon_table; p_match < __earlycon_table_end;
  	     p_match++) {
  		const struct earlycon_id *match = *p_match;
2eaa79098   Peter Hurley   earlycon: Use com...
933
934
935
936
  		if (!match->compatible[0])
  			continue;
  
  		if (fdt_node_check_compatible(fdt, offset, match->compatible))
fb11ffe74   Rob Herring   of/fdt: add FDT s...
937
  			continue;
fb11ffe74   Rob Herring   of/fdt: add FDT s...
938

c90fe9c03   Peter Hurley   of: earlycon: Mov...
939
  		of_setup_earlycon(match, offset, options);
fb11ffe74   Rob Herring   of/fdt: add FDT s...
940
941
942
943
  		return 0;
  	}
  	return -ENODEV;
  }
fb11ffe74   Rob Herring   of/fdt: add FDT s...
944
  #endif
41f880091   Grant Likely   of/flattree: Merg...
945
  /**
f00abd949   Grant Likely   of/flattree: Merg...
946
947
948
949
950
   * early_init_dt_scan_root - fetch the top level address and size cells
   */
  int __init early_init_dt_scan_root(unsigned long node, const char *uname,
  				   int depth, void *data)
  {
9d0c4dfed   Rob Herring   of/fdt: update of...
951
  	const __be32 *prop;
f00abd949   Grant Likely   of/flattree: Merg...
952
953
954
  
  	if (depth != 0)
  		return 0;
337148812   Jeremy Kerr   of: assume big-en...
955
956
  	dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
  	dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
f00abd949   Grant Likely   of/flattree: Merg...
957
  	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
337148812   Jeremy Kerr   of: assume big-en...
958
959
  	if (prop)
  		dt_root_size_cells = be32_to_cpup(prop);
f00abd949   Grant Likely   of/flattree: Merg...
960
961
962
963
  	pr_debug("dt_root_size_cells = %x
  ", dt_root_size_cells);
  
  	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
337148812   Jeremy Kerr   of: assume big-en...
964
965
  	if (prop)
  		dt_root_addr_cells = be32_to_cpup(prop);
f00abd949   Grant Likely   of/flattree: Merg...
966
967
968
969
970
971
  	pr_debug("dt_root_addr_cells = %x
  ", dt_root_addr_cells);
  
  	/* break now */
  	return 1;
  }
9d0c4dfed   Rob Herring   of/fdt: update of...
972
  u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
83f7a06eb   Grant Likely   of/flattree: merg...
973
  {
9d0c4dfed   Rob Herring   of/fdt: update of...
974
  	const __be32 *p = *cellp;
83f7a06eb   Grant Likely   of/flattree: merg...
975
976
977
978
  
  	*cellp = p + s;
  	return of_read_number(p, s);
  }
51975db0b   Grant Likely   of/flattree: merg...
979
  /**
0ef5adca5   Frank Rowand   of: fdt.c header ...
980
   * early_init_dt_scan_memory - Look for and parse memory nodes
51975db0b   Grant Likely   of/flattree: merg...
981
982
983
984
   */
  int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
  				     int depth, void *data)
  {
9d0c4dfed   Rob Herring   of/fdt: update of...
985
986
987
  	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
  	const __be32 *reg, *endp;
  	int l;
41a9ada3e   Reza Arbab   of/fdt: mark hotp...
988
  	bool hotpluggable;
51975db0b   Grant Likely   of/flattree: merg...
989
990
  
  	/* We are scanning "memory" nodes only */
da653130a   Michael Ellerman   of/fdt: Remove PP...
991
  	if (type == NULL || strcmp(type, "memory") != 0)
51975db0b   Grant Likely   of/flattree: merg...
992
993
994
995
996
997
998
999
1000
  		return 0;
  
  	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
  	if (reg == NULL)
  		reg = of_get_flat_dt_prop(node, "reg", &l);
  	if (reg == NULL)
  		return 0;
  
  	endp = reg + (l / sizeof(__be32));
41a9ada3e   Reza Arbab   of/fdt: mark hotp...
1001
  	hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL);
51975db0b   Grant Likely   of/flattree: merg...
1002

c954b36e3   Florian Fainelli   of/fdt: Remove "r...
1003
1004
  	pr_debug("memory scan node %s, reg size %d,
  ", uname, l);
51975db0b   Grant Likely   of/flattree: merg...
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  
  	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
  		u64 base, size;
  
  		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
  		size = dt_mem_next_cell(dt_root_size_cells, &reg);
  
  		if (size == 0)
  			continue;
  		pr_debug(" - %llx ,  %llx
  ", (unsigned long long)base,
  		    (unsigned long long)size);
  
  		early_init_dt_add_memory_arch(base, size);
41a9ada3e   Reza Arbab   of/fdt: mark hotp...
1019
1020
1021
1022
1023
1024
1025
1026
  
  		if (!hotpluggable)
  			continue;
  
  		if (early_init_dt_mark_hotplug_memory_arch(base, size))
  			pr_warn("failed to mark hotplug range 0x%llx - 0x%llx
  ",
  				base, base + size);
51975db0b   Grant Likely   of/flattree: merg...
1027
1028
1029
1030
  	}
  
  	return 0;
  }
86e032213   Grant Likely   of/flattree: merg...
1031
1032
1033
  int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
  				     int depth, void *data)
  {
9d0c4dfed   Rob Herring   of/fdt: update of...
1034
1035
  	int l;
  	const char *p;
428826f53   Hsin-Yi Wang   fdt: add support ...
1036
  	const void *rng_seed;
86e032213   Grant Likely   of/flattree: merg...
1037
1038
1039
  
  	pr_debug("search \"chosen\", depth: %d, uname: %s
  ", depth, uname);
85f60ae4e   Grant Likely   dt/flattree: expl...
1040
  	if (depth != 1 || !data ||
86e032213   Grant Likely   of/flattree: merg...
1041
1042
1043
1044
  	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
  		return 0;
  
  	early_init_dt_check_for_initrd(node);
25985edce   Lucas De Marchi   Fix common misspe...
1045
  	/* Retrieve command line */
86e032213   Grant Likely   of/flattree: merg...
1046
1047
  	p = of_get_flat_dt_prop(node, "bootargs", &l);
  	if (p != NULL && l > 0)
b827bcbba   xiaojiangfeng   of: del redundant...
1048
  		strlcpy(data, p, min(l, COMMAND_LINE_SIZE));
86e032213   Grant Likely   of/flattree: merg...
1049

78b782cb7   Benjamin Herrenschmidt   of: Change logic ...
1050
1051
1052
1053
1054
  	/*
  	 * CONFIG_CMDLINE is meant to be a default in case nothing else
  	 * managed to set the command line, unless CONFIG_CMDLINE_FORCE
  	 * is set in which case we override whatever was found earlier.
  	 */
86e032213   Grant Likely   of/flattree: merg...
1055
  #ifdef CONFIG_CMDLINE
34b82026a   Max Uvarov   fdt: fix extend o...
1056
1057
1058
1059
1060
1061
1062
  #if defined(CONFIG_CMDLINE_EXTEND)
  	strlcat(data, " ", COMMAND_LINE_SIZE);
  	strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
  #elif defined(CONFIG_CMDLINE_FORCE)
  	strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
  #else
  	/* No arguments from boot loader, use kernel's  cmdl*/
78b782cb7   Benjamin Herrenschmidt   of: Change logic ...
1063
  	if (!((char *)data)[0])
85f60ae4e   Grant Likely   dt/flattree: expl...
1064
  		strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
34b82026a   Max Uvarov   fdt: fix extend o...
1065
  #endif
86e032213   Grant Likely   of/flattree: merg...
1066
  #endif /* CONFIG_CMDLINE */
85f60ae4e   Grant Likely   dt/flattree: expl...
1067
1068
  	pr_debug("Command line is: %s
  ", (char*)data);
86e032213   Grant Likely   of/flattree: merg...
1069

428826f53   Hsin-Yi Wang   fdt: add support ...
1070
1071
1072
1073
1074
1075
  	rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
  	if (rng_seed && l > 0) {
  		add_bootloader_randomness(rng_seed, l);
  
  		/* try to clear seed so it won't be found. */
  		fdt_nop_property(initial_boot_params, node, "rng-seed");
dd753d961   Hsin-Yi Wang   fdt: Update CRC c...
1076
1077
1078
1079
  
  		/* update CRC check value */
  		of_fdt_crc32 = crc32_be(~0, initial_boot_params,
  				fdt_totalsize(initial_boot_params));
428826f53   Hsin-Yi Wang   fdt: add support ...
1080
  	}
86e032213   Grant Likely   of/flattree: merg...
1081
1082
1083
  	/* break now */
  	return 1;
  }
270522a04   Ard Biesheuvel   of/fdt: make memb...
1084
1085
1086
  #ifndef MIN_MEMBLOCK_ADDR
  #define MIN_MEMBLOCK_ADDR	__pa(PAGE_OFFSET)
  #endif
8eafeb480   Ard Biesheuvel   of/fdt: make memb...
1087
1088
1089
  #ifndef MAX_MEMBLOCK_ADDR
  #define MAX_MEMBLOCK_ADDR	((phys_addr_t)~0)
  #endif
3069f0c07   Laura Abbott   of: Use proper ty...
1090

068f6310b   Rob Herring   of: create defaul...
1091
1092
  void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
  {
270522a04   Ard Biesheuvel   of/fdt: make memb...
1093
  	const u64 phys_offset = MIN_MEMBLOCK_ADDR;
8f73d4b70   Geert Uytterhoeven   of: Fix memory bl...
1094

6072cf567   Mike Rapoport   of: ignore sub-pa...
1095
1096
1097
1098
1099
1100
  	if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
  		pr_warn("Ignoring memory block 0x%llx - 0x%llx
  ",
  			base, base + size);
  		return;
  	}
8f73d4b70   Geert Uytterhoeven   of: Fix memory bl...
1101
1102
1103
1104
  	if (!PAGE_ALIGNED(base)) {
  		size -= PAGE_SIZE - (base & ~PAGE_MASK);
  		base = PAGE_ALIGN(base);
  	}
068f6310b   Rob Herring   of: create defaul...
1105
  	size &= PAGE_MASK;
a67a6ed15   Laura Abbott   of: Check for phy...
1106

8eafeb480   Ard Biesheuvel   of/fdt: make memb...
1107
  	if (base > MAX_MEMBLOCK_ADDR) {
3069f0c07   Laura Abbott   of: Use proper ty...
1108
1109
1110
1111
1112
  		pr_warning("Ignoring memory block 0x%llx - 0x%llx
  ",
  				base, base + size);
  		return;
  	}
a67a6ed15   Laura Abbott   of: Check for phy...
1113

8eafeb480   Ard Biesheuvel   of/fdt: make memb...
1114
  	if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
9aacd602f   Srinivas Kandagatla   of/fdt: fix memor...
1115
1116
  		pr_warning("Ignoring memory range 0x%llx - 0x%llx
  ",
8eafeb480   Ard Biesheuvel   of/fdt: make memb...
1117
1118
  				((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
  		size = MAX_MEMBLOCK_ADDR - base + 1;
a67a6ed15   Laura Abbott   of: Check for phy...
1119
  	}
068f6310b   Rob Herring   of: create defaul...
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
  	if (base + size < phys_offset) {
  		pr_warning("Ignoring memory block 0x%llx - 0x%llx
  ",
  			   base, base + size);
  		return;
  	}
  	if (base < phys_offset) {
  		pr_warning("Ignoring memory range 0x%llx - 0x%llx
  ",
  			   base, phys_offset);
  		size -= phys_offset - base;
  		base = phys_offset;
  	}
  	memblock_add(base, size);
  }
41a9ada3e   Reza Arbab   of/fdt: mark hotp...
1135
1136
1137
1138
  int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size)
  {
  	return memblock_mark_hotplug(base, size);
  }
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
1139
1140
1141
  int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
  					phys_addr_t size, bool nomap)
  {
e8d9d1f54   Marek Szyprowski   drivers: of: add ...
1142
1143
1144
1145
  	if (nomap)
  		return memblock_remove(base, size);
  	return memblock_reserve(base, size);
  }
0fa1c5793   Rob Herring   of/fdt: use membl...
1146
  static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
aefc7ec27   Rob Herring   dt/fdt: add empty...
1147
  {
8a7f97b90   Mike Rapoport   treewide: add che...
1148
1149
1150
1151
1152
1153
1154
1155
  	void *ptr = memblock_alloc(size, align);
  
  	if (!ptr)
  		panic("%s: Failed to allocate %llu bytes align=0x%llx
  ",
  		      __func__, size, align);
  
  	return ptr;
aefc7ec27   Rob Herring   dt/fdt: add empty...
1156
  }
a1727da59   Grant Likely   of: consolidate d...
1157

4972a74b8   Laura Abbott   of: Split early_i...
1158
  bool __init early_init_dt_verify(void *params)
0288ffcbf   Rob Herring   of: Introduce com...
1159
1160
1161
  {
  	if (!params)
  		return false;
0288ffcbf   Rob Herring   of: Introduce com...
1162
  	/* check device tree validity */
50ba08f30   Bjorn Helgaas   of/fdt: Don't cle...
1163
  	if (fdt_check_header(params))
0288ffcbf   Rob Herring   of: Introduce com...
1164
  		return false;
0288ffcbf   Rob Herring   of: Introduce com...
1165

50ba08f30   Bjorn Helgaas   of/fdt: Don't cle...
1166
1167
  	/* Setup flat device-tree pointer */
  	initial_boot_params = params;
dd753d961   Hsin-Yi Wang   fdt: Update CRC c...
1168
1169
  	of_fdt_crc32 = crc32_be(~0, initial_boot_params,
  				fdt_totalsize(initial_boot_params));
4972a74b8   Laura Abbott   of: Split early_i...
1170
1171
1172
1173
1174
1175
  	return true;
  }
  
  
  void __init early_init_dt_scan_nodes(void)
  {
e1e525442   Nick Kossifidis   OF: Add a warning...
1176
  	int rc = 0;
0288ffcbf   Rob Herring   of: Introduce com...
1177
  	/* Retrieve various information from the /chosen node */
e1e525442   Nick Kossifidis   OF: Add a warning...
1178
1179
1180
1181
  	rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
  	if (!rc)
  		pr_warn("No chosen node found, continuing without
  ");
0288ffcbf   Rob Herring   of: Introduce com...
1182
1183
1184
1185
1186
1187
  
  	/* Initialize {size,address}-cells info */
  	of_scan_flat_dt(early_init_dt_scan_root, NULL);
  
  	/* Setup memory, calling early_init_dt_add_memory_arch */
  	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
4972a74b8   Laura Abbott   of: Split early_i...
1188
1189
1190
1191
1192
1193
1194
1195
1196
  }
  
  bool __init early_init_dt_scan(void *params)
  {
  	bool status;
  
  	status = early_init_dt_verify(params);
  	if (!status)
  		return false;
0288ffcbf   Rob Herring   of: Introduce com...
1197

4972a74b8   Laura Abbott   of: Split early_i...
1198
  	early_init_dt_scan_nodes();
0288ffcbf   Rob Herring   of: Introduce com...
1199
1200
  	return true;
  }
f00abd949   Grant Likely   of/flattree: Merg...
1201
  /**
41f880091   Grant Likely   of/flattree: Merg...
1202
1203
1204
1205
1206
1207
1208
1209
1210
   * unflatten_device_tree - create tree of device_nodes from flat blob
   *
   * unflattens the device-tree passed by the firmware, creating the
   * tree of struct device_node. It also fills the "name" and "type"
   * pointers of the nodes so the normal device-tree walking functions
   * can be used.
   */
  void __init unflatten_device_tree(void)
  {
c4263233f   Gavin Shan   drivers/of: Speci...
1211
  	__unflatten_device_tree(initial_boot_params, NULL, &of_root,
1d1bde550   Michal Suchanek   of: fdt: mark unf...
1212
  				early_init_dt_alloc_memory_arch, false);
41f880091   Grant Likely   of/flattree: Merg...
1213

4c7d6361f   Robert P. J. Day   open firmware: "/...
1214
  	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
611cad720   Shawn Guo   dt: add of_alias_...
1215
  	of_alias_scan(early_init_dt_alloc_memory_arch);
81d0848fc   Frank Rowand   of: Add unit test...
1216
1217
  
  	unittest_unflatten_overlay_base();
41f880091   Grant Likely   of/flattree: Merg...
1218
  }
e6ce1324e   Stephen Neuendorffer   of/flattree: Add ...
1219

a8bf7527a   Rob Herring   of: create unflat...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
  /**
   * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob
   *
   * Copies and unflattens the device-tree passed by the firmware, creating the
   * tree of struct device_node. It also fills the "name" and "type"
   * pointers of the nodes so the normal device-tree walking functions
   * can be used. This should only be used when the FDT memory has not been
   * reserved such is the case when the FDT is built-in to the kernel init
   * section. If the FDT memory is reserved already then unflatten_device_tree
   * should be used instead.
   */
  void __init unflatten_and_copy_device_tree(void)
  {
6f041e99f   James Hogan   of: Fix NULL dere...
1233
1234
1235
1236
1237
1238
1239
1240
  	int size;
  	void *dt;
  
  	if (!initial_boot_params) {
  		pr_warn("No valid device tree found, continuing without
  ");
  		return;
  	}
c972de149   Rob Herring   of/fdt: use libfd...
1241
  	size = fdt_totalsize(initial_boot_params);
6f041e99f   James Hogan   of: Fix NULL dere...
1242
  	dt = early_init_dt_alloc_memory_arch(size,
c972de149   Rob Herring   of/fdt: use libfd...
1243
  					     roundup_pow_of_two(FDT_V17_SIZE));
a8bf7527a   Rob Herring   of: create unflat...
1244
1245
1246
1247
1248
1249
1250
  
  	if (dt) {
  		memcpy(dt, initial_boot_params, size);
  		initial_boot_params = dt;
  	}
  	unflatten_device_tree();
  }
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1251
1252
1253
1254
  #ifdef CONFIG_SYSFS
  static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj,
  			       struct bin_attribute *bin_attr,
  			       char *buf, loff_t off, size_t count)
b0a6fb36a   Rob Herring   of/fdt: create co...
1255
  {
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1256
1257
1258
  	memcpy(buf, initial_boot_params + off, count);
  	return count;
  }
b0a6fb36a   Rob Herring   of/fdt: create co...
1259

08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1260
1261
1262
1263
  static int __init of_fdt_raw_init(void)
  {
  	static struct bin_attribute of_fdt_raw_attr =
  		__BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0);
b0a6fb36a   Rob Herring   of/fdt: create co...
1264

08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1265
1266
  	if (!initial_boot_params)
  		return 0;
b0a6fb36a   Rob Herring   of/fdt: create co...
1267

08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1268
1269
  	if (of_fdt_crc32 != crc32_be(~0, initial_boot_params,
  				     fdt_totalsize(initial_boot_params))) {
606ad42aa   Rob Herring   of: use pr_fmt pr...
1270
1271
  		pr_warn("not creating '/sys/firmware/fdt': CRC check failed
  ");
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1272
1273
1274
1275
  		return 0;
  	}
  	of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params);
  	return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr);
b0a6fb36a   Rob Herring   of/fdt: create co...
1276
  }
08d53aa58   Ard Biesheuvel   of/fdt: export fd...
1277
  late_initcall(of_fdt_raw_init);
b0a6fb36a   Rob Herring   of/fdt: create co...
1278
  #endif
e6ce1324e   Stephen Neuendorffer   of/flattree: Add ...
1279
  #endif /* CONFIG_OF_EARLY_FLATTREE */