xref: /openbmc/linux/drivers/of/fdt.c (revision 29eb45a9)
1e169cfbeSGrant Likely /*
2e169cfbeSGrant Likely  * Functions for working with the Flattened Device Tree data format
3e169cfbeSGrant Likely  *
4e169cfbeSGrant Likely  * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
5e169cfbeSGrant Likely  * benh@kernel.crashing.org
6e169cfbeSGrant Likely  *
7e169cfbeSGrant Likely  * This program is free software; you can redistribute it and/or
8e169cfbeSGrant Likely  * modify it under the terms of the GNU General Public License
9e169cfbeSGrant Likely  * version 2 as published by the Free Software Foundation.
10e169cfbeSGrant Likely  */
11e169cfbeSGrant Likely 
1241f88009SGrant Likely #include <linux/kernel.h>
13f7b3a835SGrant Likely #include <linux/initrd.h>
14a1727da5SGrant Likely #include <linux/memblock.h>
15fe140423SStephen Neuendorffer #include <linux/module.h>
16e169cfbeSGrant Likely #include <linux/of.h>
17e169cfbeSGrant Likely #include <linux/of_fdt.h>
184ef7b373SJeremy Kerr #include <linux/string.h>
194ef7b373SJeremy Kerr #include <linux/errno.h>
20fe140423SStephen Neuendorffer #include <linux/slab.h>
21109b6236SAnton Blanchard #include <linux/random.h>
2251975db0SGrant Likely 
23c89810acSFabio Estevam #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
2486e03221SGrant Likely #ifdef CONFIG_PPC
2586e03221SGrant Likely #include <asm/machdep.h>
2686e03221SGrant Likely #endif /* CONFIG_PPC */
2786e03221SGrant Likely 
284ef7b373SJeremy Kerr #include <asm/page.h>
294ef7b373SJeremy Kerr 
309706a36eSStephen Neuendorffer char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
319706a36eSStephen Neuendorffer {
329706a36eSStephen Neuendorffer 	return ((char *)blob) +
339706a36eSStephen Neuendorffer 		be32_to_cpu(blob->off_dt_strings) + offset;
349706a36eSStephen Neuendorffer }
359706a36eSStephen Neuendorffer 
369706a36eSStephen Neuendorffer /**
379706a36eSStephen Neuendorffer  * of_fdt_get_property - Given a node in the given flat blob, return
389706a36eSStephen Neuendorffer  * the property ptr
399706a36eSStephen Neuendorffer  */
409706a36eSStephen Neuendorffer void *of_fdt_get_property(struct boot_param_header *blob,
419706a36eSStephen Neuendorffer 		       unsigned long node, const char *name,
429706a36eSStephen Neuendorffer 		       unsigned long *size)
439706a36eSStephen Neuendorffer {
449706a36eSStephen Neuendorffer 	unsigned long p = node;
459706a36eSStephen Neuendorffer 
469706a36eSStephen Neuendorffer 	do {
479706a36eSStephen Neuendorffer 		u32 tag = be32_to_cpup((__be32 *)p);
489706a36eSStephen Neuendorffer 		u32 sz, noff;
499706a36eSStephen Neuendorffer 		const char *nstr;
509706a36eSStephen Neuendorffer 
519706a36eSStephen Neuendorffer 		p += 4;
529706a36eSStephen Neuendorffer 		if (tag == OF_DT_NOP)
539706a36eSStephen Neuendorffer 			continue;
549706a36eSStephen Neuendorffer 		if (tag != OF_DT_PROP)
559706a36eSStephen Neuendorffer 			return NULL;
569706a36eSStephen Neuendorffer 
579706a36eSStephen Neuendorffer 		sz = be32_to_cpup((__be32 *)p);
589706a36eSStephen Neuendorffer 		noff = be32_to_cpup((__be32 *)(p + 4));
599706a36eSStephen Neuendorffer 		p += 8;
609706a36eSStephen Neuendorffer 		if (be32_to_cpu(blob->version) < 0x10)
619706a36eSStephen Neuendorffer 			p = ALIGN(p, sz >= 8 ? 8 : 4);
629706a36eSStephen Neuendorffer 
639706a36eSStephen Neuendorffer 		nstr = of_fdt_get_string(blob, noff);
649706a36eSStephen Neuendorffer 		if (nstr == NULL) {
659706a36eSStephen Neuendorffer 			pr_warning("Can't find property index name !\n");
669706a36eSStephen Neuendorffer 			return NULL;
679706a36eSStephen Neuendorffer 		}
689706a36eSStephen Neuendorffer 		if (strcmp(name, nstr) == 0) {
699706a36eSStephen Neuendorffer 			if (size)
709706a36eSStephen Neuendorffer 				*size = sz;
719706a36eSStephen Neuendorffer 			return (void *)p;
729706a36eSStephen Neuendorffer 		}
739706a36eSStephen Neuendorffer 		p += sz;
749706a36eSStephen Neuendorffer 		p = ALIGN(p, 4);
759706a36eSStephen Neuendorffer 	} while (1);
769706a36eSStephen Neuendorffer }
779706a36eSStephen Neuendorffer 
789706a36eSStephen Neuendorffer /**
799706a36eSStephen Neuendorffer  * of_fdt_is_compatible - Return true if given node from the given blob has
809706a36eSStephen Neuendorffer  * compat in its compatible list
819706a36eSStephen Neuendorffer  * @blob: A device tree blob
829706a36eSStephen Neuendorffer  * @node: node to test
839706a36eSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
84a4f740cfSGrant Likely  *
85a4f740cfSGrant Likely  * On match, returns a non-zero value with smaller values returned for more
86a4f740cfSGrant Likely  * specific compatible values.
879706a36eSStephen Neuendorffer  */
889706a36eSStephen Neuendorffer int of_fdt_is_compatible(struct boot_param_header *blob,
899706a36eSStephen Neuendorffer 		      unsigned long node, const char *compat)
909706a36eSStephen Neuendorffer {
919706a36eSStephen Neuendorffer 	const char *cp;
92a4f740cfSGrant Likely 	unsigned long cplen, l, score = 0;
939706a36eSStephen Neuendorffer 
949706a36eSStephen Neuendorffer 	cp = of_fdt_get_property(blob, node, "compatible", &cplen);
959706a36eSStephen Neuendorffer 	if (cp == NULL)
969706a36eSStephen Neuendorffer 		return 0;
979706a36eSStephen Neuendorffer 	while (cplen > 0) {
98a4f740cfSGrant Likely 		score++;
999706a36eSStephen Neuendorffer 		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
100a4f740cfSGrant Likely 			return score;
1019706a36eSStephen Neuendorffer 		l = strlen(cp) + 1;
1029706a36eSStephen Neuendorffer 		cp += l;
1039706a36eSStephen Neuendorffer 		cplen -= l;
1049706a36eSStephen Neuendorffer 	}
1059706a36eSStephen Neuendorffer 
1069706a36eSStephen Neuendorffer 	return 0;
1079706a36eSStephen Neuendorffer }
1089706a36eSStephen Neuendorffer 
109a4f740cfSGrant Likely /**
110a4f740cfSGrant Likely  * of_fdt_match - Return true if node matches a list of compatible values
111a4f740cfSGrant Likely  */
112a4f740cfSGrant Likely int of_fdt_match(struct boot_param_header *blob, unsigned long node,
1137b482c83SUwe Kleine-König                  const char *const *compat)
114a4f740cfSGrant Likely {
115a4f740cfSGrant Likely 	unsigned int tmp, score = 0;
116a4f740cfSGrant Likely 
117a4f740cfSGrant Likely 	if (!compat)
118a4f740cfSGrant Likely 		return 0;
119a4f740cfSGrant Likely 
120a4f740cfSGrant Likely 	while (*compat) {
121a4f740cfSGrant Likely 		tmp = of_fdt_is_compatible(blob, node, *compat);
122a4f740cfSGrant Likely 		if (tmp && (score == 0 || (tmp < score)))
123a4f740cfSGrant Likely 			score = tmp;
124a4f740cfSGrant Likely 		compat++;
125a4f740cfSGrant Likely 	}
126a4f740cfSGrant Likely 
127a4f740cfSGrant Likely 	return score;
128a4f740cfSGrant Likely }
129a4f740cfSGrant Likely 
13044856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size,
131bbd33931SGrant Likely 				       unsigned long align)
132bbd33931SGrant Likely {
133bbd33931SGrant Likely 	void *res;
134bbd33931SGrant Likely 
13544856819SGrant Likely 	*mem = PTR_ALIGN(*mem, align);
13644856819SGrant Likely 	res = *mem;
137bbd33931SGrant Likely 	*mem += size;
138bbd33931SGrant Likely 
139bbd33931SGrant Likely 	return res;
140bbd33931SGrant Likely }
141bbd33931SGrant Likely 
142bbd33931SGrant Likely /**
143bbd33931SGrant Likely  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
144a40d6c4cSStephen Neuendorffer  * @blob: The parent device tree blob
145a7006c97SAndres Salomon  * @mem: Memory chunk to use for allocating device nodes and properties
146bbd33931SGrant Likely  * @p: pointer to node in flat tree
147bbd33931SGrant Likely  * @dad: Parent struct device_node
148bbd33931SGrant Likely  * @allnextpp: pointer to ->allnext from last allocated device_node
149bbd33931SGrant Likely  * @fpsize: Size of the node path up at the current depth.
150bbd33931SGrant Likely  */
15144856819SGrant Likely static void * unflatten_dt_node(struct boot_param_header *blob,
15244856819SGrant Likely 				void *mem,
15344856819SGrant Likely 				void **p,
154bbd33931SGrant Likely 				struct device_node *dad,
155bbd33931SGrant Likely 				struct device_node ***allnextpp,
156bbd33931SGrant Likely 				unsigned long fpsize)
157bbd33931SGrant Likely {
158bbd33931SGrant Likely 	struct device_node *np;
159bbd33931SGrant Likely 	struct property *pp, **prev_pp = NULL;
160bbd33931SGrant Likely 	char *pathp;
161bbd33931SGrant Likely 	u32 tag;
162bbd33931SGrant Likely 	unsigned int l, allocl;
163bbd33931SGrant Likely 	int has_name = 0;
164bbd33931SGrant Likely 	int new_format = 0;
165bbd33931SGrant Likely 
16644856819SGrant Likely 	tag = be32_to_cpup(*p);
167bbd33931SGrant Likely 	if (tag != OF_DT_BEGIN_NODE) {
168bbd33931SGrant Likely 		pr_err("Weird tag at start of node: %x\n", tag);
169bbd33931SGrant Likely 		return mem;
170bbd33931SGrant Likely 	}
171bbd33931SGrant Likely 	*p += 4;
17244856819SGrant Likely 	pathp = *p;
173bbd33931SGrant Likely 	l = allocl = strlen(pathp) + 1;
17444856819SGrant Likely 	*p = PTR_ALIGN(*p + l, 4);
175bbd33931SGrant Likely 
176bbd33931SGrant Likely 	/* version 0x10 has a more compact unit name here instead of the full
177bbd33931SGrant Likely 	 * path. we accumulate the full path size using "fpsize", we'll rebuild
178bbd33931SGrant Likely 	 * it later. We detect this because the first character of the name is
179bbd33931SGrant Likely 	 * not '/'.
180bbd33931SGrant Likely 	 */
181bbd33931SGrant Likely 	if ((*pathp) != '/') {
182bbd33931SGrant Likely 		new_format = 1;
183bbd33931SGrant Likely 		if (fpsize == 0) {
184bbd33931SGrant Likely 			/* root node: special case. fpsize accounts for path
185bbd33931SGrant Likely 			 * plus terminating zero. root node only has '/', so
186bbd33931SGrant Likely 			 * fpsize should be 2, but we want to avoid the first
187bbd33931SGrant Likely 			 * level nodes to have two '/' so we use fpsize 1 here
188bbd33931SGrant Likely 			 */
189bbd33931SGrant Likely 			fpsize = 1;
190bbd33931SGrant Likely 			allocl = 2;
1910fca5deaSCatalin Marinas 			l = 1;
1920fca5deaSCatalin Marinas 			*pathp = '\0';
193bbd33931SGrant Likely 		} else {
194bbd33931SGrant Likely 			/* account for '/' and path size minus terminal 0
195bbd33931SGrant Likely 			 * already in 'l'
196bbd33931SGrant Likely 			 */
197bbd33931SGrant Likely 			fpsize += l;
198bbd33931SGrant Likely 			allocl = fpsize;
199bbd33931SGrant Likely 		}
200bbd33931SGrant Likely 	}
201bbd33931SGrant Likely 
202bbd33931SGrant Likely 	np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
203bbd33931SGrant Likely 				__alignof__(struct device_node));
204bbd33931SGrant Likely 	if (allnextpp) {
205c22618a1SGrant Likely 		char *fn;
206c22618a1SGrant Likely 		np->full_name = fn = ((char *)np) + sizeof(*np);
207bbd33931SGrant Likely 		if (new_format) {
208bbd33931SGrant Likely 			/* rebuild full path for new format */
209bbd33931SGrant Likely 			if (dad && dad->parent) {
210bbd33931SGrant Likely 				strcpy(fn, dad->full_name);
211bbd33931SGrant Likely #ifdef DEBUG
212bbd33931SGrant Likely 				if ((strlen(fn) + l + 1) != allocl) {
213bbd33931SGrant Likely 					pr_debug("%s: p: %d, l: %d, a: %d\n",
214bbd33931SGrant Likely 						pathp, (int)strlen(fn),
215bbd33931SGrant Likely 						l, allocl);
216bbd33931SGrant Likely 				}
217bbd33931SGrant Likely #endif
218bbd33931SGrant Likely 				fn += strlen(fn);
219bbd33931SGrant Likely 			}
220bbd33931SGrant Likely 			*(fn++) = '/';
221c22618a1SGrant Likely 		}
222bbd33931SGrant Likely 		memcpy(fn, pathp, l);
223c22618a1SGrant Likely 
224bbd33931SGrant Likely 		prev_pp = &np->properties;
225bbd33931SGrant Likely 		**allnextpp = np;
226bbd33931SGrant Likely 		*allnextpp = &np->allnext;
227bbd33931SGrant Likely 		if (dad != NULL) {
228bbd33931SGrant Likely 			np->parent = dad;
229bbd33931SGrant Likely 			/* we temporarily use the next field as `last_child'*/
230bbd33931SGrant Likely 			if (dad->next == NULL)
231bbd33931SGrant Likely 				dad->child = np;
232bbd33931SGrant Likely 			else
233bbd33931SGrant Likely 				dad->next->sibling = np;
234bbd33931SGrant Likely 			dad->next = np;
235bbd33931SGrant Likely 		}
236bbd33931SGrant Likely 		kref_init(&np->kref);
237bbd33931SGrant Likely 	}
238a7006c97SAndres Salomon 	/* process properties */
239bbd33931SGrant Likely 	while (1) {
240bbd33931SGrant Likely 		u32 sz, noff;
241bbd33931SGrant Likely 		char *pname;
242bbd33931SGrant Likely 
24344856819SGrant Likely 		tag = be32_to_cpup(*p);
244bbd33931SGrant Likely 		if (tag == OF_DT_NOP) {
245bbd33931SGrant Likely 			*p += 4;
246bbd33931SGrant Likely 			continue;
247bbd33931SGrant Likely 		}
248bbd33931SGrant Likely 		if (tag != OF_DT_PROP)
249bbd33931SGrant Likely 			break;
250bbd33931SGrant Likely 		*p += 4;
25144856819SGrant Likely 		sz = be32_to_cpup(*p);
25244856819SGrant Likely 		noff = be32_to_cpup(*p + 4);
253bbd33931SGrant Likely 		*p += 8;
254a40d6c4cSStephen Neuendorffer 		if (be32_to_cpu(blob->version) < 0x10)
25544856819SGrant Likely 			*p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4);
256bbd33931SGrant Likely 
257a40d6c4cSStephen Neuendorffer 		pname = of_fdt_get_string(blob, noff);
258bbd33931SGrant Likely 		if (pname == NULL) {
259bbd33931SGrant Likely 			pr_info("Can't find property name in list !\n");
260bbd33931SGrant Likely 			break;
261bbd33931SGrant Likely 		}
262bbd33931SGrant Likely 		if (strcmp(pname, "name") == 0)
263bbd33931SGrant Likely 			has_name = 1;
264bbd33931SGrant Likely 		l = strlen(pname) + 1;
265bbd33931SGrant Likely 		pp = unflatten_dt_alloc(&mem, sizeof(struct property),
266bbd33931SGrant Likely 					__alignof__(struct property));
267bbd33931SGrant Likely 		if (allnextpp) {
26804b954a6SDavid Gibson 			/* We accept flattened tree phandles either in
26904b954a6SDavid Gibson 			 * ePAPR-style "phandle" properties, or the
27004b954a6SDavid Gibson 			 * legacy "linux,phandle" properties.  If both
27104b954a6SDavid Gibson 			 * appear and have different values, things
27204b954a6SDavid Gibson 			 * will get weird.  Don't do that. */
27304b954a6SDavid Gibson 			if ((strcmp(pname, "phandle") == 0) ||
27404b954a6SDavid Gibson 			    (strcmp(pname, "linux,phandle") == 0)) {
2756016a363SGrant Likely 				if (np->phandle == 0)
2769a6b2e58SGrant Likely 					np->phandle = be32_to_cpup((__be32*)*p);
277bbd33931SGrant Likely 			}
27804b954a6SDavid Gibson 			/* And we process the "ibm,phandle" property
27904b954a6SDavid Gibson 			 * used in pSeries dynamic device tree
28004b954a6SDavid Gibson 			 * stuff */
281bbd33931SGrant Likely 			if (strcmp(pname, "ibm,phandle") == 0)
2829a6b2e58SGrant Likely 				np->phandle = be32_to_cpup((__be32 *)*p);
283bbd33931SGrant Likely 			pp->name = pname;
284bbd33931SGrant Likely 			pp->length = sz;
28544856819SGrant Likely 			pp->value = *p;
286bbd33931SGrant Likely 			*prev_pp = pp;
287bbd33931SGrant Likely 			prev_pp = &pp->next;
288bbd33931SGrant Likely 		}
28944856819SGrant Likely 		*p = PTR_ALIGN((*p) + sz, 4);
290bbd33931SGrant Likely 	}
291bbd33931SGrant Likely 	/* with version 0x10 we may not have the name property, recreate
292bbd33931SGrant Likely 	 * it here from the unit name if absent
293bbd33931SGrant Likely 	 */
294bbd33931SGrant Likely 	if (!has_name) {
295bbd33931SGrant Likely 		char *p1 = pathp, *ps = pathp, *pa = NULL;
296bbd33931SGrant Likely 		int sz;
297bbd33931SGrant Likely 
298bbd33931SGrant Likely 		while (*p1) {
299bbd33931SGrant Likely 			if ((*p1) == '@')
300bbd33931SGrant Likely 				pa = p1;
301bbd33931SGrant Likely 			if ((*p1) == '/')
302bbd33931SGrant Likely 				ps = p1 + 1;
303bbd33931SGrant Likely 			p1++;
304bbd33931SGrant Likely 		}
305bbd33931SGrant Likely 		if (pa < ps)
306bbd33931SGrant Likely 			pa = p1;
307bbd33931SGrant Likely 		sz = (pa - ps) + 1;
308bbd33931SGrant Likely 		pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
309bbd33931SGrant Likely 					__alignof__(struct property));
310bbd33931SGrant Likely 		if (allnextpp) {
311bbd33931SGrant Likely 			pp->name = "name";
312bbd33931SGrant Likely 			pp->length = sz;
313bbd33931SGrant Likely 			pp->value = pp + 1;
314bbd33931SGrant Likely 			*prev_pp = pp;
315bbd33931SGrant Likely 			prev_pp = &pp->next;
316bbd33931SGrant Likely 			memcpy(pp->value, ps, sz - 1);
317bbd33931SGrant Likely 			((char *)pp->value)[sz - 1] = 0;
318bbd33931SGrant Likely 			pr_debug("fixed up name for %s -> %s\n", pathp,
319bbd33931SGrant Likely 				(char *)pp->value);
320bbd33931SGrant Likely 		}
321bbd33931SGrant Likely 	}
322bbd33931SGrant Likely 	if (allnextpp) {
323bbd33931SGrant Likely 		*prev_pp = NULL;
324bbd33931SGrant Likely 		np->name = of_get_property(np, "name", NULL);
325bbd33931SGrant Likely 		np->type = of_get_property(np, "device_type", NULL);
326bbd33931SGrant Likely 
327bbd33931SGrant Likely 		if (!np->name)
328bbd33931SGrant Likely 			np->name = "<NULL>";
329bbd33931SGrant Likely 		if (!np->type)
330bbd33931SGrant Likely 			np->type = "<NULL>";
331bbd33931SGrant Likely 	}
3327f809e1fSJason Gunthorpe 	while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
3337f809e1fSJason Gunthorpe 		if (tag == OF_DT_NOP)
3347f809e1fSJason Gunthorpe 			*p += 4;
3357f809e1fSJason Gunthorpe 		else
336a40d6c4cSStephen Neuendorffer 			mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
337a40d6c4cSStephen Neuendorffer 						fpsize);
33844856819SGrant Likely 		tag = be32_to_cpup(*p);
339bbd33931SGrant Likely 	}
340bbd33931SGrant Likely 	if (tag != OF_DT_END_NODE) {
341bbd33931SGrant Likely 		pr_err("Weird tag at end of node: %x\n", tag);
342bbd33931SGrant Likely 		return mem;
343bbd33931SGrant Likely 	}
344bbd33931SGrant Likely 	*p += 4;
345bbd33931SGrant Likely 	return mem;
346bbd33931SGrant Likely }
34741f88009SGrant Likely 
348fe140423SStephen Neuendorffer /**
349fe140423SStephen Neuendorffer  * __unflatten_device_tree - create tree of device_nodes from flat blob
350fe140423SStephen Neuendorffer  *
351fe140423SStephen Neuendorffer  * unflattens a device-tree, creating the
352fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
353fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
354fe140423SStephen Neuendorffer  * can be used.
355fe140423SStephen Neuendorffer  * @blob: The blob to expand
356fe140423SStephen Neuendorffer  * @mynodes: The device_node tree created by the call
357fe140423SStephen Neuendorffer  * @dt_alloc: An allocator that provides a virtual address to memory
358fe140423SStephen Neuendorffer  * for the resulting tree
359fe140423SStephen Neuendorffer  */
360a7006c97SAndres Salomon static void __unflatten_device_tree(struct boot_param_header *blob,
361fe140423SStephen Neuendorffer 			     struct device_node **mynodes,
362fe140423SStephen Neuendorffer 			     void * (*dt_alloc)(u64 size, u64 align))
363fe140423SStephen Neuendorffer {
36444856819SGrant Likely 	unsigned long size;
36544856819SGrant Likely 	void *start, *mem;
366fe140423SStephen Neuendorffer 	struct device_node **allnextp = mynodes;
367fe140423SStephen Neuendorffer 
368fe140423SStephen Neuendorffer 	pr_debug(" -> unflatten_device_tree()\n");
369fe140423SStephen Neuendorffer 
370fe140423SStephen Neuendorffer 	if (!blob) {
371fe140423SStephen Neuendorffer 		pr_debug("No device tree pointer\n");
372fe140423SStephen Neuendorffer 		return;
373fe140423SStephen Neuendorffer 	}
374fe140423SStephen Neuendorffer 
375fe140423SStephen Neuendorffer 	pr_debug("Unflattening device tree:\n");
376fe140423SStephen Neuendorffer 	pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
377fe140423SStephen Neuendorffer 	pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
378fe140423SStephen Neuendorffer 	pr_debug("version: %08x\n", be32_to_cpu(blob->version));
379fe140423SStephen Neuendorffer 
380fe140423SStephen Neuendorffer 	if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
381fe140423SStephen Neuendorffer 		pr_err("Invalid device tree blob header\n");
382fe140423SStephen Neuendorffer 		return;
383fe140423SStephen Neuendorffer 	}
384fe140423SStephen Neuendorffer 
385fe140423SStephen Neuendorffer 	/* First pass, scan for size */
38644856819SGrant Likely 	start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
38744856819SGrant Likely 	size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
38844856819SGrant Likely 	size = ALIGN(size, 4);
389fe140423SStephen Neuendorffer 
390fe140423SStephen Neuendorffer 	pr_debug("  size is %lx, allocating...\n", size);
391fe140423SStephen Neuendorffer 
392fe140423SStephen Neuendorffer 	/* Allocate memory for the expanded device tree */
39344856819SGrant Likely 	mem = dt_alloc(size + 4, __alignof__(struct device_node));
39444856819SGrant Likely 	memset(mem, 0, size);
395fe140423SStephen Neuendorffer 
39644856819SGrant Likely 	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
3979e401275SWladislav Wiebe 
39844856819SGrant Likely 	pr_debug("  unflattening %p...\n", mem);
399fe140423SStephen Neuendorffer 
400fe140423SStephen Neuendorffer 	/* Second pass, do actual unflattening */
40144856819SGrant Likely 	start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
402fe140423SStephen Neuendorffer 	unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
40344856819SGrant Likely 	if (be32_to_cpup(start) != OF_DT_END)
40444856819SGrant Likely 		pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start));
40544856819SGrant Likely 	if (be32_to_cpup(mem + size) != 0xdeadbeef)
406fe140423SStephen Neuendorffer 		pr_warning("End of tree marker overwritten: %08x\n",
40744856819SGrant Likely 			   be32_to_cpup(mem + size));
408fe140423SStephen Neuendorffer 	*allnextp = NULL;
409fe140423SStephen Neuendorffer 
410fe140423SStephen Neuendorffer 	pr_debug(" <- unflatten_device_tree()\n");
411fe140423SStephen Neuendorffer }
412fe140423SStephen Neuendorffer 
413fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align)
414fe140423SStephen Neuendorffer {
415fe140423SStephen Neuendorffer 	return kzalloc(size, GFP_KERNEL);
416fe140423SStephen Neuendorffer }
417fe140423SStephen Neuendorffer 
418fe140423SStephen Neuendorffer /**
419fe140423SStephen Neuendorffer  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
420fe140423SStephen Neuendorffer  *
421fe140423SStephen Neuendorffer  * unflattens the device-tree passed by the firmware, creating the
422fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
423fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
424fe140423SStephen Neuendorffer  * can be used.
425fe140423SStephen Neuendorffer  */
426fe140423SStephen Neuendorffer void of_fdt_unflatten_tree(unsigned long *blob,
427fe140423SStephen Neuendorffer 			struct device_node **mynodes)
428fe140423SStephen Neuendorffer {
429fe140423SStephen Neuendorffer 	struct boot_param_header *device_tree =
430fe140423SStephen Neuendorffer 		(struct boot_param_header *)blob;
431fe140423SStephen Neuendorffer 	__unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
432fe140423SStephen Neuendorffer }
433fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
434fe140423SStephen Neuendorffer 
43557d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */
43657d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells;
43757d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells;
43857d00ecfSStephen Neuendorffer 
43957d00ecfSStephen Neuendorffer struct boot_param_header *initial_boot_params;
44057d00ecfSStephen Neuendorffer 
44157d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE
44257d00ecfSStephen Neuendorffer 
44357d00ecfSStephen Neuendorffer /**
44457d00ecfSStephen Neuendorffer  * of_scan_flat_dt - scan flattened tree blob and call callback on each.
44557d00ecfSStephen Neuendorffer  * @it: callback function
44657d00ecfSStephen Neuendorffer  * @data: context data pointer
44757d00ecfSStephen Neuendorffer  *
44857d00ecfSStephen Neuendorffer  * This function is used to scan the flattened device-tree, it is
44957d00ecfSStephen Neuendorffer  * used to extract the memory information at boot before we can
45057d00ecfSStephen Neuendorffer  * unflatten the tree
45157d00ecfSStephen Neuendorffer  */
45257d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node,
45357d00ecfSStephen Neuendorffer 				     const char *uname, int depth,
45457d00ecfSStephen Neuendorffer 				     void *data),
45557d00ecfSStephen Neuendorffer 			   void *data)
45657d00ecfSStephen Neuendorffer {
45757d00ecfSStephen Neuendorffer 	unsigned long p = ((unsigned long)initial_boot_params) +
45857d00ecfSStephen Neuendorffer 		be32_to_cpu(initial_boot_params->off_dt_struct);
45957d00ecfSStephen Neuendorffer 	int rc = 0;
46057d00ecfSStephen Neuendorffer 	int depth = -1;
46157d00ecfSStephen Neuendorffer 
46257d00ecfSStephen Neuendorffer 	do {
46357d00ecfSStephen Neuendorffer 		u32 tag = be32_to_cpup((__be32 *)p);
464e55b0829SFabio Estevam 		const char *pathp;
46557d00ecfSStephen Neuendorffer 
46657d00ecfSStephen Neuendorffer 		p += 4;
46757d00ecfSStephen Neuendorffer 		if (tag == OF_DT_END_NODE) {
46857d00ecfSStephen Neuendorffer 			depth--;
46957d00ecfSStephen Neuendorffer 			continue;
47057d00ecfSStephen Neuendorffer 		}
47157d00ecfSStephen Neuendorffer 		if (tag == OF_DT_NOP)
47257d00ecfSStephen Neuendorffer 			continue;
47357d00ecfSStephen Neuendorffer 		if (tag == OF_DT_END)
47457d00ecfSStephen Neuendorffer 			break;
47557d00ecfSStephen Neuendorffer 		if (tag == OF_DT_PROP) {
47657d00ecfSStephen Neuendorffer 			u32 sz = be32_to_cpup((__be32 *)p);
47757d00ecfSStephen Neuendorffer 			p += 8;
47857d00ecfSStephen Neuendorffer 			if (be32_to_cpu(initial_boot_params->version) < 0x10)
47957d00ecfSStephen Neuendorffer 				p = ALIGN(p, sz >= 8 ? 8 : 4);
48057d00ecfSStephen Neuendorffer 			p += sz;
48157d00ecfSStephen Neuendorffer 			p = ALIGN(p, 4);
48257d00ecfSStephen Neuendorffer 			continue;
48357d00ecfSStephen Neuendorffer 		}
48457d00ecfSStephen Neuendorffer 		if (tag != OF_DT_BEGIN_NODE) {
48557d00ecfSStephen Neuendorffer 			pr_err("Invalid tag %x in flat device tree!\n", tag);
48657d00ecfSStephen Neuendorffer 			return -EINVAL;
48757d00ecfSStephen Neuendorffer 		}
48857d00ecfSStephen Neuendorffer 		depth++;
48957d00ecfSStephen Neuendorffer 		pathp = (char *)p;
49057d00ecfSStephen Neuendorffer 		p = ALIGN(p + strlen(pathp) + 1, 4);
491375da3a7SAndy Shevchenko 		if (*pathp == '/')
492375da3a7SAndy Shevchenko 			pathp = kbasename(pathp);
49357d00ecfSStephen Neuendorffer 		rc = it(p, pathp, depth, data);
49457d00ecfSStephen Neuendorffer 		if (rc != 0)
49557d00ecfSStephen Neuendorffer 			break;
49657d00ecfSStephen Neuendorffer 	} while (1);
49757d00ecfSStephen Neuendorffer 
49857d00ecfSStephen Neuendorffer 	return rc;
49957d00ecfSStephen Neuendorffer }
50057d00ecfSStephen Neuendorffer 
50157d00ecfSStephen Neuendorffer /**
50257d00ecfSStephen Neuendorffer  * of_get_flat_dt_root - find the root node in the flat blob
50357d00ecfSStephen Neuendorffer  */
50457d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void)
50557d00ecfSStephen Neuendorffer {
50657d00ecfSStephen Neuendorffer 	unsigned long p = ((unsigned long)initial_boot_params) +
50757d00ecfSStephen Neuendorffer 		be32_to_cpu(initial_boot_params->off_dt_struct);
50857d00ecfSStephen Neuendorffer 
50957d00ecfSStephen Neuendorffer 	while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
51057d00ecfSStephen Neuendorffer 		p += 4;
51157d00ecfSStephen Neuendorffer 	BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
51257d00ecfSStephen Neuendorffer 	p += 4;
51357d00ecfSStephen Neuendorffer 	return ALIGN(p + strlen((char *)p) + 1, 4);
51457d00ecfSStephen Neuendorffer }
51557d00ecfSStephen Neuendorffer 
51657d00ecfSStephen Neuendorffer /**
51757d00ecfSStephen Neuendorffer  * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
51857d00ecfSStephen Neuendorffer  *
51957d00ecfSStephen Neuendorffer  * This function can be used within scan_flattened_dt callback to get
52057d00ecfSStephen Neuendorffer  * access to properties
52157d00ecfSStephen Neuendorffer  */
52257d00ecfSStephen Neuendorffer void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
52357d00ecfSStephen Neuendorffer 				 unsigned long *size)
52457d00ecfSStephen Neuendorffer {
52557d00ecfSStephen Neuendorffer 	return of_fdt_get_property(initial_boot_params, node, name, size);
52657d00ecfSStephen Neuendorffer }
52757d00ecfSStephen Neuendorffer 
52857d00ecfSStephen Neuendorffer /**
52957d00ecfSStephen Neuendorffer  * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
53057d00ecfSStephen Neuendorffer  * @node: node to test
53157d00ecfSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
53257d00ecfSStephen Neuendorffer  */
53357d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
53457d00ecfSStephen Neuendorffer {
53557d00ecfSStephen Neuendorffer 	return of_fdt_is_compatible(initial_boot_params, node, compat);
53657d00ecfSStephen Neuendorffer }
53757d00ecfSStephen Neuendorffer 
538a4f740cfSGrant Likely /**
539a4f740cfSGrant Likely  * of_flat_dt_match - Return true if node matches a list of compatible values
540a4f740cfSGrant Likely  */
5417b482c83SUwe Kleine-König int __init of_flat_dt_match(unsigned long node, const char *const *compat)
542a4f740cfSGrant Likely {
543a4f740cfSGrant Likely 	return of_fdt_match(initial_boot_params, node, compat);
544a4f740cfSGrant Likely }
545a4f740cfSGrant Likely 
54657d74bcfSMarek Szyprowski struct fdt_scan_status {
54757d74bcfSMarek Szyprowski 	const char *name;
54857d74bcfSMarek Szyprowski 	int namelen;
54957d74bcfSMarek Szyprowski 	int depth;
55057d74bcfSMarek Szyprowski 	int found;
55157d74bcfSMarek Szyprowski 	int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
55257d74bcfSMarek Szyprowski 	void *data;
55357d74bcfSMarek Szyprowski };
55457d74bcfSMarek Szyprowski 
55557d74bcfSMarek Szyprowski /**
55657d74bcfSMarek Szyprowski  * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
55757d74bcfSMarek Szyprowski  */
55857d74bcfSMarek Szyprowski static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
55957d74bcfSMarek Szyprowski 					int depth, void *data)
56057d74bcfSMarek Szyprowski {
56157d74bcfSMarek Szyprowski 	struct fdt_scan_status *st = data;
56257d74bcfSMarek Szyprowski 
56357d74bcfSMarek Szyprowski 	/*
56457d74bcfSMarek Szyprowski 	 * if scan at the requested fdt node has been completed,
56557d74bcfSMarek Szyprowski 	 * return -ENXIO to abort further scanning
56657d74bcfSMarek Szyprowski 	 */
56757d74bcfSMarek Szyprowski 	if (depth <= st->depth)
56857d74bcfSMarek Szyprowski 		return -ENXIO;
56957d74bcfSMarek Szyprowski 
57057d74bcfSMarek Szyprowski 	/* requested fdt node has been found, so call iterator function */
57157d74bcfSMarek Szyprowski 	if (st->found)
57257d74bcfSMarek Szyprowski 		return st->iterator(node, uname, depth, st->data);
57357d74bcfSMarek Szyprowski 
57457d74bcfSMarek Szyprowski 	/* check if scanning automata is entering next level of fdt nodes */
57557d74bcfSMarek Szyprowski 	if (depth == st->depth + 1 &&
57657d74bcfSMarek Szyprowski 	    strncmp(st->name, uname, st->namelen) == 0 &&
57757d74bcfSMarek Szyprowski 	    uname[st->namelen] == 0) {
57857d74bcfSMarek Szyprowski 		st->depth += 1;
57957d74bcfSMarek Szyprowski 		if (st->name[st->namelen] == 0) {
58057d74bcfSMarek Szyprowski 			st->found = 1;
58157d74bcfSMarek Szyprowski 		} else {
58257d74bcfSMarek Szyprowski 			const char *next = st->name + st->namelen + 1;
58357d74bcfSMarek Szyprowski 			st->name = next;
58457d74bcfSMarek Szyprowski 			st->namelen = strcspn(next, "/");
58557d74bcfSMarek Szyprowski 		}
58657d74bcfSMarek Szyprowski 		return 0;
58757d74bcfSMarek Szyprowski 	}
58857d74bcfSMarek Szyprowski 
58957d74bcfSMarek Szyprowski 	/* scan next fdt node */
59057d74bcfSMarek Szyprowski 	return 0;
59157d74bcfSMarek Szyprowski }
59257d74bcfSMarek Szyprowski 
59357d74bcfSMarek Szyprowski /**
59457d74bcfSMarek Szyprowski  * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
59557d74bcfSMarek Szyprowski  *			     child of the given path.
59657d74bcfSMarek Szyprowski  * @path: path to start searching for children
59757d74bcfSMarek Szyprowski  * @it: callback function
59857d74bcfSMarek Szyprowski  * @data: context data pointer
59957d74bcfSMarek Szyprowski  *
60057d74bcfSMarek Szyprowski  * This function is used to scan the flattened device-tree starting from the
60157d74bcfSMarek Szyprowski  * node given by path. It is used to extract information (like reserved
60257d74bcfSMarek Szyprowski  * memory), which is required on ealy boot before we can unflatten the tree.
60357d74bcfSMarek Szyprowski  */
60457d74bcfSMarek Szyprowski int __init of_scan_flat_dt_by_path(const char *path,
60557d74bcfSMarek Szyprowski 	int (*it)(unsigned long node, const char *name, int depth, void *data),
60657d74bcfSMarek Szyprowski 	void *data)
60757d74bcfSMarek Szyprowski {
60857d74bcfSMarek Szyprowski 	struct fdt_scan_status st = {path, 0, -1, 0, it, data};
60957d74bcfSMarek Szyprowski 	int ret = 0;
61057d74bcfSMarek Szyprowski 
61157d74bcfSMarek Szyprowski 	if (initial_boot_params)
61257d74bcfSMarek Szyprowski                 ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
61357d74bcfSMarek Szyprowski 
61457d74bcfSMarek Szyprowski 	if (!st.found)
61557d74bcfSMarek Szyprowski 		return -ENOENT;
61657d74bcfSMarek Szyprowski 	else if (ret == -ENXIO)	/* scan has been completed */
61757d74bcfSMarek Szyprowski 		return 0;
61857d74bcfSMarek Szyprowski 	else
61957d74bcfSMarek Szyprowski 		return ret;
62057d74bcfSMarek Szyprowski }
62157d74bcfSMarek Szyprowski 
622f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD
623f7b3a835SGrant Likely /**
624f7b3a835SGrant Likely  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
625f7b3a835SGrant Likely  * @node: reference to node containing initrd location ('chosen')
626f7b3a835SGrant Likely  */
62729eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node)
628f7b3a835SGrant Likely {
629374d5c99SSantosh Shilimkar 	u64 start, end;
630374d5c99SSantosh Shilimkar 	unsigned long len;
63133714881SJeremy Kerr 	__be32 *prop;
632f7b3a835SGrant Likely 
633f7b3a835SGrant Likely 	pr_debug("Looking for initrd properties... ");
634f7b3a835SGrant Likely 
635f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
6361406bc2fSJeremy Kerr 	if (!prop)
6371406bc2fSJeremy Kerr 		return;
638374d5c99SSantosh Shilimkar 	start = of_read_number(prop, len/4);
639f7b3a835SGrant Likely 
640f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
6411406bc2fSJeremy Kerr 	if (!prop)
6421406bc2fSJeremy Kerr 		return;
643374d5c99SSantosh Shilimkar 	end = of_read_number(prop, len/4);
644f7b3a835SGrant Likely 
64529eb45a9SRob Herring 	initrd_start = (unsigned long)__va(start);
64629eb45a9SRob Herring 	initrd_end = (unsigned long)__va(end);
64729eb45a9SRob Herring 	initrd_below_start_ok = 1;
64829eb45a9SRob Herring 
649374d5c99SSantosh Shilimkar 	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
650374d5c99SSantosh Shilimkar 		 (unsigned long long)start, (unsigned long long)end);
651f7b3a835SGrant Likely }
652f7b3a835SGrant Likely #else
65329eb45a9SRob Herring static inline void early_init_dt_check_for_initrd(unsigned long node)
654f7b3a835SGrant Likely {
655f7b3a835SGrant Likely }
656f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */
657f7b3a835SGrant Likely 
65841f88009SGrant Likely /**
659f00abd94SGrant Likely  * early_init_dt_scan_root - fetch the top level address and size cells
660f00abd94SGrant Likely  */
661f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname,
662f00abd94SGrant Likely 				   int depth, void *data)
663f00abd94SGrant Likely {
66433714881SJeremy Kerr 	__be32 *prop;
665f00abd94SGrant Likely 
666f00abd94SGrant Likely 	if (depth != 0)
667f00abd94SGrant Likely 		return 0;
668f00abd94SGrant Likely 
66933714881SJeremy Kerr 	dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
67033714881SJeremy Kerr 	dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
67133714881SJeremy Kerr 
672f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
67333714881SJeremy Kerr 	if (prop)
67433714881SJeremy Kerr 		dt_root_size_cells = be32_to_cpup(prop);
675f00abd94SGrant Likely 	pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
676f00abd94SGrant Likely 
677f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
67833714881SJeremy Kerr 	if (prop)
67933714881SJeremy Kerr 		dt_root_addr_cells = be32_to_cpup(prop);
680f00abd94SGrant Likely 	pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
681f00abd94SGrant Likely 
682f00abd94SGrant Likely 	/* break now */
683f00abd94SGrant Likely 	return 1;
684f00abd94SGrant Likely }
685f00abd94SGrant Likely 
6862e89e685SJeremy Kerr u64 __init dt_mem_next_cell(int s, __be32 **cellp)
68783f7a06eSGrant Likely {
6882e89e685SJeremy Kerr 	__be32 *p = *cellp;
68983f7a06eSGrant Likely 
69083f7a06eSGrant Likely 	*cellp = p + s;
69183f7a06eSGrant Likely 	return of_read_number(p, s);
69283f7a06eSGrant Likely }
69383f7a06eSGrant Likely 
69451975db0SGrant Likely /**
69551975db0SGrant Likely  * early_init_dt_scan_memory - Look for an parse memory nodes
69651975db0SGrant Likely  */
69751975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
69851975db0SGrant Likely 				     int depth, void *data)
69951975db0SGrant Likely {
70051975db0SGrant Likely 	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
70151975db0SGrant Likely 	__be32 *reg, *endp;
70251975db0SGrant Likely 	unsigned long l;
70351975db0SGrant Likely 
70451975db0SGrant Likely 	/* We are scanning "memory" nodes only */
70551975db0SGrant Likely 	if (type == NULL) {
70651975db0SGrant Likely 		/*
70751975db0SGrant Likely 		 * The longtrail doesn't have a device_type on the
70851975db0SGrant Likely 		 * /memory node, so look for the node called /memory@0.
70951975db0SGrant Likely 		 */
71051975db0SGrant Likely 		if (depth != 1 || strcmp(uname, "memory@0") != 0)
71151975db0SGrant Likely 			return 0;
71251975db0SGrant Likely 	} else if (strcmp(type, "memory") != 0)
71351975db0SGrant Likely 		return 0;
71451975db0SGrant Likely 
71551975db0SGrant Likely 	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
71651975db0SGrant Likely 	if (reg == NULL)
71751975db0SGrant Likely 		reg = of_get_flat_dt_prop(node, "reg", &l);
71851975db0SGrant Likely 	if (reg == NULL)
71951975db0SGrant Likely 		return 0;
72051975db0SGrant Likely 
72151975db0SGrant Likely 	endp = reg + (l / sizeof(__be32));
72251975db0SGrant Likely 
72351975db0SGrant Likely 	pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
72451975db0SGrant Likely 	    uname, l, reg[0], reg[1], reg[2], reg[3]);
72551975db0SGrant Likely 
72651975db0SGrant Likely 	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
72751975db0SGrant Likely 		u64 base, size;
72851975db0SGrant Likely 
72951975db0SGrant Likely 		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
73051975db0SGrant Likely 		size = dt_mem_next_cell(dt_root_size_cells, &reg);
73151975db0SGrant Likely 
73251975db0SGrant Likely 		if (size == 0)
73351975db0SGrant Likely 			continue;
73451975db0SGrant Likely 		pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
73551975db0SGrant Likely 		    (unsigned long long)size);
73651975db0SGrant Likely 
73751975db0SGrant Likely 		early_init_dt_add_memory_arch(base, size);
73851975db0SGrant Likely 	}
73951975db0SGrant Likely 
74051975db0SGrant Likely 	return 0;
74151975db0SGrant Likely }
74251975db0SGrant Likely 
74386e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
74486e03221SGrant Likely 				     int depth, void *data)
74586e03221SGrant Likely {
74686e03221SGrant Likely 	unsigned long l;
74786e03221SGrant Likely 	char *p;
74886e03221SGrant Likely 
74986e03221SGrant Likely 	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
75086e03221SGrant Likely 
75185f60ae4SGrant Likely 	if (depth != 1 || !data ||
75286e03221SGrant Likely 	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
75386e03221SGrant Likely 		return 0;
75486e03221SGrant Likely 
75586e03221SGrant Likely 	early_init_dt_check_for_initrd(node);
75686e03221SGrant Likely 
75725985edcSLucas De Marchi 	/* Retrieve command line */
75886e03221SGrant Likely 	p = of_get_flat_dt_prop(node, "bootargs", &l);
75986e03221SGrant Likely 	if (p != NULL && l > 0)
76085f60ae4SGrant Likely 		strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
76186e03221SGrant Likely 
76278b782cbSBenjamin Herrenschmidt 	/*
76378b782cbSBenjamin Herrenschmidt 	 * CONFIG_CMDLINE is meant to be a default in case nothing else
76478b782cbSBenjamin Herrenschmidt 	 * managed to set the command line, unless CONFIG_CMDLINE_FORCE
76578b782cbSBenjamin Herrenschmidt 	 * is set in which case we override whatever was found earlier.
76678b782cbSBenjamin Herrenschmidt 	 */
76786e03221SGrant Likely #ifdef CONFIG_CMDLINE
76886e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE
76978b782cbSBenjamin Herrenschmidt 	if (!((char *)data)[0])
77086e03221SGrant Likely #endif
77185f60ae4SGrant Likely 		strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
77286e03221SGrant Likely #endif /* CONFIG_CMDLINE */
77386e03221SGrant Likely 
77485f60ae4SGrant Likely 	pr_debug("Command line is: %s\n", (char*)data);
77586e03221SGrant Likely 
77686e03221SGrant Likely 	/* break now */
77786e03221SGrant Likely 	return 1;
77886e03221SGrant Likely }
77986e03221SGrant Likely 
780a1727da5SGrant Likely #ifdef CONFIG_HAVE_MEMBLOCK
781068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
782068f6310SRob Herring {
783068f6310SRob Herring 	const u64 phys_offset = __pa(PAGE_OFFSET);
784068f6310SRob Herring 	base &= PAGE_MASK;
785068f6310SRob Herring 	size &= PAGE_MASK;
786068f6310SRob Herring 	if (base + size < phys_offset) {
787068f6310SRob Herring 		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
788068f6310SRob Herring 			   base, base + size);
789068f6310SRob Herring 		return;
790068f6310SRob Herring 	}
791068f6310SRob Herring 	if (base < phys_offset) {
792068f6310SRob Herring 		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
793068f6310SRob Herring 			   base, phys_offset);
794068f6310SRob Herring 		size -= phys_offset - base;
795068f6310SRob Herring 		base = phys_offset;
796068f6310SRob Herring 	}
797068f6310SRob Herring 	memblock_add(base, size);
798068f6310SRob Herring }
799068f6310SRob Herring 
800a1727da5SGrant Likely /*
801a1727da5SGrant Likely  * called from unflatten_device_tree() to bootstrap devicetree itself
802a1727da5SGrant Likely  * Architectures can override this definition if memblock isn't used
803a1727da5SGrant Likely  */
804a1727da5SGrant Likely void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
805a1727da5SGrant Likely {
806a1727da5SGrant Likely 	return __va(memblock_alloc(size, align));
807a1727da5SGrant Likely }
808a1727da5SGrant Likely #endif
809a1727da5SGrant Likely 
8100288ffcbSRob Herring bool __init early_init_dt_scan(void *params)
8110288ffcbSRob Herring {
8120288ffcbSRob Herring 	if (!params)
8130288ffcbSRob Herring 		return false;
8140288ffcbSRob Herring 
8150288ffcbSRob Herring 	/* Setup flat device-tree pointer */
8160288ffcbSRob Herring 	initial_boot_params = params;
8170288ffcbSRob Herring 
8180288ffcbSRob Herring 	/* check device tree validity */
8190288ffcbSRob Herring 	if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
8200288ffcbSRob Herring 		initial_boot_params = NULL;
8210288ffcbSRob Herring 		return false;
8220288ffcbSRob Herring 	}
8230288ffcbSRob Herring 
8240288ffcbSRob Herring 	/* Retrieve various information from the /chosen node */
8250288ffcbSRob Herring 	of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
8260288ffcbSRob Herring 
8270288ffcbSRob Herring 	/* Initialize {size,address}-cells info */
8280288ffcbSRob Herring 	of_scan_flat_dt(early_init_dt_scan_root, NULL);
8290288ffcbSRob Herring 
8300288ffcbSRob Herring 	/* Setup memory, calling early_init_dt_add_memory_arch */
8310288ffcbSRob Herring 	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
8320288ffcbSRob Herring 
8330288ffcbSRob Herring 	return true;
8340288ffcbSRob Herring }
8350288ffcbSRob Herring 
836f00abd94SGrant Likely /**
83741f88009SGrant Likely  * unflatten_device_tree - create tree of device_nodes from flat blob
83841f88009SGrant Likely  *
83941f88009SGrant Likely  * unflattens the device-tree passed by the firmware, creating the
84041f88009SGrant Likely  * tree of struct device_node. It also fills the "name" and "type"
84141f88009SGrant Likely  * pointers of the nodes so the normal device-tree walking functions
84241f88009SGrant Likely  * can be used.
84341f88009SGrant Likely  */
84441f88009SGrant Likely void __init unflatten_device_tree(void)
84541f88009SGrant Likely {
846465aac6dSRandy Dunlap 	__unflatten_device_tree(initial_boot_params, &of_allnodes,
847672c5446SGrant Likely 				early_init_dt_alloc_memory_arch);
84841f88009SGrant Likely 
8494c7d6361SRobert P. J. Day 	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
850611cad72SShawn Guo 	of_alias_scan(early_init_dt_alloc_memory_arch);
85141f88009SGrant Likely }
852e6ce1324SStephen Neuendorffer 
853a8bf7527SRob Herring /**
854a8bf7527SRob Herring  * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob
855a8bf7527SRob Herring  *
856a8bf7527SRob Herring  * Copies and unflattens the device-tree passed by the firmware, creating the
857a8bf7527SRob Herring  * tree of struct device_node. It also fills the "name" and "type"
858a8bf7527SRob Herring  * pointers of the nodes so the normal device-tree walking functions
859a8bf7527SRob Herring  * can be used. This should only be used when the FDT memory has not been
860a8bf7527SRob Herring  * reserved such is the case when the FDT is built-in to the kernel init
861a8bf7527SRob Herring  * section. If the FDT memory is reserved already then unflatten_device_tree
862a8bf7527SRob Herring  * should be used instead.
863a8bf7527SRob Herring  */
864a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void)
865a8bf7527SRob Herring {
866a8bf7527SRob Herring 	int size = __be32_to_cpu(initial_boot_params->totalsize);
867a8bf7527SRob Herring 	void *dt = early_init_dt_alloc_memory_arch(size,
868a8bf7527SRob Herring 		__alignof__(struct boot_param_header));
869a8bf7527SRob Herring 
870a8bf7527SRob Herring 	if (dt) {
871a8bf7527SRob Herring 		memcpy(dt, initial_boot_params, size);
872a8bf7527SRob Herring 		initial_boot_params = dt;
873a8bf7527SRob Herring 	}
874a8bf7527SRob Herring 	unflatten_device_tree();
875a8bf7527SRob Herring }
876a8bf7527SRob Herring 
877e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */
878109b6236SAnton Blanchard 
879109b6236SAnton Blanchard /* Feed entire flattened device tree into the random pool */
880109b6236SAnton Blanchard static int __init add_fdt_randomness(void)
881109b6236SAnton Blanchard {
882109b6236SAnton Blanchard 	if (initial_boot_params)
883109b6236SAnton Blanchard 		add_device_randomness(initial_boot_params,
884109b6236SAnton Blanchard 				be32_to_cpu(initial_boot_params->totalsize));
885109b6236SAnton Blanchard 
886109b6236SAnton Blanchard 	return 0;
887109b6236SAnton Blanchard }
888109b6236SAnton Blanchard core_initcall(add_fdt_randomness);
889