xref: /openbmc/linux/drivers/of/fdt.c (revision a7006c97)
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>
14fe140423SStephen Neuendorffer #include <linux/module.h>
15e169cfbeSGrant Likely #include <linux/of.h>
16e169cfbeSGrant Likely #include <linux/of_fdt.h>
174ef7b373SJeremy Kerr #include <linux/string.h>
184ef7b373SJeremy Kerr #include <linux/errno.h>
19fe140423SStephen Neuendorffer #include <linux/slab.h>
2051975db0SGrant Likely 
2186e03221SGrant Likely #ifdef CONFIG_PPC
2286e03221SGrant Likely #include <asm/machdep.h>
2386e03221SGrant Likely #endif /* CONFIG_PPC */
2486e03221SGrant Likely 
254ef7b373SJeremy Kerr #include <asm/page.h>
264ef7b373SJeremy Kerr 
279706a36eSStephen Neuendorffer char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
289706a36eSStephen Neuendorffer {
299706a36eSStephen Neuendorffer 	return ((char *)blob) +
309706a36eSStephen Neuendorffer 		be32_to_cpu(blob->off_dt_strings) + offset;
319706a36eSStephen Neuendorffer }
329706a36eSStephen Neuendorffer 
339706a36eSStephen Neuendorffer /**
349706a36eSStephen Neuendorffer  * of_fdt_get_property - Given a node in the given flat blob, return
359706a36eSStephen Neuendorffer  * the property ptr
369706a36eSStephen Neuendorffer  */
379706a36eSStephen Neuendorffer void *of_fdt_get_property(struct boot_param_header *blob,
389706a36eSStephen Neuendorffer 		       unsigned long node, const char *name,
399706a36eSStephen Neuendorffer 		       unsigned long *size)
409706a36eSStephen Neuendorffer {
419706a36eSStephen Neuendorffer 	unsigned long p = node;
429706a36eSStephen Neuendorffer 
439706a36eSStephen Neuendorffer 	do {
449706a36eSStephen Neuendorffer 		u32 tag = be32_to_cpup((__be32 *)p);
459706a36eSStephen Neuendorffer 		u32 sz, noff;
469706a36eSStephen Neuendorffer 		const char *nstr;
479706a36eSStephen Neuendorffer 
489706a36eSStephen Neuendorffer 		p += 4;
499706a36eSStephen Neuendorffer 		if (tag == OF_DT_NOP)
509706a36eSStephen Neuendorffer 			continue;
519706a36eSStephen Neuendorffer 		if (tag != OF_DT_PROP)
529706a36eSStephen Neuendorffer 			return NULL;
539706a36eSStephen Neuendorffer 
549706a36eSStephen Neuendorffer 		sz = be32_to_cpup((__be32 *)p);
559706a36eSStephen Neuendorffer 		noff = be32_to_cpup((__be32 *)(p + 4));
569706a36eSStephen Neuendorffer 		p += 8;
579706a36eSStephen Neuendorffer 		if (be32_to_cpu(blob->version) < 0x10)
589706a36eSStephen Neuendorffer 			p = ALIGN(p, sz >= 8 ? 8 : 4);
599706a36eSStephen Neuendorffer 
609706a36eSStephen Neuendorffer 		nstr = of_fdt_get_string(blob, noff);
619706a36eSStephen Neuendorffer 		if (nstr == NULL) {
629706a36eSStephen Neuendorffer 			pr_warning("Can't find property index name !\n");
639706a36eSStephen Neuendorffer 			return NULL;
649706a36eSStephen Neuendorffer 		}
659706a36eSStephen Neuendorffer 		if (strcmp(name, nstr) == 0) {
669706a36eSStephen Neuendorffer 			if (size)
679706a36eSStephen Neuendorffer 				*size = sz;
689706a36eSStephen Neuendorffer 			return (void *)p;
699706a36eSStephen Neuendorffer 		}
709706a36eSStephen Neuendorffer 		p += sz;
719706a36eSStephen Neuendorffer 		p = ALIGN(p, 4);
729706a36eSStephen Neuendorffer 	} while (1);
739706a36eSStephen Neuendorffer }
749706a36eSStephen Neuendorffer 
759706a36eSStephen Neuendorffer /**
769706a36eSStephen Neuendorffer  * of_fdt_is_compatible - Return true if given node from the given blob has
779706a36eSStephen Neuendorffer  * compat in its compatible list
789706a36eSStephen Neuendorffer  * @blob: A device tree blob
799706a36eSStephen Neuendorffer  * @node: node to test
809706a36eSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
81a4f740cfSGrant Likely  *
82a4f740cfSGrant Likely  * On match, returns a non-zero value with smaller values returned for more
83a4f740cfSGrant Likely  * specific compatible values.
849706a36eSStephen Neuendorffer  */
859706a36eSStephen Neuendorffer int of_fdt_is_compatible(struct boot_param_header *blob,
869706a36eSStephen Neuendorffer 		      unsigned long node, const char *compat)
879706a36eSStephen Neuendorffer {
889706a36eSStephen Neuendorffer 	const char *cp;
89a4f740cfSGrant Likely 	unsigned long cplen, l, score = 0;
909706a36eSStephen Neuendorffer 
919706a36eSStephen Neuendorffer 	cp = of_fdt_get_property(blob, node, "compatible", &cplen);
929706a36eSStephen Neuendorffer 	if (cp == NULL)
939706a36eSStephen Neuendorffer 		return 0;
949706a36eSStephen Neuendorffer 	while (cplen > 0) {
95a4f740cfSGrant Likely 		score++;
969706a36eSStephen Neuendorffer 		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
97a4f740cfSGrant Likely 			return score;
989706a36eSStephen Neuendorffer 		l = strlen(cp) + 1;
999706a36eSStephen Neuendorffer 		cp += l;
1009706a36eSStephen Neuendorffer 		cplen -= l;
1019706a36eSStephen Neuendorffer 	}
1029706a36eSStephen Neuendorffer 
1039706a36eSStephen Neuendorffer 	return 0;
1049706a36eSStephen Neuendorffer }
1059706a36eSStephen Neuendorffer 
106a4f740cfSGrant Likely /**
107a4f740cfSGrant Likely  * of_fdt_match - Return true if node matches a list of compatible values
108a4f740cfSGrant Likely  */
109a4f740cfSGrant Likely int of_fdt_match(struct boot_param_header *blob, unsigned long node,
110a4f740cfSGrant Likely                  const char **compat)
111a4f740cfSGrant Likely {
112a4f740cfSGrant Likely 	unsigned int tmp, score = 0;
113a4f740cfSGrant Likely 
114a4f740cfSGrant Likely 	if (!compat)
115a4f740cfSGrant Likely 		return 0;
116a4f740cfSGrant Likely 
117a4f740cfSGrant Likely 	while (*compat) {
118a4f740cfSGrant Likely 		tmp = of_fdt_is_compatible(blob, node, *compat);
119a4f740cfSGrant Likely 		if (tmp && (score == 0 || (tmp < score)))
120a4f740cfSGrant Likely 			score = tmp;
121a4f740cfSGrant Likely 		compat++;
122a4f740cfSGrant Likely 	}
123a4f740cfSGrant Likely 
124a4f740cfSGrant Likely 	return score;
125a4f740cfSGrant Likely }
126a4f740cfSGrant Likely 
127a40d6c4cSStephen Neuendorffer static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
128bbd33931SGrant Likely 				       unsigned long align)
129bbd33931SGrant Likely {
130bbd33931SGrant Likely 	void *res;
131bbd33931SGrant Likely 
132f1d4c3a7SGrant Likely 	*mem = ALIGN(*mem, align);
133bbd33931SGrant Likely 	res = (void *)*mem;
134bbd33931SGrant Likely 	*mem += size;
135bbd33931SGrant Likely 
136bbd33931SGrant Likely 	return res;
137bbd33931SGrant Likely }
138bbd33931SGrant Likely 
139bbd33931SGrant Likely /**
140bbd33931SGrant Likely  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
141a40d6c4cSStephen Neuendorffer  * @blob: The parent device tree blob
142a7006c97SAndres Salomon  * @mem: Memory chunk to use for allocating device nodes and properties
143bbd33931SGrant Likely  * @p: pointer to node in flat tree
144bbd33931SGrant Likely  * @dad: Parent struct device_node
145bbd33931SGrant Likely  * @allnextpp: pointer to ->allnext from last allocated device_node
146bbd33931SGrant Likely  * @fpsize: Size of the node path up at the current depth.
147bbd33931SGrant Likely  */
148a7006c97SAndres Salomon static unsigned long unflatten_dt_node(struct boot_param_header *blob,
149a40d6c4cSStephen Neuendorffer 				unsigned long mem,
150bbd33931SGrant Likely 				unsigned long *p,
151bbd33931SGrant Likely 				struct device_node *dad,
152bbd33931SGrant Likely 				struct device_node ***allnextpp,
153bbd33931SGrant Likely 				unsigned long fpsize)
154bbd33931SGrant Likely {
155bbd33931SGrant Likely 	struct device_node *np;
156bbd33931SGrant Likely 	struct property *pp, **prev_pp = NULL;
157bbd33931SGrant Likely 	char *pathp;
158bbd33931SGrant Likely 	u32 tag;
159bbd33931SGrant Likely 	unsigned int l, allocl;
160bbd33931SGrant Likely 	int has_name = 0;
161bbd33931SGrant Likely 	int new_format = 0;
162bbd33931SGrant Likely 
16333714881SJeremy Kerr 	tag = be32_to_cpup((__be32 *)(*p));
164bbd33931SGrant Likely 	if (tag != OF_DT_BEGIN_NODE) {
165bbd33931SGrant Likely 		pr_err("Weird tag at start of node: %x\n", tag);
166bbd33931SGrant Likely 		return mem;
167bbd33931SGrant Likely 	}
168bbd33931SGrant Likely 	*p += 4;
169bbd33931SGrant Likely 	pathp = (char *)*p;
170bbd33931SGrant Likely 	l = allocl = strlen(pathp) + 1;
171f1d4c3a7SGrant Likely 	*p = ALIGN(*p + l, 4);
172bbd33931SGrant Likely 
173bbd33931SGrant Likely 	/* version 0x10 has a more compact unit name here instead of the full
174bbd33931SGrant Likely 	 * path. we accumulate the full path size using "fpsize", we'll rebuild
175bbd33931SGrant Likely 	 * it later. We detect this because the first character of the name is
176bbd33931SGrant Likely 	 * not '/'.
177bbd33931SGrant Likely 	 */
178bbd33931SGrant Likely 	if ((*pathp) != '/') {
179bbd33931SGrant Likely 		new_format = 1;
180bbd33931SGrant Likely 		if (fpsize == 0) {
181bbd33931SGrant Likely 			/* root node: special case. fpsize accounts for path
182bbd33931SGrant Likely 			 * plus terminating zero. root node only has '/', so
183bbd33931SGrant Likely 			 * fpsize should be 2, but we want to avoid the first
184bbd33931SGrant Likely 			 * level nodes to have two '/' so we use fpsize 1 here
185bbd33931SGrant Likely 			 */
186bbd33931SGrant Likely 			fpsize = 1;
187bbd33931SGrant Likely 			allocl = 2;
188bbd33931SGrant Likely 		} else {
189bbd33931SGrant Likely 			/* account for '/' and path size minus terminal 0
190bbd33931SGrant Likely 			 * already in 'l'
191bbd33931SGrant Likely 			 */
192bbd33931SGrant Likely 			fpsize += l;
193bbd33931SGrant Likely 			allocl = fpsize;
194bbd33931SGrant Likely 		}
195bbd33931SGrant Likely 	}
196bbd33931SGrant Likely 
197bbd33931SGrant Likely 	np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
198bbd33931SGrant Likely 				__alignof__(struct device_node));
199bbd33931SGrant Likely 	if (allnextpp) {
200bbd33931SGrant Likely 		memset(np, 0, sizeof(*np));
201bbd33931SGrant Likely 		np->full_name = ((char *)np) + sizeof(struct device_node);
202bbd33931SGrant Likely 		if (new_format) {
203bbd33931SGrant Likely 			char *fn = np->full_name;
204bbd33931SGrant Likely 			/* rebuild full path for new format */
205bbd33931SGrant Likely 			if (dad && dad->parent) {
206bbd33931SGrant Likely 				strcpy(fn, dad->full_name);
207bbd33931SGrant Likely #ifdef DEBUG
208bbd33931SGrant Likely 				if ((strlen(fn) + l + 1) != allocl) {
209bbd33931SGrant Likely 					pr_debug("%s: p: %d, l: %d, a: %d\n",
210bbd33931SGrant Likely 						pathp, (int)strlen(fn),
211bbd33931SGrant Likely 						l, allocl);
212bbd33931SGrant Likely 				}
213bbd33931SGrant Likely #endif
214bbd33931SGrant Likely 				fn += strlen(fn);
215bbd33931SGrant Likely 			}
216bbd33931SGrant Likely 			*(fn++) = '/';
217bbd33931SGrant Likely 			memcpy(fn, pathp, l);
218bbd33931SGrant Likely 		} else
219bbd33931SGrant Likely 			memcpy(np->full_name, pathp, l);
220bbd33931SGrant Likely 		prev_pp = &np->properties;
221bbd33931SGrant Likely 		**allnextpp = np;
222bbd33931SGrant Likely 		*allnextpp = &np->allnext;
223bbd33931SGrant Likely 		if (dad != NULL) {
224bbd33931SGrant Likely 			np->parent = dad;
225bbd33931SGrant Likely 			/* we temporarily use the next field as `last_child'*/
226bbd33931SGrant Likely 			if (dad->next == NULL)
227bbd33931SGrant Likely 				dad->child = np;
228bbd33931SGrant Likely 			else
229bbd33931SGrant Likely 				dad->next->sibling = np;
230bbd33931SGrant Likely 			dad->next = np;
231bbd33931SGrant Likely 		}
232bbd33931SGrant Likely 		kref_init(&np->kref);
233bbd33931SGrant Likely 	}
234a7006c97SAndres Salomon 	/* process properties */
235bbd33931SGrant Likely 	while (1) {
236bbd33931SGrant Likely 		u32 sz, noff;
237bbd33931SGrant Likely 		char *pname;
238bbd33931SGrant Likely 
23933714881SJeremy Kerr 		tag = be32_to_cpup((__be32 *)(*p));
240bbd33931SGrant Likely 		if (tag == OF_DT_NOP) {
241bbd33931SGrant Likely 			*p += 4;
242bbd33931SGrant Likely 			continue;
243bbd33931SGrant Likely 		}
244bbd33931SGrant Likely 		if (tag != OF_DT_PROP)
245bbd33931SGrant Likely 			break;
246bbd33931SGrant Likely 		*p += 4;
24733714881SJeremy Kerr 		sz = be32_to_cpup((__be32 *)(*p));
24833714881SJeremy Kerr 		noff = be32_to_cpup((__be32 *)((*p) + 4));
249bbd33931SGrant Likely 		*p += 8;
250a40d6c4cSStephen Neuendorffer 		if (be32_to_cpu(blob->version) < 0x10)
251f1d4c3a7SGrant Likely 			*p = ALIGN(*p, sz >= 8 ? 8 : 4);
252bbd33931SGrant Likely 
253a40d6c4cSStephen Neuendorffer 		pname = of_fdt_get_string(blob, noff);
254bbd33931SGrant Likely 		if (pname == NULL) {
255bbd33931SGrant Likely 			pr_info("Can't find property name in list !\n");
256bbd33931SGrant Likely 			break;
257bbd33931SGrant Likely 		}
258bbd33931SGrant Likely 		if (strcmp(pname, "name") == 0)
259bbd33931SGrant Likely 			has_name = 1;
260bbd33931SGrant Likely 		l = strlen(pname) + 1;
261bbd33931SGrant Likely 		pp = unflatten_dt_alloc(&mem, sizeof(struct property),
262bbd33931SGrant Likely 					__alignof__(struct property));
263bbd33931SGrant Likely 		if (allnextpp) {
26404b954a6SDavid Gibson 			/* We accept flattened tree phandles either in
26504b954a6SDavid Gibson 			 * ePAPR-style "phandle" properties, or the
26604b954a6SDavid Gibson 			 * legacy "linux,phandle" properties.  If both
26704b954a6SDavid Gibson 			 * appear and have different values, things
26804b954a6SDavid Gibson 			 * will get weird.  Don't do that. */
26904b954a6SDavid Gibson 			if ((strcmp(pname, "phandle") == 0) ||
27004b954a6SDavid Gibson 			    (strcmp(pname, "linux,phandle") == 0)) {
2716016a363SGrant Likely 				if (np->phandle == 0)
2729a6b2e58SGrant Likely 					np->phandle = be32_to_cpup((__be32*)*p);
273bbd33931SGrant Likely 			}
27404b954a6SDavid Gibson 			/* And we process the "ibm,phandle" property
27504b954a6SDavid Gibson 			 * used in pSeries dynamic device tree
27604b954a6SDavid Gibson 			 * stuff */
277bbd33931SGrant Likely 			if (strcmp(pname, "ibm,phandle") == 0)
2789a6b2e58SGrant Likely 				np->phandle = be32_to_cpup((__be32 *)*p);
279bbd33931SGrant Likely 			pp->name = pname;
280bbd33931SGrant Likely 			pp->length = sz;
281bbd33931SGrant Likely 			pp->value = (void *)*p;
282bbd33931SGrant Likely 			*prev_pp = pp;
283bbd33931SGrant Likely 			prev_pp = &pp->next;
284bbd33931SGrant Likely 		}
285f1d4c3a7SGrant Likely 		*p = ALIGN((*p) + sz, 4);
286bbd33931SGrant Likely 	}
287bbd33931SGrant Likely 	/* with version 0x10 we may not have the name property, recreate
288bbd33931SGrant Likely 	 * it here from the unit name if absent
289bbd33931SGrant Likely 	 */
290bbd33931SGrant Likely 	if (!has_name) {
291bbd33931SGrant Likely 		char *p1 = pathp, *ps = pathp, *pa = NULL;
292bbd33931SGrant Likely 		int sz;
293bbd33931SGrant Likely 
294bbd33931SGrant Likely 		while (*p1) {
295bbd33931SGrant Likely 			if ((*p1) == '@')
296bbd33931SGrant Likely 				pa = p1;
297bbd33931SGrant Likely 			if ((*p1) == '/')
298bbd33931SGrant Likely 				ps = p1 + 1;
299bbd33931SGrant Likely 			p1++;
300bbd33931SGrant Likely 		}
301bbd33931SGrant Likely 		if (pa < ps)
302bbd33931SGrant Likely 			pa = p1;
303bbd33931SGrant Likely 		sz = (pa - ps) + 1;
304bbd33931SGrant Likely 		pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
305bbd33931SGrant Likely 					__alignof__(struct property));
306bbd33931SGrant Likely 		if (allnextpp) {
307bbd33931SGrant Likely 			pp->name = "name";
308bbd33931SGrant Likely 			pp->length = sz;
309bbd33931SGrant Likely 			pp->value = pp + 1;
310bbd33931SGrant Likely 			*prev_pp = pp;
311bbd33931SGrant Likely 			prev_pp = &pp->next;
312bbd33931SGrant Likely 			memcpy(pp->value, ps, sz - 1);
313bbd33931SGrant Likely 			((char *)pp->value)[sz - 1] = 0;
314bbd33931SGrant Likely 			pr_debug("fixed up name for %s -> %s\n", pathp,
315bbd33931SGrant Likely 				(char *)pp->value);
316bbd33931SGrant Likely 		}
317bbd33931SGrant Likely 	}
318bbd33931SGrant Likely 	if (allnextpp) {
319bbd33931SGrant Likely 		*prev_pp = NULL;
320bbd33931SGrant Likely 		np->name = of_get_property(np, "name", NULL);
321bbd33931SGrant Likely 		np->type = of_get_property(np, "device_type", NULL);
322bbd33931SGrant Likely 
323bbd33931SGrant Likely 		if (!np->name)
324bbd33931SGrant Likely 			np->name = "<NULL>";
325bbd33931SGrant Likely 		if (!np->type)
326bbd33931SGrant Likely 			np->type = "<NULL>";
327bbd33931SGrant Likely 	}
3287f809e1fSJason Gunthorpe 	while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
3297f809e1fSJason Gunthorpe 		if (tag == OF_DT_NOP)
3307f809e1fSJason Gunthorpe 			*p += 4;
3317f809e1fSJason Gunthorpe 		else
332a40d6c4cSStephen Neuendorffer 			mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
333a40d6c4cSStephen Neuendorffer 						fpsize);
33433714881SJeremy Kerr 		tag = be32_to_cpup((__be32 *)(*p));
335bbd33931SGrant Likely 	}
336bbd33931SGrant Likely 	if (tag != OF_DT_END_NODE) {
337bbd33931SGrant Likely 		pr_err("Weird tag at end of node: %x\n", tag);
338bbd33931SGrant Likely 		return mem;
339bbd33931SGrant Likely 	}
340bbd33931SGrant Likely 	*p += 4;
341bbd33931SGrant Likely 	return mem;
342bbd33931SGrant Likely }
34341f88009SGrant Likely 
344fe140423SStephen Neuendorffer /**
345fe140423SStephen Neuendorffer  * __unflatten_device_tree - create tree of device_nodes from flat blob
346fe140423SStephen Neuendorffer  *
347fe140423SStephen Neuendorffer  * unflattens a device-tree, creating the
348fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
349fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
350fe140423SStephen Neuendorffer  * can be used.
351fe140423SStephen Neuendorffer  * @blob: The blob to expand
352fe140423SStephen Neuendorffer  * @mynodes: The device_node tree created by the call
353fe140423SStephen Neuendorffer  * @dt_alloc: An allocator that provides a virtual address to memory
354fe140423SStephen Neuendorffer  * for the resulting tree
355fe140423SStephen Neuendorffer  */
356a7006c97SAndres Salomon static void __unflatten_device_tree(struct boot_param_header *blob,
357fe140423SStephen Neuendorffer 			     struct device_node **mynodes,
358fe140423SStephen Neuendorffer 			     void * (*dt_alloc)(u64 size, u64 align))
359fe140423SStephen Neuendorffer {
360fe140423SStephen Neuendorffer 	unsigned long start, mem, size;
361fe140423SStephen Neuendorffer 	struct device_node **allnextp = mynodes;
362fe140423SStephen Neuendorffer 
363fe140423SStephen Neuendorffer 	pr_debug(" -> unflatten_device_tree()\n");
364fe140423SStephen Neuendorffer 
365fe140423SStephen Neuendorffer 	if (!blob) {
366fe140423SStephen Neuendorffer 		pr_debug("No device tree pointer\n");
367fe140423SStephen Neuendorffer 		return;
368fe140423SStephen Neuendorffer 	}
369fe140423SStephen Neuendorffer 
370fe140423SStephen Neuendorffer 	pr_debug("Unflattening device tree:\n");
371fe140423SStephen Neuendorffer 	pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
372fe140423SStephen Neuendorffer 	pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
373fe140423SStephen Neuendorffer 	pr_debug("version: %08x\n", be32_to_cpu(blob->version));
374fe140423SStephen Neuendorffer 
375fe140423SStephen Neuendorffer 	if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
376fe140423SStephen Neuendorffer 		pr_err("Invalid device tree blob header\n");
377fe140423SStephen Neuendorffer 		return;
378fe140423SStephen Neuendorffer 	}
379fe140423SStephen Neuendorffer 
380fe140423SStephen Neuendorffer 	/* First pass, scan for size */
381fe140423SStephen Neuendorffer 	start = ((unsigned long)blob) +
382fe140423SStephen Neuendorffer 		be32_to_cpu(blob->off_dt_struct);
383fe140423SStephen Neuendorffer 	size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
384fe140423SStephen Neuendorffer 	size = (size | 3) + 1;
385fe140423SStephen Neuendorffer 
386fe140423SStephen Neuendorffer 	pr_debug("  size is %lx, allocating...\n", size);
387fe140423SStephen Neuendorffer 
388fe140423SStephen Neuendorffer 	/* Allocate memory for the expanded device tree */
389fe140423SStephen Neuendorffer 	mem = (unsigned long)
390fe140423SStephen Neuendorffer 		dt_alloc(size + 4, __alignof__(struct device_node));
391fe140423SStephen Neuendorffer 
392fe140423SStephen Neuendorffer 	((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
393fe140423SStephen Neuendorffer 
394fe140423SStephen Neuendorffer 	pr_debug("  unflattening %lx...\n", mem);
395fe140423SStephen Neuendorffer 
396fe140423SStephen Neuendorffer 	/* Second pass, do actual unflattening */
397fe140423SStephen Neuendorffer 	start = ((unsigned long)blob) +
398fe140423SStephen Neuendorffer 		be32_to_cpu(blob->off_dt_struct);
399fe140423SStephen Neuendorffer 	unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
400fe140423SStephen Neuendorffer 	if (be32_to_cpup((__be32 *)start) != OF_DT_END)
401fe140423SStephen Neuendorffer 		pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
402fe140423SStephen Neuendorffer 	if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
403fe140423SStephen Neuendorffer 		pr_warning("End of tree marker overwritten: %08x\n",
404fe140423SStephen Neuendorffer 			   be32_to_cpu(((__be32 *)mem)[size / 4]));
405fe140423SStephen Neuendorffer 	*allnextp = NULL;
406fe140423SStephen Neuendorffer 
407fe140423SStephen Neuendorffer 	pr_debug(" <- unflatten_device_tree()\n");
408fe140423SStephen Neuendorffer }
409fe140423SStephen Neuendorffer 
410fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align)
411fe140423SStephen Neuendorffer {
412fe140423SStephen Neuendorffer 	return kzalloc(size, GFP_KERNEL);
413fe140423SStephen Neuendorffer }
414fe140423SStephen Neuendorffer 
415fe140423SStephen Neuendorffer /**
416fe140423SStephen Neuendorffer  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
417fe140423SStephen Neuendorffer  *
418fe140423SStephen Neuendorffer  * unflattens the device-tree passed by the firmware, creating the
419fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
420fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
421fe140423SStephen Neuendorffer  * can be used.
422fe140423SStephen Neuendorffer  */
423fe140423SStephen Neuendorffer void of_fdt_unflatten_tree(unsigned long *blob,
424fe140423SStephen Neuendorffer 			struct device_node **mynodes)
425fe140423SStephen Neuendorffer {
426fe140423SStephen Neuendorffer 	struct boot_param_header *device_tree =
427fe140423SStephen Neuendorffer 		(struct boot_param_header *)blob;
428fe140423SStephen Neuendorffer 	__unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
429fe140423SStephen Neuendorffer }
430fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
431fe140423SStephen Neuendorffer 
43257d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */
43357d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells;
43457d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells;
43557d00ecfSStephen Neuendorffer 
43657d00ecfSStephen Neuendorffer struct boot_param_header *initial_boot_params;
43757d00ecfSStephen Neuendorffer 
43857d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE
43957d00ecfSStephen Neuendorffer 
44057d00ecfSStephen Neuendorffer /**
44157d00ecfSStephen Neuendorffer  * of_scan_flat_dt - scan flattened tree blob and call callback on each.
44257d00ecfSStephen Neuendorffer  * @it: callback function
44357d00ecfSStephen Neuendorffer  * @data: context data pointer
44457d00ecfSStephen Neuendorffer  *
44557d00ecfSStephen Neuendorffer  * This function is used to scan the flattened device-tree, it is
44657d00ecfSStephen Neuendorffer  * used to extract the memory information at boot before we can
44757d00ecfSStephen Neuendorffer  * unflatten the tree
44857d00ecfSStephen Neuendorffer  */
44957d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node,
45057d00ecfSStephen Neuendorffer 				     const char *uname, int depth,
45157d00ecfSStephen Neuendorffer 				     void *data),
45257d00ecfSStephen Neuendorffer 			   void *data)
45357d00ecfSStephen Neuendorffer {
45457d00ecfSStephen Neuendorffer 	unsigned long p = ((unsigned long)initial_boot_params) +
45557d00ecfSStephen Neuendorffer 		be32_to_cpu(initial_boot_params->off_dt_struct);
45657d00ecfSStephen Neuendorffer 	int rc = 0;
45757d00ecfSStephen Neuendorffer 	int depth = -1;
45857d00ecfSStephen Neuendorffer 
45957d00ecfSStephen Neuendorffer 	do {
46057d00ecfSStephen Neuendorffer 		u32 tag = be32_to_cpup((__be32 *)p);
46157d00ecfSStephen Neuendorffer 		char *pathp;
46257d00ecfSStephen Neuendorffer 
46357d00ecfSStephen Neuendorffer 		p += 4;
46457d00ecfSStephen Neuendorffer 		if (tag == OF_DT_END_NODE) {
46557d00ecfSStephen Neuendorffer 			depth--;
46657d00ecfSStephen Neuendorffer 			continue;
46757d00ecfSStephen Neuendorffer 		}
46857d00ecfSStephen Neuendorffer 		if (tag == OF_DT_NOP)
46957d00ecfSStephen Neuendorffer 			continue;
47057d00ecfSStephen Neuendorffer 		if (tag == OF_DT_END)
47157d00ecfSStephen Neuendorffer 			break;
47257d00ecfSStephen Neuendorffer 		if (tag == OF_DT_PROP) {
47357d00ecfSStephen Neuendorffer 			u32 sz = be32_to_cpup((__be32 *)p);
47457d00ecfSStephen Neuendorffer 			p += 8;
47557d00ecfSStephen Neuendorffer 			if (be32_to_cpu(initial_boot_params->version) < 0x10)
47657d00ecfSStephen Neuendorffer 				p = ALIGN(p, sz >= 8 ? 8 : 4);
47757d00ecfSStephen Neuendorffer 			p += sz;
47857d00ecfSStephen Neuendorffer 			p = ALIGN(p, 4);
47957d00ecfSStephen Neuendorffer 			continue;
48057d00ecfSStephen Neuendorffer 		}
48157d00ecfSStephen Neuendorffer 		if (tag != OF_DT_BEGIN_NODE) {
48257d00ecfSStephen Neuendorffer 			pr_err("Invalid tag %x in flat device tree!\n", tag);
48357d00ecfSStephen Neuendorffer 			return -EINVAL;
48457d00ecfSStephen Neuendorffer 		}
48557d00ecfSStephen Neuendorffer 		depth++;
48657d00ecfSStephen Neuendorffer 		pathp = (char *)p;
48757d00ecfSStephen Neuendorffer 		p = ALIGN(p + strlen(pathp) + 1, 4);
48857d00ecfSStephen Neuendorffer 		if ((*pathp) == '/') {
48957d00ecfSStephen Neuendorffer 			char *lp, *np;
49057d00ecfSStephen Neuendorffer 			for (lp = NULL, np = pathp; *np; np++)
49157d00ecfSStephen Neuendorffer 				if ((*np) == '/')
49257d00ecfSStephen Neuendorffer 					lp = np+1;
49357d00ecfSStephen Neuendorffer 			if (lp != NULL)
49457d00ecfSStephen Neuendorffer 				pathp = lp;
49557d00ecfSStephen Neuendorffer 		}
49657d00ecfSStephen Neuendorffer 		rc = it(p, pathp, depth, data);
49757d00ecfSStephen Neuendorffer 		if (rc != 0)
49857d00ecfSStephen Neuendorffer 			break;
49957d00ecfSStephen Neuendorffer 	} while (1);
50057d00ecfSStephen Neuendorffer 
50157d00ecfSStephen Neuendorffer 	return rc;
50257d00ecfSStephen Neuendorffer }
50357d00ecfSStephen Neuendorffer 
50457d00ecfSStephen Neuendorffer /**
50557d00ecfSStephen Neuendorffer  * of_get_flat_dt_root - find the root node in the flat blob
50657d00ecfSStephen Neuendorffer  */
50757d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void)
50857d00ecfSStephen Neuendorffer {
50957d00ecfSStephen Neuendorffer 	unsigned long p = ((unsigned long)initial_boot_params) +
51057d00ecfSStephen Neuendorffer 		be32_to_cpu(initial_boot_params->off_dt_struct);
51157d00ecfSStephen Neuendorffer 
51257d00ecfSStephen Neuendorffer 	while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
51357d00ecfSStephen Neuendorffer 		p += 4;
51457d00ecfSStephen Neuendorffer 	BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
51557d00ecfSStephen Neuendorffer 	p += 4;
51657d00ecfSStephen Neuendorffer 	return ALIGN(p + strlen((char *)p) + 1, 4);
51757d00ecfSStephen Neuendorffer }
51857d00ecfSStephen Neuendorffer 
51957d00ecfSStephen Neuendorffer /**
52057d00ecfSStephen Neuendorffer  * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
52157d00ecfSStephen Neuendorffer  *
52257d00ecfSStephen Neuendorffer  * This function can be used within scan_flattened_dt callback to get
52357d00ecfSStephen Neuendorffer  * access to properties
52457d00ecfSStephen Neuendorffer  */
52557d00ecfSStephen Neuendorffer void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
52657d00ecfSStephen Neuendorffer 				 unsigned long *size)
52757d00ecfSStephen Neuendorffer {
52857d00ecfSStephen Neuendorffer 	return of_fdt_get_property(initial_boot_params, node, name, size);
52957d00ecfSStephen Neuendorffer }
53057d00ecfSStephen Neuendorffer 
53157d00ecfSStephen Neuendorffer /**
53257d00ecfSStephen Neuendorffer  * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
53357d00ecfSStephen Neuendorffer  * @node: node to test
53457d00ecfSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
53557d00ecfSStephen Neuendorffer  */
53657d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
53757d00ecfSStephen Neuendorffer {
53857d00ecfSStephen Neuendorffer 	return of_fdt_is_compatible(initial_boot_params, node, compat);
53957d00ecfSStephen Neuendorffer }
54057d00ecfSStephen Neuendorffer 
541a4f740cfSGrant Likely /**
542a4f740cfSGrant Likely  * of_flat_dt_match - Return true if node matches a list of compatible values
543a4f740cfSGrant Likely  */
544a4f740cfSGrant Likely int __init of_flat_dt_match(unsigned long node, const char **compat)
545a4f740cfSGrant Likely {
546a4f740cfSGrant Likely 	return of_fdt_match(initial_boot_params, node, compat);
547a4f740cfSGrant Likely }
548a4f740cfSGrant Likely 
549f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD
550f7b3a835SGrant Likely /**
551f7b3a835SGrant Likely  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
552f7b3a835SGrant Likely  * @node: reference to node containing initrd location ('chosen')
553f7b3a835SGrant Likely  */
554f7b3a835SGrant Likely void __init early_init_dt_check_for_initrd(unsigned long node)
555f7b3a835SGrant Likely {
5561406bc2fSJeremy Kerr 	unsigned long start, end, len;
55733714881SJeremy Kerr 	__be32 *prop;
558f7b3a835SGrant Likely 
559f7b3a835SGrant Likely 	pr_debug("Looking for initrd properties... ");
560f7b3a835SGrant Likely 
561f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
5621406bc2fSJeremy Kerr 	if (!prop)
5631406bc2fSJeremy Kerr 		return;
5641406bc2fSJeremy Kerr 	start = of_read_ulong(prop, len/4);
565f7b3a835SGrant Likely 
566f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
5671406bc2fSJeremy Kerr 	if (!prop)
5681406bc2fSJeremy Kerr 		return;
5691406bc2fSJeremy Kerr 	end = of_read_ulong(prop, len/4);
570f7b3a835SGrant Likely 
5711406bc2fSJeremy Kerr 	early_init_dt_setup_initrd_arch(start, end);
5721406bc2fSJeremy Kerr 	pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n", start, end);
573f7b3a835SGrant Likely }
574f7b3a835SGrant Likely #else
575f7b3a835SGrant Likely inline void early_init_dt_check_for_initrd(unsigned long node)
576f7b3a835SGrant Likely {
577f7b3a835SGrant Likely }
578f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */
579f7b3a835SGrant Likely 
58041f88009SGrant Likely /**
581f00abd94SGrant Likely  * early_init_dt_scan_root - fetch the top level address and size cells
582f00abd94SGrant Likely  */
583f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname,
584f00abd94SGrant Likely 				   int depth, void *data)
585f00abd94SGrant Likely {
58633714881SJeremy Kerr 	__be32 *prop;
587f00abd94SGrant Likely 
588f00abd94SGrant Likely 	if (depth != 0)
589f00abd94SGrant Likely 		return 0;
590f00abd94SGrant Likely 
59133714881SJeremy Kerr 	dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
59233714881SJeremy Kerr 	dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
59333714881SJeremy Kerr 
594f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
59533714881SJeremy Kerr 	if (prop)
59633714881SJeremy Kerr 		dt_root_size_cells = be32_to_cpup(prop);
597f00abd94SGrant Likely 	pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
598f00abd94SGrant Likely 
599f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
60033714881SJeremy Kerr 	if (prop)
60133714881SJeremy Kerr 		dt_root_addr_cells = be32_to_cpup(prop);
602f00abd94SGrant Likely 	pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
603f00abd94SGrant Likely 
604f00abd94SGrant Likely 	/* break now */
605f00abd94SGrant Likely 	return 1;
606f00abd94SGrant Likely }
607f00abd94SGrant Likely 
6082e89e685SJeremy Kerr u64 __init dt_mem_next_cell(int s, __be32 **cellp)
60983f7a06eSGrant Likely {
6102e89e685SJeremy Kerr 	__be32 *p = *cellp;
61183f7a06eSGrant Likely 
61283f7a06eSGrant Likely 	*cellp = p + s;
61383f7a06eSGrant Likely 	return of_read_number(p, s);
61483f7a06eSGrant Likely }
61583f7a06eSGrant Likely 
61651975db0SGrant Likely /**
61751975db0SGrant Likely  * early_init_dt_scan_memory - Look for an parse memory nodes
61851975db0SGrant Likely  */
61951975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
62051975db0SGrant Likely 				     int depth, void *data)
62151975db0SGrant Likely {
62251975db0SGrant Likely 	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
62351975db0SGrant Likely 	__be32 *reg, *endp;
62451975db0SGrant Likely 	unsigned long l;
62551975db0SGrant Likely 
62651975db0SGrant Likely 	/* We are scanning "memory" nodes only */
62751975db0SGrant Likely 	if (type == NULL) {
62851975db0SGrant Likely 		/*
62951975db0SGrant Likely 		 * The longtrail doesn't have a device_type on the
63051975db0SGrant Likely 		 * /memory node, so look for the node called /memory@0.
63151975db0SGrant Likely 		 */
63251975db0SGrant Likely 		if (depth != 1 || strcmp(uname, "memory@0") != 0)
63351975db0SGrant Likely 			return 0;
63451975db0SGrant Likely 	} else if (strcmp(type, "memory") != 0)
63551975db0SGrant Likely 		return 0;
63651975db0SGrant Likely 
63751975db0SGrant Likely 	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
63851975db0SGrant Likely 	if (reg == NULL)
63951975db0SGrant Likely 		reg = of_get_flat_dt_prop(node, "reg", &l);
64051975db0SGrant Likely 	if (reg == NULL)
64151975db0SGrant Likely 		return 0;
64251975db0SGrant Likely 
64351975db0SGrant Likely 	endp = reg + (l / sizeof(__be32));
64451975db0SGrant Likely 
64551975db0SGrant Likely 	pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
64651975db0SGrant Likely 	    uname, l, reg[0], reg[1], reg[2], reg[3]);
64751975db0SGrant Likely 
64851975db0SGrant Likely 	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
64951975db0SGrant Likely 		u64 base, size;
65051975db0SGrant Likely 
65151975db0SGrant Likely 		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
65251975db0SGrant Likely 		size = dt_mem_next_cell(dt_root_size_cells, &reg);
65351975db0SGrant Likely 
65451975db0SGrant Likely 		if (size == 0)
65551975db0SGrant Likely 			continue;
65651975db0SGrant Likely 		pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
65751975db0SGrant Likely 		    (unsigned long long)size);
65851975db0SGrant Likely 
65951975db0SGrant Likely 		early_init_dt_add_memory_arch(base, size);
66051975db0SGrant Likely 	}
66151975db0SGrant Likely 
66251975db0SGrant Likely 	return 0;
66351975db0SGrant Likely }
66451975db0SGrant Likely 
66586e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
66686e03221SGrant Likely 				     int depth, void *data)
66786e03221SGrant Likely {
66886e03221SGrant Likely 	unsigned long l;
66986e03221SGrant Likely 	char *p;
67086e03221SGrant Likely 
67186e03221SGrant Likely 	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
67286e03221SGrant Likely 
67386e03221SGrant Likely 	if (depth != 1 ||
67486e03221SGrant Likely 	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
67586e03221SGrant Likely 		return 0;
67686e03221SGrant Likely 
67786e03221SGrant Likely 	early_init_dt_check_for_initrd(node);
67886e03221SGrant Likely 
67986e03221SGrant Likely 	/* Retreive command line */
68086e03221SGrant Likely 	p = of_get_flat_dt_prop(node, "bootargs", &l);
68186e03221SGrant Likely 	if (p != NULL && l > 0)
68286e03221SGrant Likely 		strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
68386e03221SGrant Likely 
68486e03221SGrant Likely #ifdef CONFIG_CMDLINE
68586e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE
68686e03221SGrant Likely 	if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
68786e03221SGrant Likely #endif
68886e03221SGrant Likely 		strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
68986e03221SGrant Likely #endif /* CONFIG_CMDLINE */
69086e03221SGrant Likely 
69186e03221SGrant Likely 	pr_debug("Command line is: %s\n", cmd_line);
69286e03221SGrant Likely 
69386e03221SGrant Likely 	/* break now */
69486e03221SGrant Likely 	return 1;
69586e03221SGrant Likely }
69686e03221SGrant Likely 
697f00abd94SGrant Likely /**
69841f88009SGrant Likely  * unflatten_device_tree - create tree of device_nodes from flat blob
69941f88009SGrant Likely  *
70041f88009SGrant Likely  * unflattens the device-tree passed by the firmware, creating the
70141f88009SGrant Likely  * tree of struct device_node. It also fills the "name" and "type"
70241f88009SGrant Likely  * pointers of the nodes so the normal device-tree walking functions
70341f88009SGrant Likely  * can be used.
70441f88009SGrant Likely  */
70541f88009SGrant Likely void __init unflatten_device_tree(void)
70641f88009SGrant Likely {
707fe140423SStephen Neuendorffer 	__unflatten_device_tree(initial_boot_params, &allnodes,
708672c5446SGrant Likely 				early_init_dt_alloc_memory_arch);
70941f88009SGrant Likely 
71041f88009SGrant Likely 	/* Get pointer to OF "/chosen" node for use everywhere */
71141f88009SGrant Likely 	of_chosen = of_find_node_by_path("/chosen");
71241f88009SGrant Likely 	if (of_chosen == NULL)
71341f88009SGrant Likely 		of_chosen = of_find_node_by_path("/chosen@0");
71441f88009SGrant Likely }
715e6ce1324SStephen Neuendorffer 
716e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */
717