xref: /openbmc/linux/drivers/of/fdt.c (revision 2f945a79)
1af6074fcSRob Herring // SPDX-License-Identifier: GPL-2.0
2e169cfbeSGrant Likely /*
3e169cfbeSGrant Likely  * Functions for working with the Flattened Device Tree data format
4e169cfbeSGrant Likely  *
5e169cfbeSGrant Likely  * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
6e169cfbeSGrant Likely  * benh@kernel.crashing.org
7e169cfbeSGrant Likely  */
8e169cfbeSGrant Likely 
9606ad42aSRob Herring #define pr_fmt(fmt)	"OF: fdt: " fmt
10606ad42aSRob Herring 
11f7e7ce93SGeert Uytterhoeven #include <linux/crash_dump.h>
1208d53aa5SArd Biesheuvel #include <linux/crc32.h>
1341f88009SGrant Likely #include <linux/kernel.h>
14f7b3a835SGrant Likely #include <linux/initrd.h>
15a1727da5SGrant Likely #include <linux/memblock.h>
16f8062386SGuenter Roeck #include <linux/mutex.h>
17e169cfbeSGrant Likely #include <linux/of.h>
18e169cfbeSGrant Likely #include <linux/of_fdt.h>
193f0c8206SMarek Szyprowski #include <linux/of_reserved_mem.h>
20e8d9d1f5SMarek Szyprowski #include <linux/sizes.h>
214ef7b373SJeremy Kerr #include <linux/string.h>
224ef7b373SJeremy Kerr #include <linux/errno.h>
23fe140423SStephen Neuendorffer #include <linux/slab.h>
24e6a6928cSRob Herring #include <linux/libfdt.h>
25b0a6fb36SRob Herring #include <linux/debugfs.h>
26fb11ffe7SRob Herring #include <linux/serial_core.h>
2708d53aa5SArd Biesheuvel #include <linux/sysfs.h>
28428826f5SHsin-Yi Wang #include <linux/random.h>
29972fa3a7SCalvin Zhang #include <linux/kmemleak.h>
3051975db0SGrant Likely 
31c89810acSFabio Estevam #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
324ef7b373SJeremy Kerr #include <asm/page.h>
334ef7b373SJeremy Kerr 
3481d0848fSFrank Rowand #include "of_private.h"
3581d0848fSFrank Rowand 
36704033ceSLaura Abbott /*
37704033ceSLaura Abbott  * of_fdt_limit_memory - limit the number of regions in the /memory node
38704033ceSLaura Abbott  * @limit: maximum entries
39704033ceSLaura Abbott  *
40704033ceSLaura Abbott  * Adjust the flattened device tree to have at most 'limit' number of
41704033ceSLaura Abbott  * memory entries in the /memory node. This function may be called
42704033ceSLaura Abbott  * any time after initial_boot_param is set.
43704033ceSLaura Abbott  */
449b4d2b63SStephen Boyd void __init of_fdt_limit_memory(int limit)
45704033ceSLaura Abbott {
46704033ceSLaura Abbott 	int memory;
47704033ceSLaura Abbott 	int len;
48704033ceSLaura Abbott 	const void *val;
49704033ceSLaura Abbott 	int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
50704033ceSLaura Abbott 	int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
5117a70355SRob Herring 	const __be32 *addr_prop;
5217a70355SRob Herring 	const __be32 *size_prop;
53704033ceSLaura Abbott 	int root_offset;
54704033ceSLaura Abbott 	int cell_size;
55704033ceSLaura Abbott 
56704033ceSLaura Abbott 	root_offset = fdt_path_offset(initial_boot_params, "/");
57704033ceSLaura Abbott 	if (root_offset < 0)
58704033ceSLaura Abbott 		return;
59704033ceSLaura Abbott 
60704033ceSLaura Abbott 	addr_prop = fdt_getprop(initial_boot_params, root_offset,
61704033ceSLaura Abbott 				"#address-cells", NULL);
62704033ceSLaura Abbott 	if (addr_prop)
63704033ceSLaura Abbott 		nr_address_cells = fdt32_to_cpu(*addr_prop);
64704033ceSLaura Abbott 
65704033ceSLaura Abbott 	size_prop = fdt_getprop(initial_boot_params, root_offset,
66704033ceSLaura Abbott 				"#size-cells", NULL);
67704033ceSLaura Abbott 	if (size_prop)
68704033ceSLaura Abbott 		nr_size_cells = fdt32_to_cpu(*size_prop);
69704033ceSLaura Abbott 
70704033ceSLaura Abbott 	cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells);
71704033ceSLaura Abbott 
72704033ceSLaura Abbott 	memory = fdt_path_offset(initial_boot_params, "/memory");
73704033ceSLaura Abbott 	if (memory > 0) {
74704033ceSLaura Abbott 		val = fdt_getprop(initial_boot_params, memory, "reg", &len);
75704033ceSLaura Abbott 		if (len > limit*cell_size) {
76704033ceSLaura Abbott 			len = limit*cell_size;
77704033ceSLaura Abbott 			pr_debug("Limiting number of entries to %d\n", limit);
78704033ceSLaura Abbott 			fdt_setprop(initial_boot_params, memory, "reg", val,
79704033ceSLaura Abbott 					len);
80704033ceSLaura Abbott 		}
81704033ceSLaura Abbott 	}
82704033ceSLaura Abbott }
83704033ceSLaura Abbott 
84ecc8a96eSRob Herring static bool of_fdt_device_is_available(const void *blob, unsigned long node)
85ecc8a96eSRob Herring {
86ecc8a96eSRob Herring 	const char *status = fdt_getprop(blob, node, "status", NULL);
87ecc8a96eSRob Herring 
88ecc8a96eSRob Herring 	if (!status)
89ecc8a96eSRob Herring 		return true;
90ecc8a96eSRob Herring 
91ecc8a96eSRob Herring 	if (!strcmp(status, "ok") || !strcmp(status, "okay"))
92ecc8a96eSRob Herring 		return true;
93ecc8a96eSRob Herring 
94ecc8a96eSRob Herring 	return false;
95ecc8a96eSRob Herring }
96ecc8a96eSRob Herring 
9744856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size,
98bbd33931SGrant Likely 				       unsigned long align)
99bbd33931SGrant Likely {
100bbd33931SGrant Likely 	void *res;
101bbd33931SGrant Likely 
10244856819SGrant Likely 	*mem = PTR_ALIGN(*mem, align);
10344856819SGrant Likely 	res = *mem;
104bbd33931SGrant Likely 	*mem += size;
105bbd33931SGrant Likely 
106bbd33931SGrant Likely 	return res;
107bbd33931SGrant Likely }
108bbd33931SGrant Likely 
109dfbd4c6eSGavin Shan static void populate_properties(const void *blob,
110dfbd4c6eSGavin Shan 				int offset,
111dfbd4c6eSGavin Shan 				void **mem,
112dfbd4c6eSGavin Shan 				struct device_node *np,
113dfbd4c6eSGavin Shan 				const char *nodename,
1145063e25aSGrant Likely 				bool dryrun)
115bbd33931SGrant Likely {
116dfbd4c6eSGavin Shan 	struct property *pp, **pprev = NULL;
117dfbd4c6eSGavin Shan 	int cur;
118dfbd4c6eSGavin Shan 	bool has_name = false;
119dfbd4c6eSGavin Shan 
120dfbd4c6eSGavin Shan 	pprev = &np->properties;
121dfbd4c6eSGavin Shan 	for (cur = fdt_first_property_offset(blob, offset);
122dfbd4c6eSGavin Shan 	     cur >= 0;
123dfbd4c6eSGavin Shan 	     cur = fdt_next_property_offset(blob, cur)) {
124dfbd4c6eSGavin Shan 		const __be32 *val;
125dfbd4c6eSGavin Shan 		const char *pname;
126dfbd4c6eSGavin Shan 		u32 sz;
127dfbd4c6eSGavin Shan 
128dfbd4c6eSGavin Shan 		val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
129dfbd4c6eSGavin Shan 		if (!val) {
130606ad42aSRob Herring 			pr_warn("Cannot locate property at 0x%x\n", cur);
131dfbd4c6eSGavin Shan 			continue;
132dfbd4c6eSGavin Shan 		}
133dfbd4c6eSGavin Shan 
134dfbd4c6eSGavin Shan 		if (!pname) {
135606ad42aSRob Herring 			pr_warn("Cannot find property name at 0x%x\n", cur);
136dfbd4c6eSGavin Shan 			continue;
137dfbd4c6eSGavin Shan 		}
138dfbd4c6eSGavin Shan 
139dfbd4c6eSGavin Shan 		if (!strcmp(pname, "name"))
140dfbd4c6eSGavin Shan 			has_name = true;
141dfbd4c6eSGavin Shan 
142dfbd4c6eSGavin Shan 		pp = unflatten_dt_alloc(mem, sizeof(struct property),
143dfbd4c6eSGavin Shan 					__alignof__(struct property));
144dfbd4c6eSGavin Shan 		if (dryrun)
145dfbd4c6eSGavin Shan 			continue;
146dfbd4c6eSGavin Shan 
147dfbd4c6eSGavin Shan 		/* We accept flattened tree phandles either in
148dfbd4c6eSGavin Shan 		 * ePAPR-style "phandle" properties, or the
149dfbd4c6eSGavin Shan 		 * legacy "linux,phandle" properties.  If both
150dfbd4c6eSGavin Shan 		 * appear and have different values, things
151dfbd4c6eSGavin Shan 		 * will get weird. Don't do that.
152dfbd4c6eSGavin Shan 		 */
153dfbd4c6eSGavin Shan 		if (!strcmp(pname, "phandle") ||
154dfbd4c6eSGavin Shan 		    !strcmp(pname, "linux,phandle")) {
155dfbd4c6eSGavin Shan 			if (!np->phandle)
156dfbd4c6eSGavin Shan 				np->phandle = be32_to_cpup(val);
157dfbd4c6eSGavin Shan 		}
158dfbd4c6eSGavin Shan 
159dfbd4c6eSGavin Shan 		/* And we process the "ibm,phandle" property
160dfbd4c6eSGavin Shan 		 * used in pSeries dynamic device tree
161dfbd4c6eSGavin Shan 		 * stuff
162dfbd4c6eSGavin Shan 		 */
163dfbd4c6eSGavin Shan 		if (!strcmp(pname, "ibm,phandle"))
164dfbd4c6eSGavin Shan 			np->phandle = be32_to_cpup(val);
165dfbd4c6eSGavin Shan 
166dfbd4c6eSGavin Shan 		pp->name   = (char *)pname;
167dfbd4c6eSGavin Shan 		pp->length = sz;
168dfbd4c6eSGavin Shan 		pp->value  = (__be32 *)val;
169dfbd4c6eSGavin Shan 		*pprev     = pp;
170dfbd4c6eSGavin Shan 		pprev      = &pp->next;
171dfbd4c6eSGavin Shan 	}
172dfbd4c6eSGavin Shan 
173dfbd4c6eSGavin Shan 	/* With version 0x10 we may not have the name property,
174dfbd4c6eSGavin Shan 	 * recreate it here from the unit name if absent
175dfbd4c6eSGavin Shan 	 */
176dfbd4c6eSGavin Shan 	if (!has_name) {
177dfbd4c6eSGavin Shan 		const char *p = nodename, *ps = p, *pa = NULL;
178dfbd4c6eSGavin Shan 		int len;
179dfbd4c6eSGavin Shan 
180dfbd4c6eSGavin Shan 		while (*p) {
181dfbd4c6eSGavin Shan 			if ((*p) == '@')
182dfbd4c6eSGavin Shan 				pa = p;
183dfbd4c6eSGavin Shan 			else if ((*p) == '/')
184dfbd4c6eSGavin Shan 				ps = p + 1;
185dfbd4c6eSGavin Shan 			p++;
186dfbd4c6eSGavin Shan 		}
187dfbd4c6eSGavin Shan 
188dfbd4c6eSGavin Shan 		if (pa < ps)
189dfbd4c6eSGavin Shan 			pa = p;
190dfbd4c6eSGavin Shan 		len = (pa - ps) + 1;
191dfbd4c6eSGavin Shan 		pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
192dfbd4c6eSGavin Shan 					__alignof__(struct property));
193dfbd4c6eSGavin Shan 		if (!dryrun) {
194dfbd4c6eSGavin Shan 			pp->name   = "name";
195dfbd4c6eSGavin Shan 			pp->length = len;
196dfbd4c6eSGavin Shan 			pp->value  = pp + 1;
197dfbd4c6eSGavin Shan 			*pprev     = pp;
198dfbd4c6eSGavin Shan 			memcpy(pp->value, ps, len - 1);
199dfbd4c6eSGavin Shan 			((char *)pp->value)[len - 1] = 0;
200dfbd4c6eSGavin Shan 			pr_debug("fixed up name for %s -> %s\n",
201dfbd4c6eSGavin Shan 				 nodename, (char *)pp->value);
202dfbd4c6eSGavin Shan 		}
203dfbd4c6eSGavin Shan 	}
204dfbd4c6eSGavin Shan }
205dfbd4c6eSGavin Shan 
206649cab56SFrank Rowand static int populate_node(const void *blob,
207dfbd4c6eSGavin Shan 			  int offset,
208dfbd4c6eSGavin Shan 			  void **mem,
209dfbd4c6eSGavin Shan 			  struct device_node *dad,
210dfbd4c6eSGavin Shan 			  struct device_node **pnp,
211dfbd4c6eSGavin Shan 			  bool dryrun)
212dfbd4c6eSGavin Shan {
213bbd33931SGrant Likely 	struct device_node *np;
214e6a6928cSRob Herring 	const char *pathp;
215649cab56SFrank Rowand 	int len;
216bbd33931SGrant Likely 
217649cab56SFrank Rowand 	pathp = fdt_get_name(blob, offset, &len);
218dfbd4c6eSGavin Shan 	if (!pathp) {
219dfbd4c6eSGavin Shan 		*pnp = NULL;
220649cab56SFrank Rowand 		return len;
221dfbd4c6eSGavin Shan 	}
222e6a6928cSRob Herring 
223649cab56SFrank Rowand 	len++;
224bbd33931SGrant Likely 
225649cab56SFrank Rowand 	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + len,
226bbd33931SGrant Likely 				__alignof__(struct device_node));
2275063e25aSGrant Likely 	if (!dryrun) {
228c22618a1SGrant Likely 		char *fn;
2290829f6d1SPantelis Antoniou 		of_node_init(np);
230c22618a1SGrant Likely 		np->full_name = fn = ((char *)np) + sizeof(*np);
231a7e4cfb0SRob Herring 
232649cab56SFrank Rowand 		memcpy(fn, pathp, len);
233c22618a1SGrant Likely 
234bbd33931SGrant Likely 		if (dad != NULL) {
235bbd33931SGrant Likely 			np->parent = dad;
23670161ff3SGrant Likely 			np->sibling = dad->child;
237bbd33931SGrant Likely 			dad->child = np;
238bbd33931SGrant Likely 		}
239bbd33931SGrant Likely 	}
240bbd33931SGrant Likely 
241dfbd4c6eSGavin Shan 	populate_properties(blob, offset, mem, np, pathp, dryrun);
2425063e25aSGrant Likely 	if (!dryrun) {
243bbd33931SGrant Likely 		np->name = of_get_property(np, "name", NULL);
244bbd33931SGrant Likely 		if (!np->name)
245bbd33931SGrant Likely 			np->name = "<NULL>";
246bbd33931SGrant Likely 	}
247e6a6928cSRob Herring 
248dfbd4c6eSGavin Shan 	*pnp = np;
2497913145aSXu Qiang 	return 0;
250dfbd4c6eSGavin Shan }
251dfbd4c6eSGavin Shan 
25250800082SGavin Shan static void reverse_nodes(struct device_node *parent)
25350800082SGavin Shan {
25450800082SGavin Shan 	struct device_node *child, *next;
25550800082SGavin Shan 
25650800082SGavin Shan 	/* In-depth first */
25750800082SGavin Shan 	child = parent->child;
25850800082SGavin Shan 	while (child) {
25950800082SGavin Shan 		reverse_nodes(child);
26050800082SGavin Shan 
26150800082SGavin Shan 		child = child->sibling;
26250800082SGavin Shan 	}
26350800082SGavin Shan 
26450800082SGavin Shan 	/* Reverse the nodes in the child list */
26550800082SGavin Shan 	child = parent->child;
26650800082SGavin Shan 	parent->child = NULL;
26750800082SGavin Shan 	while (child) {
26850800082SGavin Shan 		next = child->sibling;
26950800082SGavin Shan 
27050800082SGavin Shan 		child->sibling = parent->child;
27150800082SGavin Shan 		parent->child = child;
27250800082SGavin Shan 		child = next;
27350800082SGavin Shan 	}
27450800082SGavin Shan }
27550800082SGavin Shan 
276dfbd4c6eSGavin Shan /**
277947c82cbSGavin Shan  * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree
278dfbd4c6eSGavin Shan  * @blob: The parent device tree blob
279dfbd4c6eSGavin Shan  * @mem: Memory chunk to use for allocating device nodes and properties
280dfbd4c6eSGavin Shan  * @dad: Parent struct device_node
281dfbd4c6eSGavin Shan  * @nodepp: The device_node tree created by the call
28250800082SGavin Shan  *
2838c8239c2SRob Herring  * Return: The size of unflattened device tree or error code
284dfbd4c6eSGavin Shan  */
285947c82cbSGavin Shan static int unflatten_dt_nodes(const void *blob,
286dfbd4c6eSGavin Shan 			      void *mem,
287dfbd4c6eSGavin Shan 			      struct device_node *dad,
28850800082SGavin Shan 			      struct device_node **nodepp)
289dfbd4c6eSGavin Shan {
29050800082SGavin Shan 	struct device_node *root;
2918c237cd0SGavin Shan 	int offset = 0, depth = 0, initial_depth = 0;
29250800082SGavin Shan #define FDT_MAX_DEPTH	64
29350800082SGavin Shan 	struct device_node *nps[FDT_MAX_DEPTH];
29450800082SGavin Shan 	void *base = mem;
29550800082SGavin Shan 	bool dryrun = !base;
296649cab56SFrank Rowand 	int ret;
297dfbd4c6eSGavin Shan 
29850800082SGavin Shan 	if (nodepp)
29950800082SGavin Shan 		*nodepp = NULL;
300dfbd4c6eSGavin Shan 
3018c237cd0SGavin Shan 	/*
3028c237cd0SGavin Shan 	 * We're unflattening device sub-tree if @dad is valid. There are
3038c237cd0SGavin Shan 	 * possibly multiple nodes in the first level of depth. We need
3048c237cd0SGavin Shan 	 * set @depth to 1 to make fdt_next_node() happy as it bails
3058c237cd0SGavin Shan 	 * immediately when negative @depth is found. Otherwise, the device
3068c237cd0SGavin Shan 	 * nodes except the first one won't be unflattened successfully.
3078c237cd0SGavin Shan 	 */
3088c237cd0SGavin Shan 	if (dad)
3098c237cd0SGavin Shan 		depth = initial_depth = 1;
3108c237cd0SGavin Shan 
31150800082SGavin Shan 	root = dad;
31278c44d91SRhyland Klein 	nps[depth] = dad;
3138c237cd0SGavin Shan 
31450800082SGavin Shan 	for (offset = 0;
3158c237cd0SGavin Shan 	     offset >= 0 && depth >= initial_depth;
31650800082SGavin Shan 	     offset = fdt_next_node(blob, offset, &depth)) {
317*2f945a79SSergey Shtylyov 		if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH - 1))
31850800082SGavin Shan 			continue;
319e6a6928cSRob Herring 
32077ea8a68SRob Herring 		if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
32177ea8a68SRob Herring 		    !of_fdt_device_is_available(blob, offset))
32277ea8a68SRob Herring 			continue;
32377ea8a68SRob Herring 
324649cab56SFrank Rowand 		ret = populate_node(blob, offset, &mem, nps[depth],
325649cab56SFrank Rowand 				   &nps[depth+1], dryrun);
326649cab56SFrank Rowand 		if (ret < 0)
327649cab56SFrank Rowand 			return ret;
32850800082SGavin Shan 
32950800082SGavin Shan 		if (!dryrun && nodepp && !*nodepp)
33078c44d91SRhyland Klein 			*nodepp = nps[depth+1];
33150800082SGavin Shan 		if (!dryrun && !root)
33278c44d91SRhyland Klein 			root = nps[depth+1];
33350800082SGavin Shan 	}
33450800082SGavin Shan 
33550800082SGavin Shan 	if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
336606ad42aSRob Herring 		pr_err("Error %d processing FDT\n", offset);
33750800082SGavin Shan 		return -EINVAL;
33850800082SGavin Shan 	}
339e6a6928cSRob Herring 
34070161ff3SGrant Likely 	/*
34170161ff3SGrant Likely 	 * Reverse the child list. Some drivers assumes node order matches .dts
34270161ff3SGrant Likely 	 * node order
34370161ff3SGrant Likely 	 */
34450800082SGavin Shan 	if (!dryrun)
34550800082SGavin Shan 		reverse_nodes(root);
34670161ff3SGrant Likely 
34750800082SGavin Shan 	return mem - base;
348bbd33931SGrant Likely }
34941f88009SGrant Likely 
350fe140423SStephen Neuendorffer /**
351fe140423SStephen Neuendorffer  * __unflatten_device_tree - create tree of device_nodes from flat blob
352fe140423SStephen Neuendorffer  * @blob: The blob to expand
353c4263233SGavin Shan  * @dad: Parent device node
354fe140423SStephen Neuendorffer  * @mynodes: The device_node tree created by the call
355fe140423SStephen Neuendorffer  * @dt_alloc: An allocator that provides a virtual address to memory
356fe140423SStephen Neuendorffer  * for the resulting tree
357f5d2da67SStephen Boyd  * @detached: if true set OF_DETACHED on @mynodes
35883262418SGavin Shan  *
35962f026f0SRob Herring  * unflattens a device-tree, creating the tree of struct device_node. It also
36062f026f0SRob Herring  * fills the "name" and "type" pointers of the nodes so the normal device-tree
36162f026f0SRob Herring  * walking functions can be used.
36262f026f0SRob Herring  *
3638c8239c2SRob Herring  * Return: NULL on failure or the memory chunk containing the unflattened
36483262418SGavin Shan  * device tree on success.
365fe140423SStephen Neuendorffer  */
36681d0848fSFrank Rowand void *__unflatten_device_tree(const void *blob,
367c4263233SGavin Shan 			      struct device_node *dad,
368fe140423SStephen Neuendorffer 			      struct device_node **mynodes,
3691d1bde55SMichal Suchanek 			      void *(*dt_alloc)(u64 size, u64 align),
3701d1bde55SMichal Suchanek 			      bool detached)
371fe140423SStephen Neuendorffer {
37250800082SGavin Shan 	int size;
373e6a6928cSRob Herring 	void *mem;
374649cab56SFrank Rowand 	int ret;
375649cab56SFrank Rowand 
376649cab56SFrank Rowand 	if (mynodes)
377649cab56SFrank Rowand 		*mynodes = NULL;
378fe140423SStephen Neuendorffer 
379fe140423SStephen Neuendorffer 	pr_debug(" -> unflatten_device_tree()\n");
380fe140423SStephen Neuendorffer 
381fe140423SStephen Neuendorffer 	if (!blob) {
382fe140423SStephen Neuendorffer 		pr_debug("No device tree pointer\n");
38383262418SGavin Shan 		return NULL;
384fe140423SStephen Neuendorffer 	}
385fe140423SStephen Neuendorffer 
386fe140423SStephen Neuendorffer 	pr_debug("Unflattening device tree:\n");
387c972de14SRob Herring 	pr_debug("magic: %08x\n", fdt_magic(blob));
388c972de14SRob Herring 	pr_debug("size: %08x\n", fdt_totalsize(blob));
389c972de14SRob Herring 	pr_debug("version: %08x\n", fdt_version(blob));
390fe140423SStephen Neuendorffer 
391c972de14SRob Herring 	if (fdt_check_header(blob)) {
392fe140423SStephen Neuendorffer 		pr_err("Invalid device tree blob header\n");
39383262418SGavin Shan 		return NULL;
394fe140423SStephen Neuendorffer 	}
395fe140423SStephen Neuendorffer 
396fe140423SStephen Neuendorffer 	/* First pass, scan for size */
397c4263233SGavin Shan 	size = unflatten_dt_nodes(blob, NULL, dad, NULL);
398649cab56SFrank Rowand 	if (size <= 0)
39983262418SGavin Shan 		return NULL;
400fe140423SStephen Neuendorffer 
40150800082SGavin Shan 	size = ALIGN(size, 4);
40250800082SGavin Shan 	pr_debug("  size is %d, allocating...\n", size);
403fe140423SStephen Neuendorffer 
404fe140423SStephen Neuendorffer 	/* Allocate memory for the expanded device tree */
40544856819SGrant Likely 	mem = dt_alloc(size + 4, __alignof__(struct device_node));
40649e67dd1SJohan Hovold 	if (!mem)
40749e67dd1SJohan Hovold 		return NULL;
40849e67dd1SJohan Hovold 
40944856819SGrant Likely 	memset(mem, 0, size);
410fe140423SStephen Neuendorffer 
41144856819SGrant Likely 	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
4129e401275SWladislav Wiebe 
41344856819SGrant Likely 	pr_debug("  unflattening %p...\n", mem);
414fe140423SStephen Neuendorffer 
415fe140423SStephen Neuendorffer 	/* Second pass, do actual unflattening */
416649cab56SFrank Rowand 	ret = unflatten_dt_nodes(blob, mem, dad, mynodes);
417649cab56SFrank Rowand 
41844856819SGrant Likely 	if (be32_to_cpup(mem + size) != 0xdeadbeef)
419e2f04da7SKefeng Wang 		pr_warn("End of tree marker overwritten: %08x\n",
42044856819SGrant Likely 			be32_to_cpup(mem + size));
421fe140423SStephen Neuendorffer 
422649cab56SFrank Rowand 	if (ret <= 0)
423649cab56SFrank Rowand 		return NULL;
424649cab56SFrank Rowand 
425649cab56SFrank Rowand 	if (detached && mynodes && *mynodes) {
4261d1bde55SMichal Suchanek 		of_node_set_flag(*mynodes, OF_DETACHED);
4271d1bde55SMichal Suchanek 		pr_debug("unflattened tree is detached\n");
4281d1bde55SMichal Suchanek 	}
4291d1bde55SMichal Suchanek 
430fe140423SStephen Neuendorffer 	pr_debug(" <- unflatten_device_tree()\n");
43183262418SGavin Shan 	return mem;
432fe140423SStephen Neuendorffer }
433fe140423SStephen Neuendorffer 
434fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align)
435fe140423SStephen Neuendorffer {
436fe140423SStephen Neuendorffer 	return kzalloc(size, GFP_KERNEL);
437fe140423SStephen Neuendorffer }
438fe140423SStephen Neuendorffer 
439f8062386SGuenter Roeck static DEFINE_MUTEX(of_fdt_unflatten_mutex);
440f8062386SGuenter Roeck 
441fe140423SStephen Neuendorffer /**
442fe140423SStephen Neuendorffer  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
443c4263233SGavin Shan  * @blob: Flat device tree blob
444c4263233SGavin Shan  * @dad: Parent device node
445c4263233SGavin Shan  * @mynodes: The device tree created by the call
446fe140423SStephen Neuendorffer  *
447fe140423SStephen Neuendorffer  * unflattens the device-tree passed by the firmware, creating the
448fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
449fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
450fe140423SStephen Neuendorffer  * can be used.
45183262418SGavin Shan  *
4528c8239c2SRob Herring  * Return: NULL on failure or the memory chunk containing the unflattened
45383262418SGavin Shan  * device tree on success.
454fe140423SStephen Neuendorffer  */
45583262418SGavin Shan void *of_fdt_unflatten_tree(const unsigned long *blob,
456c4263233SGavin Shan 			    struct device_node *dad,
457fe140423SStephen Neuendorffer 			    struct device_node **mynodes)
458fe140423SStephen Neuendorffer {
45983262418SGavin Shan 	void *mem;
46083262418SGavin Shan 
461f8062386SGuenter Roeck 	mutex_lock(&of_fdt_unflatten_mutex);
4621d1bde55SMichal Suchanek 	mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc,
4631d1bde55SMichal Suchanek 				      true);
464f8062386SGuenter Roeck 	mutex_unlock(&of_fdt_unflatten_mutex);
46583262418SGavin Shan 
46683262418SGavin Shan 	return mem;
467fe140423SStephen Neuendorffer }
468fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
469fe140423SStephen Neuendorffer 
47057d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */
47157d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells;
47257d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells;
47357d00ecfSStephen Neuendorffer 
4747c71650fSStephen Boyd void *initial_boot_params __ro_after_init;
47557d00ecfSStephen Neuendorffer 
47657d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE
47757d00ecfSStephen Neuendorffer 
47808d53aa5SArd Biesheuvel static u32 of_fdt_crc32;
47908d53aa5SArd Biesheuvel 
480f8a855edSPeter Collingbourne static int __init early_init_dt_reserve_memory(phys_addr_t base,
48118250b43SGeert Uytterhoeven 					       phys_addr_t size, bool nomap)
48218250b43SGeert Uytterhoeven {
48318250b43SGeert Uytterhoeven 	if (nomap) {
48418250b43SGeert Uytterhoeven 		/*
48518250b43SGeert Uytterhoeven 		 * If the memory is already reserved (by another region), we
486da17d690SStephen Boyd 		 * should not allow it to be marked nomap, but don't worry
487da17d690SStephen Boyd 		 * if the region isn't memory as it won't be mapped.
48818250b43SGeert Uytterhoeven 		 */
489da17d690SStephen Boyd 		if (memblock_overlaps_region(&memblock.memory, base, size) &&
490da17d690SStephen Boyd 		    memblock_is_region_reserved(base, size))
49118250b43SGeert Uytterhoeven 			return -EBUSY;
49218250b43SGeert Uytterhoeven 
49318250b43SGeert Uytterhoeven 		return memblock_mark_nomap(base, size);
49418250b43SGeert Uytterhoeven 	}
49518250b43SGeert Uytterhoeven 	return memblock_reserve(base, size);
49618250b43SGeert Uytterhoeven }
49718250b43SGeert Uytterhoeven 
498a300dc86SLee Jones /*
499c8813f7eSchenqiwu  * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
500e8d9d1f5SMarek Szyprowski  */
501e8d9d1f5SMarek Szyprowski static int __init __reserved_mem_reserve_reg(unsigned long node,
502e8d9d1f5SMarek Szyprowski 					     const char *uname)
503e8d9d1f5SMarek Szyprowski {
504e8d9d1f5SMarek Szyprowski 	int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
505e8d9d1f5SMarek Szyprowski 	phys_addr_t base, size;
5069d0c4dfeSRob Herring 	int len;
5079d0c4dfeSRob Herring 	const __be32 *prop;
5085c68b823SMasahiro Yamada 	int first = 1;
5095c68b823SMasahiro Yamada 	bool nomap;
510e8d9d1f5SMarek Szyprowski 
511e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "reg", &len);
512e8d9d1f5SMarek Szyprowski 	if (!prop)
513e8d9d1f5SMarek Szyprowski 		return -ENOENT;
514e8d9d1f5SMarek Szyprowski 
515e8d9d1f5SMarek Szyprowski 	if (len && len % t_len != 0) {
516e8d9d1f5SMarek Szyprowski 		pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
517e8d9d1f5SMarek Szyprowski 		       uname);
518e8d9d1f5SMarek Szyprowski 		return -EINVAL;
519e8d9d1f5SMarek Szyprowski 	}
520e8d9d1f5SMarek Szyprowski 
521e8d9d1f5SMarek Szyprowski 	nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
522e8d9d1f5SMarek Szyprowski 
523e8d9d1f5SMarek Szyprowski 	while (len >= t_len) {
524e8d9d1f5SMarek Szyprowski 		base = dt_mem_next_cell(dt_root_addr_cells, &prop);
525e8d9d1f5SMarek Szyprowski 		size = dt_mem_next_cell(dt_root_size_cells, &prop);
526e8d9d1f5SMarek Szyprowski 
527b5f2a8c0SAl Cooper 		if (size &&
528f8a855edSPeter Collingbourne 		    early_init_dt_reserve_memory(base, size, nomap) == 0) {
5292892d8a0SGeert Uytterhoeven 			pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
5302892d8a0SGeert Uytterhoeven 				uname, &base, (unsigned long)(size / SZ_1M));
531972fa3a7SCalvin Zhang 			if (!nomap)
532c200d900SPatrick Wang 				kmemleak_alloc_phys(base, size, 0);
533972fa3a7SCalvin Zhang 		}
534e8d9d1f5SMarek Szyprowski 		else
5356991cd74SVincent Whitchurch 			pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
5362892d8a0SGeert Uytterhoeven 			       uname, &base, (unsigned long)(size / SZ_1M));
537e8d9d1f5SMarek Szyprowski 
538e8d9d1f5SMarek Szyprowski 		len -= t_len;
5393f0c8206SMarek Szyprowski 		if (first) {
5403f0c8206SMarek Szyprowski 			fdt_reserved_mem_save_node(node, uname, base, size);
5413f0c8206SMarek Szyprowski 			first = 0;
5423f0c8206SMarek Szyprowski 		}
543e8d9d1f5SMarek Szyprowski 	}
544e8d9d1f5SMarek Szyprowski 	return 0;
545e8d9d1f5SMarek Szyprowski }
546e8d9d1f5SMarek Szyprowski 
547a300dc86SLee Jones /*
548e8d9d1f5SMarek Szyprowski  * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
549e8d9d1f5SMarek Szyprowski  * in /reserved-memory matches the values supported by the current implementation,
550e8d9d1f5SMarek Szyprowski  * also check if ranges property has been provided
551e8d9d1f5SMarek Szyprowski  */
5525b624118SXiubo Li static int __init __reserved_mem_check_root(unsigned long node)
553e8d9d1f5SMarek Szyprowski {
5549d0c4dfeSRob Herring 	const __be32 *prop;
555e8d9d1f5SMarek Szyprowski 
556e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
557e8d9d1f5SMarek Szyprowski 	if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
558e8d9d1f5SMarek Szyprowski 		return -EINVAL;
559e8d9d1f5SMarek Szyprowski 
560e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
561e8d9d1f5SMarek Szyprowski 	if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
562e8d9d1f5SMarek Szyprowski 		return -EINVAL;
563e8d9d1f5SMarek Szyprowski 
564e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "ranges", NULL);
565e8d9d1f5SMarek Szyprowski 	if (!prop)
566e8d9d1f5SMarek Szyprowski 		return -EINVAL;
567e8d9d1f5SMarek Szyprowski 	return 0;
568e8d9d1f5SMarek Szyprowski }
569e8d9d1f5SMarek Szyprowski 
570a300dc86SLee Jones /*
571fb2293fdSRob Herring  * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
572e8d9d1f5SMarek Szyprowski  */
573fb2293fdSRob Herring static int __init fdt_scan_reserved_mem(void)
574e8d9d1f5SMarek Szyprowski {
575fb2293fdSRob Herring 	int node, child;
576fb2293fdSRob Herring 	const void *fdt = initial_boot_params;
577e8d9d1f5SMarek Szyprowski 
578fb2293fdSRob Herring 	node = fdt_path_offset(fdt, "/reserved-memory");
579fb2293fdSRob Herring 	if (node < 0)
580fb2293fdSRob Herring 		return -ENODEV;
581fb2293fdSRob Herring 
582e8d9d1f5SMarek Szyprowski 	if (__reserved_mem_check_root(node) != 0) {
583e8d9d1f5SMarek Szyprowski 		pr_err("Reserved memory: unsupported node format, ignoring\n");
584fb2293fdSRob Herring 		return -EINVAL;
585e8d9d1f5SMarek Szyprowski 	}
586e8d9d1f5SMarek Szyprowski 
587fb2293fdSRob Herring 	fdt_for_each_subnode(child, fdt, node) {
588fb2293fdSRob Herring 		const char *uname;
589fb2293fdSRob Herring 		int err;
590e8d9d1f5SMarek Szyprowski 
591fb2293fdSRob Herring 		if (!of_fdt_device_is_available(fdt, child))
592fb2293fdSRob Herring 			continue;
593e8d9d1f5SMarek Szyprowski 
594fb2293fdSRob Herring 		uname = fdt_get_name(fdt, child, NULL);
595fb2293fdSRob Herring 
596fb2293fdSRob Herring 		err = __reserved_mem_reserve_reg(child, uname);
597fb2293fdSRob Herring 		if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL))
598fb2293fdSRob Herring 			fdt_reserved_mem_save_node(child, uname, 0, 0);
599fb2293fdSRob Herring 	}
600e8d9d1f5SMarek Szyprowski 	return 0;
601e8d9d1f5SMarek Szyprowski }
602e8d9d1f5SMarek Szyprowski 
603f7e7ce93SGeert Uytterhoeven /*
6042fcf9a17SGeert Uytterhoeven  * fdt_reserve_elfcorehdr() - reserves memory for elf core header
605f7e7ce93SGeert Uytterhoeven  *
606f7e7ce93SGeert Uytterhoeven  * This function reserves the memory occupied by an elf core header
607f7e7ce93SGeert Uytterhoeven  * described in the device tree. This region contains all the
608f7e7ce93SGeert Uytterhoeven  * information about primary kernel's core image and is used by a dump
609f7e7ce93SGeert Uytterhoeven  * capture kernel to access the system memory on primary kernel.
610f7e7ce93SGeert Uytterhoeven  */
6112fcf9a17SGeert Uytterhoeven static void __init fdt_reserve_elfcorehdr(void)
612f7e7ce93SGeert Uytterhoeven {
613f7e7ce93SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_CRASH_DUMP) || !elfcorehdr_size)
614f7e7ce93SGeert Uytterhoeven 		return;
615f7e7ce93SGeert Uytterhoeven 
616f7e7ce93SGeert Uytterhoeven 	if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
617f7e7ce93SGeert Uytterhoeven 		pr_warn("elfcorehdr is overlapped\n");
618f7e7ce93SGeert Uytterhoeven 		return;
619f7e7ce93SGeert Uytterhoeven 	}
620f7e7ce93SGeert Uytterhoeven 
621f7e7ce93SGeert Uytterhoeven 	memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
622f7e7ce93SGeert Uytterhoeven 
623f7e7ce93SGeert Uytterhoeven 	pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n",
624f7e7ce93SGeert Uytterhoeven 		elfcorehdr_size >> 10, elfcorehdr_addr);
625f7e7ce93SGeert Uytterhoeven }
626f7e7ce93SGeert Uytterhoeven 
627e8d9d1f5SMarek Szyprowski /**
628e8d9d1f5SMarek Szyprowski  * early_init_fdt_scan_reserved_mem() - create reserved memory regions
629e8d9d1f5SMarek Szyprowski  *
630e8d9d1f5SMarek Szyprowski  * This function grabs memory from early allocator for device exclusive use
631e8d9d1f5SMarek Szyprowski  * defined in device tree structures. It should be called by arch specific code
632e8d9d1f5SMarek Szyprowski  * once the early allocator (i.e. memblock) has been fully activated.
633e8d9d1f5SMarek Szyprowski  */
634e8d9d1f5SMarek Szyprowski void __init early_init_fdt_scan_reserved_mem(void)
635e8d9d1f5SMarek Szyprowski {
636d1552ce4SRob Herring 	int n;
637d1552ce4SRob Herring 	u64 base, size;
638d1552ce4SRob Herring 
6392040b527SJosh Cartwright 	if (!initial_boot_params)
6402040b527SJosh Cartwright 		return;
6412040b527SJosh Cartwright 
642d1552ce4SRob Herring 	/* Process header /memreserve/ fields */
643d1552ce4SRob Herring 	for (n = 0; ; n++) {
644d1552ce4SRob Herring 		fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
645d1552ce4SRob Herring 		if (!size)
646d1552ce4SRob Herring 			break;
647f8a855edSPeter Collingbourne 		memblock_reserve(base, size);
648d1552ce4SRob Herring 	}
649d1552ce4SRob Herring 
650fb2293fdSRob Herring 	fdt_scan_reserved_mem();
6512fcf9a17SGeert Uytterhoeven 	fdt_reserve_elfcorehdr();
652132507edSNikhil Gupta 	fdt_init_reserved_mem();
653e8d9d1f5SMarek Szyprowski }
654e8d9d1f5SMarek Szyprowski 
655e8d9d1f5SMarek Szyprowski /**
65624bbd929SArd Biesheuvel  * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob
65724bbd929SArd Biesheuvel  */
65824bbd929SArd Biesheuvel void __init early_init_fdt_reserve_self(void)
65924bbd929SArd Biesheuvel {
66024bbd929SArd Biesheuvel 	if (!initial_boot_params)
66124bbd929SArd Biesheuvel 		return;
66224bbd929SArd Biesheuvel 
66324bbd929SArd Biesheuvel 	/* Reserve the dtb region */
664f8a855edSPeter Collingbourne 	memblock_reserve(__pa(initial_boot_params),
665f8a855edSPeter Collingbourne 			 fdt_totalsize(initial_boot_params));
66624bbd929SArd Biesheuvel }
66724bbd929SArd Biesheuvel 
66824bbd929SArd Biesheuvel /**
66957d00ecfSStephen Neuendorffer  * of_scan_flat_dt - scan flattened tree blob and call callback on each.
67057d00ecfSStephen Neuendorffer  * @it: callback function
67157d00ecfSStephen Neuendorffer  * @data: context data pointer
67257d00ecfSStephen Neuendorffer  *
67357d00ecfSStephen Neuendorffer  * This function is used to scan the flattened device-tree, it is
67457d00ecfSStephen Neuendorffer  * used to extract the memory information at boot before we can
67557d00ecfSStephen Neuendorffer  * unflatten the tree
67657d00ecfSStephen Neuendorffer  */
67757d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node,
67857d00ecfSStephen Neuendorffer 				     const char *uname, int depth,
67957d00ecfSStephen Neuendorffer 				     void *data),
68057d00ecfSStephen Neuendorffer 			   void *data)
68157d00ecfSStephen Neuendorffer {
682e6a6928cSRob Herring 	const void *blob = initial_boot_params;
683e55b0829SFabio Estevam 	const char *pathp;
684e6a6928cSRob Herring 	int offset, rc = 0, depth = -1;
68557d00ecfSStephen Neuendorffer 
6863ec75441STobias Wolf 	if (!blob)
6873ec75441STobias Wolf 		return 0;
6883ec75441STobias Wolf 
689e6a6928cSRob Herring 	for (offset = fdt_next_node(blob, -1, &depth);
690e6a6928cSRob Herring 	     offset >= 0 && depth >= 0 && !rc;
691e6a6928cSRob Herring 	     offset = fdt_next_node(blob, offset, &depth)) {
692e6a6928cSRob Herring 
693e6a6928cSRob Herring 		pathp = fdt_get_name(blob, offset, NULL);
694e6a6928cSRob Herring 		rc = it(offset, pathp, depth, data);
695e6a6928cSRob Herring 	}
69657d00ecfSStephen Neuendorffer 	return rc;
69757d00ecfSStephen Neuendorffer }
69857d00ecfSStephen Neuendorffer 
69957d00ecfSStephen Neuendorffer /**
700ea47dd19SNicholas Piggin  * of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each.
701a300dc86SLee Jones  * @parent: parent node
702ea47dd19SNicholas Piggin  * @it: callback function
703ea47dd19SNicholas Piggin  * @data: context data pointer
704ea47dd19SNicholas Piggin  *
705ea47dd19SNicholas Piggin  * This function is used to scan sub-nodes of a node.
706ea47dd19SNicholas Piggin  */
707ea47dd19SNicholas Piggin int __init of_scan_flat_dt_subnodes(unsigned long parent,
708ea47dd19SNicholas Piggin 				    int (*it)(unsigned long node,
709ea47dd19SNicholas Piggin 					      const char *uname,
710ea47dd19SNicholas Piggin 					      void *data),
711ea47dd19SNicholas Piggin 				    void *data)
712ea47dd19SNicholas Piggin {
713ea47dd19SNicholas Piggin 	const void *blob = initial_boot_params;
714ea47dd19SNicholas Piggin 	int node;
715ea47dd19SNicholas Piggin 
716ea47dd19SNicholas Piggin 	fdt_for_each_subnode(node, blob, parent) {
717ea47dd19SNicholas Piggin 		const char *pathp;
718ea47dd19SNicholas Piggin 		int rc;
719ea47dd19SNicholas Piggin 
720ea47dd19SNicholas Piggin 		pathp = fdt_get_name(blob, node, NULL);
721ea47dd19SNicholas Piggin 		rc = it(node, pathp, data);
722ea47dd19SNicholas Piggin 		if (rc)
723ea47dd19SNicholas Piggin 			return rc;
724ea47dd19SNicholas Piggin 	}
725ea47dd19SNicholas Piggin 	return 0;
726ea47dd19SNicholas Piggin }
727ea47dd19SNicholas Piggin 
728ea47dd19SNicholas Piggin /**
7299c609868SShannon Zhao  * of_get_flat_dt_subnode_by_name - get the subnode by given name
7309c609868SShannon Zhao  *
7319c609868SShannon Zhao  * @node: the parent node
7329c609868SShannon Zhao  * @uname: the name of subnode
7339c609868SShannon Zhao  * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none
7349c609868SShannon Zhao  */
7359c609868SShannon Zhao 
7369b4d2b63SStephen Boyd int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
7379c609868SShannon Zhao {
7389c609868SShannon Zhao 	return fdt_subnode_offset(initial_boot_params, node, uname);
7399c609868SShannon Zhao }
7409c609868SShannon Zhao 
741a300dc86SLee Jones /*
74257d00ecfSStephen Neuendorffer  * of_get_flat_dt_root - find the root node in the flat blob
74357d00ecfSStephen Neuendorffer  */
74457d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void)
74557d00ecfSStephen Neuendorffer {
746e6a6928cSRob Herring 	return 0;
74757d00ecfSStephen Neuendorffer }
74857d00ecfSStephen Neuendorffer 
749a300dc86SLee Jones /*
75057d00ecfSStephen Neuendorffer  * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
75157d00ecfSStephen Neuendorffer  *
75257d00ecfSStephen Neuendorffer  * This function can be used within scan_flattened_dt callback to get
75357d00ecfSStephen Neuendorffer  * access to properties
75457d00ecfSStephen Neuendorffer  */
7559d0c4dfeSRob Herring const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
7569d0c4dfeSRob Herring 				       int *size)
75757d00ecfSStephen Neuendorffer {
758e6a6928cSRob Herring 	return fdt_getprop(initial_boot_params, node, name, size);
75957d00ecfSStephen Neuendorffer }
76057d00ecfSStephen Neuendorffer 
76157d00ecfSStephen Neuendorffer /**
7625d9c4e95SKefeng Wang  * of_fdt_is_compatible - Return true if given node from the given blob has
7635d9c4e95SKefeng Wang  * compat in its compatible list
7645d9c4e95SKefeng Wang  * @blob: A device tree blob
7655d9c4e95SKefeng Wang  * @node: node to test
7665d9c4e95SKefeng Wang  * @compat: compatible string to compare with compatible list.
7675d9c4e95SKefeng Wang  *
7688c8239c2SRob Herring  * Return: a non-zero value on match with smaller values returned for more
7695d9c4e95SKefeng Wang  * specific compatible values.
7705d9c4e95SKefeng Wang  */
7715d9c4e95SKefeng Wang static int of_fdt_is_compatible(const void *blob,
7725d9c4e95SKefeng Wang 		      unsigned long node, const char *compat)
7735d9c4e95SKefeng Wang {
7745d9c4e95SKefeng Wang 	const char *cp;
7755d9c4e95SKefeng Wang 	int cplen;
7765d9c4e95SKefeng Wang 	unsigned long l, score = 0;
7775d9c4e95SKefeng Wang 
7785d9c4e95SKefeng Wang 	cp = fdt_getprop(blob, node, "compatible", &cplen);
7795d9c4e95SKefeng Wang 	if (cp == NULL)
7805d9c4e95SKefeng Wang 		return 0;
7815d9c4e95SKefeng Wang 	while (cplen > 0) {
7825d9c4e95SKefeng Wang 		score++;
7835d9c4e95SKefeng Wang 		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
7845d9c4e95SKefeng Wang 			return score;
7855d9c4e95SKefeng Wang 		l = strlen(cp) + 1;
7865d9c4e95SKefeng Wang 		cp += l;
7875d9c4e95SKefeng Wang 		cplen -= l;
7885d9c4e95SKefeng Wang 	}
7895d9c4e95SKefeng Wang 
7905d9c4e95SKefeng Wang 	return 0;
7915d9c4e95SKefeng Wang }
7925d9c4e95SKefeng Wang 
7935d9c4e95SKefeng Wang /**
79457d00ecfSStephen Neuendorffer  * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
79557d00ecfSStephen Neuendorffer  * @node: node to test
79657d00ecfSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
79757d00ecfSStephen Neuendorffer  */
79857d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
79957d00ecfSStephen Neuendorffer {
80057d00ecfSStephen Neuendorffer 	return of_fdt_is_compatible(initial_boot_params, node, compat);
80157d00ecfSStephen Neuendorffer }
80257d00ecfSStephen Neuendorffer 
803a300dc86SLee Jones /*
804a4f740cfSGrant Likely  * of_flat_dt_match - Return true if node matches a list of compatible values
805a4f740cfSGrant Likely  */
8069b4d2b63SStephen Boyd static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
807a4f740cfSGrant Likely {
8085d9c4e95SKefeng Wang 	unsigned int tmp, score = 0;
8095d9c4e95SKefeng Wang 
8105d9c4e95SKefeng Wang 	if (!compat)
8115d9c4e95SKefeng Wang 		return 0;
8125d9c4e95SKefeng Wang 
8135d9c4e95SKefeng Wang 	while (*compat) {
8145d9c4e95SKefeng Wang 		tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
8155d9c4e95SKefeng Wang 		if (tmp && (score == 0 || (tmp < score)))
8165d9c4e95SKefeng Wang 			score = tmp;
8175d9c4e95SKefeng Wang 		compat++;
8185d9c4e95SKefeng Wang 	}
8195d9c4e95SKefeng Wang 
8205d9c4e95SKefeng Wang 	return score;
821a4f740cfSGrant Likely }
822a4f740cfSGrant Likely 
823a300dc86SLee Jones /*
824a300dc86SLee Jones  * of_get_flat_dt_phandle - Given a node in the flat blob, return the phandle
825ea47dd19SNicholas Piggin  */
826ea47dd19SNicholas Piggin uint32_t __init of_get_flat_dt_phandle(unsigned long node)
827ea47dd19SNicholas Piggin {
828ea47dd19SNicholas Piggin 	return fdt_get_phandle(initial_boot_params, node);
829ea47dd19SNicholas Piggin }
830ea47dd19SNicholas Piggin 
83157d74bcfSMarek Szyprowski struct fdt_scan_status {
83257d74bcfSMarek Szyprowski 	const char *name;
83357d74bcfSMarek Szyprowski 	int namelen;
83457d74bcfSMarek Szyprowski 	int depth;
83557d74bcfSMarek Szyprowski 	int found;
83657d74bcfSMarek Szyprowski 	int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
83757d74bcfSMarek Szyprowski 	void *data;
83857d74bcfSMarek Szyprowski };
83957d74bcfSMarek Szyprowski 
8406a903a25SRob Herring const char * __init of_flat_dt_get_machine_name(void)
8416a903a25SRob Herring {
8426a903a25SRob Herring 	const char *name;
8436a903a25SRob Herring 	unsigned long dt_root = of_get_flat_dt_root();
8446a903a25SRob Herring 
8456a903a25SRob Herring 	name = of_get_flat_dt_prop(dt_root, "model", NULL);
8466a903a25SRob Herring 	if (!name)
8476a903a25SRob Herring 		name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
8486a903a25SRob Herring 	return name;
8496a903a25SRob Herring }
8506a903a25SRob Herring 
8516a903a25SRob Herring /**
8526a903a25SRob Herring  * of_flat_dt_match_machine - Iterate match tables to find matching machine.
8536a903a25SRob Herring  *
8546a903a25SRob Herring  * @default_match: A machine specific ptr to return in case of no match.
8556a903a25SRob Herring  * @get_next_compat: callback function to return next compatible match table.
8566a903a25SRob Herring  *
8576a903a25SRob Herring  * Iterate through machine match tables to find the best match for the machine
8586a903a25SRob Herring  * compatible string in the FDT.
8596a903a25SRob Herring  */
8606a903a25SRob Herring const void * __init of_flat_dt_match_machine(const void *default_match,
8616a903a25SRob Herring 		const void * (*get_next_compat)(const char * const**))
8626a903a25SRob Herring {
8636a903a25SRob Herring 	const void *data = NULL;
8646a903a25SRob Herring 	const void *best_data = default_match;
8656a903a25SRob Herring 	const char *const *compat;
8666a903a25SRob Herring 	unsigned long dt_root;
8676a903a25SRob Herring 	unsigned int best_score = ~1, score = 0;
8686a903a25SRob Herring 
8696a903a25SRob Herring 	dt_root = of_get_flat_dt_root();
8706a903a25SRob Herring 	while ((data = get_next_compat(&compat))) {
8716a903a25SRob Herring 		score = of_flat_dt_match(dt_root, compat);
8726a903a25SRob Herring 		if (score > 0 && score < best_score) {
8736a903a25SRob Herring 			best_data = data;
8746a903a25SRob Herring 			best_score = score;
8756a903a25SRob Herring 		}
8766a903a25SRob Herring 	}
8776a903a25SRob Herring 	if (!best_data) {
8786a903a25SRob Herring 		const char *prop;
8799d0c4dfeSRob Herring 		int size;
8806a903a25SRob Herring 
8816a903a25SRob Herring 		pr_err("\n unrecognized device tree list:\n[ ");
8826a903a25SRob Herring 
8836a903a25SRob Herring 		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
8846a903a25SRob Herring 		if (prop) {
8856a903a25SRob Herring 			while (size > 0) {
8866a903a25SRob Herring 				printk("'%s' ", prop);
8876a903a25SRob Herring 				size -= strlen(prop) + 1;
8886a903a25SRob Herring 				prop += strlen(prop) + 1;
8896a903a25SRob Herring 			}
8906a903a25SRob Herring 		}
8916a903a25SRob Herring 		printk("]\n\n");
8926a903a25SRob Herring 		return NULL;
8936a903a25SRob Herring 	}
8946a903a25SRob Herring 
8956a903a25SRob Herring 	pr_info("Machine model: %s\n", of_flat_dt_get_machine_name());
8966a903a25SRob Herring 
8976a903a25SRob Herring 	return best_data;
8986a903a25SRob Herring }
8996a903a25SRob Herring 
900369bc9abSArd Biesheuvel static void __early_init_dt_declare_initrd(unsigned long start,
901369bc9abSArd Biesheuvel 					   unsigned long end)
902369bc9abSArd Biesheuvel {
903cdbc848bSFlorian Fainelli 	/* ARM64 would cause a BUG to occur here when CONFIG_DEBUG_VM is
904cdbc848bSFlorian Fainelli 	 * enabled since __va() is called too early. ARM64 does make use
905cdbc848bSFlorian Fainelli 	 * of phys_initrd_start/phys_initrd_size so we can skip this
906cdbc848bSFlorian Fainelli 	 * conversion.
907cdbc848bSFlorian Fainelli 	 */
908cdbc848bSFlorian Fainelli 	if (!IS_ENABLED(CONFIG_ARM64)) {
909369bc9abSArd Biesheuvel 		initrd_start = (unsigned long)__va(start);
910369bc9abSArd Biesheuvel 		initrd_end = (unsigned long)__va(end);
911369bc9abSArd Biesheuvel 		initrd_below_start_ok = 1;
912369bc9abSArd Biesheuvel 	}
913cdbc848bSFlorian Fainelli }
914369bc9abSArd Biesheuvel 
915f7b3a835SGrant Likely /**
916f7b3a835SGrant Likely  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
917f7b3a835SGrant Likely  * @node: reference to node containing initrd location ('chosen')
918f7b3a835SGrant Likely  */
91929eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node)
920f7b3a835SGrant Likely {
921374d5c99SSantosh Shilimkar 	u64 start, end;
9229d0c4dfeSRob Herring 	int len;
9239d0c4dfeSRob Herring 	const __be32 *prop;
924f7b3a835SGrant Likely 
925bf2e8609SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
926bf2e8609SGeert Uytterhoeven 		return;
927bf2e8609SGeert Uytterhoeven 
928f7b3a835SGrant Likely 	pr_debug("Looking for initrd properties... ");
929f7b3a835SGrant Likely 
930f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
9311406bc2fSJeremy Kerr 	if (!prop)
9321406bc2fSJeremy Kerr 		return;
933374d5c99SSantosh Shilimkar 	start = of_read_number(prop, len/4);
934f7b3a835SGrant Likely 
935f7b3a835SGrant Likely 	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
9361406bc2fSJeremy Kerr 	if (!prop)
9371406bc2fSJeremy Kerr 		return;
938374d5c99SSantosh Shilimkar 	end = of_read_number(prop, len/4);
939f7b3a835SGrant Likely 
940369bc9abSArd Biesheuvel 	__early_init_dt_declare_initrd(start, end);
941fe7db757SFlorian Fainelli 	phys_initrd_start = start;
942fe7db757SFlorian Fainelli 	phys_initrd_size = end - start;
94329eb45a9SRob Herring 
9440e407a9aSGeert Uytterhoeven 	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n", start, end);
945f7b3a835SGrant Likely }
946f7b3a835SGrant Likely 
947f7e7ce93SGeert Uytterhoeven /**
948f7e7ce93SGeert Uytterhoeven  * early_init_dt_check_for_elfcorehdr - Decode elfcorehdr location from flat
949f7e7ce93SGeert Uytterhoeven  * tree
950f7e7ce93SGeert Uytterhoeven  * @node: reference to node containing elfcorehdr location ('chosen')
951f7e7ce93SGeert Uytterhoeven  */
952f7e7ce93SGeert Uytterhoeven static void __init early_init_dt_check_for_elfcorehdr(unsigned long node)
953f7e7ce93SGeert Uytterhoeven {
954f7e7ce93SGeert Uytterhoeven 	const __be32 *prop;
955f7e7ce93SGeert Uytterhoeven 	int len;
956f7e7ce93SGeert Uytterhoeven 
957f7e7ce93SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_CRASH_DUMP))
958f7e7ce93SGeert Uytterhoeven 		return;
959f7e7ce93SGeert Uytterhoeven 
960f7e7ce93SGeert Uytterhoeven 	pr_debug("Looking for elfcorehdr property... ");
961f7e7ce93SGeert Uytterhoeven 
962f7e7ce93SGeert Uytterhoeven 	prop = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len);
963f7e7ce93SGeert Uytterhoeven 	if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells)))
964f7e7ce93SGeert Uytterhoeven 		return;
965f7e7ce93SGeert Uytterhoeven 
966f7e7ce93SGeert Uytterhoeven 	elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
967f7e7ce93SGeert Uytterhoeven 	elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &prop);
968f7e7ce93SGeert Uytterhoeven 
969f7e7ce93SGeert Uytterhoeven 	pr_debug("elfcorehdr_start=0x%llx elfcorehdr_size=0x%llx\n",
970f7e7ce93SGeert Uytterhoeven 		 elfcorehdr_addr, elfcorehdr_size);
971f7e7ce93SGeert Uytterhoeven }
972f7e7ce93SGeert Uytterhoeven 
9738347b417SZhen Lei static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
9742af2b50aSGeert Uytterhoeven 
975fb319e77SChen Zhou /*
976fb319e77SChen Zhou  * The main usage of linux,usable-memory-range is for crash dump kernel.
977fb319e77SChen Zhou  * Originally, the number of usable-memory regions is one. Now there may
978fb319e77SChen Zhou  * be two regions, low region and high region.
979fb319e77SChen Zhou  * To make compatibility with existing user-space and older kdump, the low
980fb319e77SChen Zhou  * region is always the last range of linux,usable-memory-range if exist.
981fb319e77SChen Zhou  */
982fb319e77SChen Zhou #define MAX_USABLE_RANGES		2
983fb319e77SChen Zhou 
9842af2b50aSGeert Uytterhoeven /**
9852af2b50aSGeert Uytterhoeven  * early_init_dt_check_for_usable_mem_range - Decode usable memory range
9862af2b50aSGeert Uytterhoeven  * location from flat tree
9872af2b50aSGeert Uytterhoeven  */
988b398123bSPingfan Liu void __init early_init_dt_check_for_usable_mem_range(void)
9892af2b50aSGeert Uytterhoeven {
990fb319e77SChen Zhou 	struct memblock_region rgn[MAX_USABLE_RANGES] = {0};
991fb319e77SChen Zhou 	const __be32 *prop, *endp;
992fb319e77SChen Zhou 	int len, i;
9938347b417SZhen Lei 	unsigned long node = chosen_node_offset;
9948347b417SZhen Lei 
9958347b417SZhen Lei 	if ((long)node < 0)
9968347b417SZhen Lei 		return;
9972af2b50aSGeert Uytterhoeven 
9982af2b50aSGeert Uytterhoeven 	pr_debug("Looking for usable-memory-range property... ");
9992af2b50aSGeert Uytterhoeven 
10002af2b50aSGeert Uytterhoeven 	prop = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len);
1001fb319e77SChen Zhou 	if (!prop || (len % (dt_root_addr_cells + dt_root_size_cells)))
10022af2b50aSGeert Uytterhoeven 		return;
10032af2b50aSGeert Uytterhoeven 
1004fb319e77SChen Zhou 	endp = prop + (len / sizeof(__be32));
1005fb319e77SChen Zhou 	for (i = 0; i < MAX_USABLE_RANGES && prop < endp; i++) {
1006fb319e77SChen Zhou 		rgn[i].base = dt_mem_next_cell(dt_root_addr_cells, &prop);
1007fb319e77SChen Zhou 		rgn[i].size = dt_mem_next_cell(dt_root_size_cells, &prop);
10082af2b50aSGeert Uytterhoeven 
1009fb319e77SChen Zhou 		pr_debug("cap_mem_regions[%d]: base=%pa, size=%pa\n",
1010fb319e77SChen Zhou 			 i, &rgn[i].base, &rgn[i].size);
1011fb319e77SChen Zhou 	}
10128347b417SZhen Lei 
1013fb319e77SChen Zhou 	memblock_cap_memory_range(rgn[0].base, rgn[0].size);
1014fb319e77SChen Zhou 	for (i = 1; i < MAX_USABLE_RANGES && rgn[i].size; i++)
1015fb319e77SChen Zhou 		memblock_add(rgn[i].base, rgn[i].size);
10162af2b50aSGeert Uytterhoeven }
10172af2b50aSGeert Uytterhoeven 
1018fb11ffe7SRob Herring #ifdef CONFIG_SERIAL_EARLYCON
1019fb11ffe7SRob Herring 
1020d503187bSLeif Lindholm int __init early_init_dt_scan_chosen_stdout(void)
1021fb11ffe7SRob Herring {
1022fb11ffe7SRob Herring 	int offset;
10234d118c9aSPeter Hurley 	const char *p, *q, *options = NULL;
1024fb11ffe7SRob Herring 	int l;
102562dcd9c5SJohan Hovold 	const struct earlycon_id *match;
1026fb11ffe7SRob Herring 	const void *fdt = initial_boot_params;
102765e20e8cSMichael Walle 	int ret;
1028fb11ffe7SRob Herring 
1029fb11ffe7SRob Herring 	offset = fdt_path_offset(fdt, "/chosen");
1030fb11ffe7SRob Herring 	if (offset < 0)
1031fb11ffe7SRob Herring 		offset = fdt_path_offset(fdt, "/chosen@0");
1032fb11ffe7SRob Herring 	if (offset < 0)
1033fb11ffe7SRob Herring 		return -ENOENT;
1034fb11ffe7SRob Herring 
1035fb11ffe7SRob Herring 	p = fdt_getprop(fdt, offset, "stdout-path", &l);
1036fb11ffe7SRob Herring 	if (!p)
1037fb11ffe7SRob Herring 		p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
1038fb11ffe7SRob Herring 	if (!p || !l)
1039fb11ffe7SRob Herring 		return -ENOENT;
1040fb11ffe7SRob Herring 
10414d118c9aSPeter Hurley 	q = strchrnul(p, ':');
10424d118c9aSPeter Hurley 	if (*q != '\0')
10434d118c9aSPeter Hurley 		options = q + 1;
10440fcc286fSPeter Hurley 	l = q - p;
10456296ad9eSStefan Agner 
1046fb11ffe7SRob Herring 	/* Get the node specified by stdout-path */
10470fcc286fSPeter Hurley 	offset = fdt_path_offset_namelen(fdt, p, l);
10480fcc286fSPeter Hurley 	if (offset < 0) {
10490fcc286fSPeter Hurley 		pr_warn("earlycon: stdout-path %.*s not found\n", l, p);
10500fcc286fSPeter Hurley 		return 0;
10510fcc286fSPeter Hurley 	}
1052fb11ffe7SRob Herring 
105362dcd9c5SJohan Hovold 	for (match = __earlycon_table; match < __earlycon_table_end; match++) {
10542eaa7909SPeter Hurley 		if (!match->compatible[0])
1055fb11ffe7SRob Herring 			continue;
10562eaa7909SPeter Hurley 
10572eaa7909SPeter Hurley 		if (fdt_node_check_compatible(fdt, offset, match->compatible))
10582eaa7909SPeter Hurley 			continue;
1059fb11ffe7SRob Herring 
106065e20e8cSMichael Walle 		ret = of_setup_earlycon(match, offset, options);
106165e20e8cSMichael Walle 		if (!ret || ret == -EALREADY)
1062fb11ffe7SRob Herring 			return 0;
1063fb11ffe7SRob Herring 	}
1064fb11ffe7SRob Herring 	return -ENODEV;
1065fb11ffe7SRob Herring }
1066fb11ffe7SRob Herring #endif
1067fb11ffe7SRob Herring 
1068a300dc86SLee Jones /*
1069f00abd94SGrant Likely  * early_init_dt_scan_root - fetch the top level address and size cells
1070f00abd94SGrant Likely  */
1071d665881dSRob Herring int __init early_init_dt_scan_root(void)
1072f00abd94SGrant Likely {
10739d0c4dfeSRob Herring 	const __be32 *prop;
1074d665881dSRob Herring 	const void *fdt = initial_boot_params;
1075d665881dSRob Herring 	int node = fdt_path_offset(fdt, "/");
1076f00abd94SGrant Likely 
1077d665881dSRob Herring 	if (node < 0)
1078d665881dSRob Herring 		return -ENODEV;
1079f00abd94SGrant Likely 
108033714881SJeremy Kerr 	dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
108133714881SJeremy Kerr 	dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
108233714881SJeremy Kerr 
1083f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
108433714881SJeremy Kerr 	if (prop)
108533714881SJeremy Kerr 		dt_root_size_cells = be32_to_cpup(prop);
1086f00abd94SGrant Likely 	pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
1087f00abd94SGrant Likely 
1088f00abd94SGrant Likely 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
108933714881SJeremy Kerr 	if (prop)
109033714881SJeremy Kerr 		dt_root_addr_cells = be32_to_cpup(prop);
1091f00abd94SGrant Likely 	pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
1092f00abd94SGrant Likely 
1093d665881dSRob Herring 	return 0;
1094f00abd94SGrant Likely }
1095f00abd94SGrant Likely 
10969d0c4dfeSRob Herring u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
109783f7a06eSGrant Likely {
10989d0c4dfeSRob Herring 	const __be32 *p = *cellp;
109983f7a06eSGrant Likely 
110083f7a06eSGrant Likely 	*cellp = p + s;
110183f7a06eSGrant Likely 	return of_read_number(p, s);
110283f7a06eSGrant Likely }
110383f7a06eSGrant Likely 
1104a300dc86SLee Jones /*
11050ef5adcaSFrank Rowand  * early_init_dt_scan_memory - Look for and parse memory nodes
110651975db0SGrant Likely  */
11071f012283SRob Herring int __init early_init_dt_scan_memory(void)
110851975db0SGrant Likely {
11091f012283SRob Herring 	int node;
11101f012283SRob Herring 	const void *fdt = initial_boot_params;
11111f012283SRob Herring 
11121f012283SRob Herring 	fdt_for_each_subnode(node, fdt, 0) {
11139d0c4dfeSRob Herring 		const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
11149d0c4dfeSRob Herring 		const __be32 *reg, *endp;
11159d0c4dfeSRob Herring 		int l;
111641a9ada3SReza Arbab 		bool hotpluggable;
111751975db0SGrant Likely 
111851975db0SGrant Likely 		/* We are scanning "memory" nodes only */
1119da653130SMichael Ellerman 		if (type == NULL || strcmp(type, "memory") != 0)
11201f012283SRob Herring 			continue;
112151975db0SGrant Likely 
1122df5cd369SAndre Przywara 		if (!of_fdt_device_is_available(fdt, node))
1123df5cd369SAndre Przywara 			continue;
1124df5cd369SAndre Przywara 
112551975db0SGrant Likely 		reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
112651975db0SGrant Likely 		if (reg == NULL)
112751975db0SGrant Likely 			reg = of_get_flat_dt_prop(node, "reg", &l);
112851975db0SGrant Likely 		if (reg == NULL)
11291f012283SRob Herring 			continue;
113051975db0SGrant Likely 
113151975db0SGrant Likely 		endp = reg + (l / sizeof(__be32));
113241a9ada3SReza Arbab 		hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL);
113351975db0SGrant Likely 
11341f012283SRob Herring 		pr_debug("memory scan node %s, reg size %d,\n",
11351f012283SRob Herring 			 fdt_get_name(fdt, node, NULL), l);
113651975db0SGrant Likely 
113751975db0SGrant Likely 		while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
113851975db0SGrant Likely 			u64 base, size;
113951975db0SGrant Likely 
114051975db0SGrant Likely 			base = dt_mem_next_cell(dt_root_addr_cells, &reg);
114151975db0SGrant Likely 			size = dt_mem_next_cell(dt_root_size_cells, &reg);
114251975db0SGrant Likely 
114351975db0SGrant Likely 			if (size == 0)
114451975db0SGrant Likely 				continue;
11450e407a9aSGeert Uytterhoeven 			pr_debug(" - %llx, %llx\n", base, size);
114651975db0SGrant Likely 
114751975db0SGrant Likely 			early_init_dt_add_memory_arch(base, size);
114841a9ada3SReza Arbab 
114941a9ada3SReza Arbab 			if (!hotpluggable)
115041a9ada3SReza Arbab 				continue;
115141a9ada3SReza Arbab 
115239c6b3a3SGeert Uytterhoeven 			if (memblock_mark_hotplug(base, size))
115341a9ada3SReza Arbab 				pr_warn("failed to mark hotplug range 0x%llx - 0x%llx\n",
115441a9ada3SReza Arbab 					base, base + size);
115551975db0SGrant Likely 		}
11561f012283SRob Herring 	}
115751975db0SGrant Likely 	return 0;
115851975db0SGrant Likely }
115951975db0SGrant Likely 
116060f20d84SRob Herring int __init early_init_dt_scan_chosen(char *cmdline)
116186e03221SGrant Likely {
116260f20d84SRob Herring 	int l, node;
11639d0c4dfeSRob Herring 	const char *p;
1164428826f5SHsin-Yi Wang 	const void *rng_seed;
116560f20d84SRob Herring 	const void *fdt = initial_boot_params;
116686e03221SGrant Likely 
116760f20d84SRob Herring 	node = fdt_path_offset(fdt, "/chosen");
116860f20d84SRob Herring 	if (node < 0)
116960f20d84SRob Herring 		node = fdt_path_offset(fdt, "/chosen@0");
117060f20d84SRob Herring 	if (node < 0)
117160f20d84SRob Herring 		return -ENOENT;
117286e03221SGrant Likely 
11738347b417SZhen Lei 	chosen_node_offset = node;
11748347b417SZhen Lei 
117586e03221SGrant Likely 	early_init_dt_check_for_initrd(node);
1176f7e7ce93SGeert Uytterhoeven 	early_init_dt_check_for_elfcorehdr(node);
117786e03221SGrant Likely 
117825985edcSLucas De Marchi 	/* Retrieve command line */
117986e03221SGrant Likely 	p = of_get_flat_dt_prop(node, "bootargs", &l);
118086e03221SGrant Likely 	if (p != NULL && l > 0)
118160f20d84SRob Herring 		strlcpy(cmdline, p, min(l, COMMAND_LINE_SIZE));
118286e03221SGrant Likely 
118378b782cbSBenjamin Herrenschmidt 	/*
118478b782cbSBenjamin Herrenschmidt 	 * CONFIG_CMDLINE is meant to be a default in case nothing else
118578b782cbSBenjamin Herrenschmidt 	 * managed to set the command line, unless CONFIG_CMDLINE_FORCE
118678b782cbSBenjamin Herrenschmidt 	 * is set in which case we override whatever was found earlier.
118778b782cbSBenjamin Herrenschmidt 	 */
118886e03221SGrant Likely #ifdef CONFIG_CMDLINE
118934b82026SMax Uvarov #if defined(CONFIG_CMDLINE_EXTEND)
119060f20d84SRob Herring 	strlcat(cmdline, " ", COMMAND_LINE_SIZE);
119160f20d84SRob Herring 	strlcat(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
119234b82026SMax Uvarov #elif defined(CONFIG_CMDLINE_FORCE)
119360f20d84SRob Herring 	strlcpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
119434b82026SMax Uvarov #else
119534b82026SMax Uvarov 	/* No arguments from boot loader, use kernel's  cmdl*/
119660f20d84SRob Herring 	if (!((char *)cmdline)[0])
119760f20d84SRob Herring 		strlcpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
119834b82026SMax Uvarov #endif
119986e03221SGrant Likely #endif /* CONFIG_CMDLINE */
120086e03221SGrant Likely 
120160f20d84SRob Herring 	pr_debug("Command line is: %s\n", (char *)cmdline);
120286e03221SGrant Likely 
1203428826f5SHsin-Yi Wang 	rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
1204428826f5SHsin-Yi Wang 	if (rng_seed && l > 0) {
1205428826f5SHsin-Yi Wang 		add_bootloader_randomness(rng_seed, l);
1206428826f5SHsin-Yi Wang 
1207428826f5SHsin-Yi Wang 		/* try to clear seed so it won't be found. */
1208428826f5SHsin-Yi Wang 		fdt_nop_property(initial_boot_params, node, "rng-seed");
1209dd753d96SHsin-Yi Wang 
1210dd753d96SHsin-Yi Wang 		/* update CRC check value */
1211dd753d96SHsin-Yi Wang 		of_fdt_crc32 = crc32_be(~0, initial_boot_params,
1212dd753d96SHsin-Yi Wang 				fdt_totalsize(initial_boot_params));
1213428826f5SHsin-Yi Wang 	}
1214428826f5SHsin-Yi Wang 
121560f20d84SRob Herring 	return 0;
121686e03221SGrant Likely }
121786e03221SGrant Likely 
1218270522a0SArd Biesheuvel #ifndef MIN_MEMBLOCK_ADDR
1219270522a0SArd Biesheuvel #define MIN_MEMBLOCK_ADDR	__pa(PAGE_OFFSET)
1220270522a0SArd Biesheuvel #endif
12218eafeb48SArd Biesheuvel #ifndef MAX_MEMBLOCK_ADDR
12228eafeb48SArd Biesheuvel #define MAX_MEMBLOCK_ADDR	((phys_addr_t)~0)
12238eafeb48SArd Biesheuvel #endif
12243069f0c0SLaura Abbott 
1225068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
1226068f6310SRob Herring {
1227270522a0SArd Biesheuvel 	const u64 phys_offset = MIN_MEMBLOCK_ADDR;
12288f73d4b7SGeert Uytterhoeven 
12298cccffc5SArd Biesheuvel 	if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
12308cccffc5SArd Biesheuvel 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
12318cccffc5SArd Biesheuvel 			base, base + size);
12328cccffc5SArd Biesheuvel 		return;
12338cccffc5SArd Biesheuvel 	}
12346072cf56SMike Rapoport 
12356072cf56SMike Rapoport 	if (!PAGE_ALIGNED(base)) {
12368f73d4b7SGeert Uytterhoeven 		size -= PAGE_SIZE - (base & ~PAGE_MASK);
12378f73d4b7SGeert Uytterhoeven 		base = PAGE_ALIGN(base);
12388f73d4b7SGeert Uytterhoeven 	}
1239068f6310SRob Herring 	size &= PAGE_MASK;
1240a67a6ed1SLaura Abbott 
12418eafeb48SArd Biesheuvel 	if (base > MAX_MEMBLOCK_ADDR) {
1242e2f04da7SKefeng Wang 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
1243a67a6ed1SLaura Abbott 			base, base + size);
1244a67a6ed1SLaura Abbott 		return;
1245a67a6ed1SLaura Abbott 	}
1246a67a6ed1SLaura Abbott 
12478eafeb48SArd Biesheuvel 	if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
1248e2f04da7SKefeng Wang 		pr_warn("Ignoring memory range 0x%llx - 0x%llx\n",
12498eafeb48SArd Biesheuvel 			((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
12508eafeb48SArd Biesheuvel 		size = MAX_MEMBLOCK_ADDR - base + 1;
1251a67a6ed1SLaura Abbott 	}
1252a67a6ed1SLaura Abbott 
1253068f6310SRob Herring 	if (base + size < phys_offset) {
1254e2f04da7SKefeng Wang 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
1255068f6310SRob Herring 			base, base + size);
1256068f6310SRob Herring 		return;
1257068f6310SRob Herring 	}
1258068f6310SRob Herring 	if (base < phys_offset) {
1259e2f04da7SKefeng Wang 		pr_warn("Ignoring memory range 0x%llx - 0x%llx\n",
1260068f6310SRob Herring 			base, phys_offset);
1261068f6310SRob Herring 		size -= phys_offset - base;
1262068f6310SRob Herring 		base = phys_offset;
1263068f6310SRob Herring 	}
1264068f6310SRob Herring 	memblock_add(base, size);
1265068f6310SRob Herring }
1266068f6310SRob Herring 
12670fa1c579SRob Herring static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
12680fa1c579SRob Herring {
12698a7f97b9SMike Rapoport 	void *ptr = memblock_alloc(size, align);
12708a7f97b9SMike Rapoport 
12718a7f97b9SMike Rapoport 	if (!ptr)
12728a7f97b9SMike Rapoport 		panic("%s: Failed to allocate %llu bytes align=0x%llx\n",
12738a7f97b9SMike Rapoport 		      __func__, size, align);
12748a7f97b9SMike Rapoport 
12758a7f97b9SMike Rapoport 	return ptr;
12760fa1c579SRob Herring }
12770fa1c579SRob Herring 
12784972a74bSLaura Abbott bool __init early_init_dt_verify(void *params)
12790288ffcbSRob Herring {
12800288ffcbSRob Herring 	if (!params)
12810288ffcbSRob Herring 		return false;
12820288ffcbSRob Herring 
128350ba08f3SBjorn Helgaas 	/* check device tree validity */
128450ba08f3SBjorn Helgaas 	if (fdt_check_header(params))
128550ba08f3SBjorn Helgaas 		return false;
128650ba08f3SBjorn Helgaas 
12870288ffcbSRob Herring 	/* Setup flat device-tree pointer */
12880288ffcbSRob Herring 	initial_boot_params = params;
1289dd753d96SHsin-Yi Wang 	of_fdt_crc32 = crc32_be(~0, initial_boot_params,
1290dd753d96SHsin-Yi Wang 				fdt_totalsize(initial_boot_params));
12914972a74bSLaura Abbott 	return true;
12924972a74bSLaura Abbott }
12934972a74bSLaura Abbott 
12944972a74bSLaura Abbott 
12954972a74bSLaura Abbott void __init early_init_dt_scan_nodes(void)
12964972a74bSLaura Abbott {
129760f20d84SRob Herring 	int rc;
1298e1e52544SNick Kossifidis 
1299f7e7ce93SGeert Uytterhoeven 	/* Initialize {size,address}-cells info */
1300d665881dSRob Herring 	early_init_dt_scan_root();
1301f7e7ce93SGeert Uytterhoeven 
13020288ffcbSRob Herring 	/* Retrieve various information from the /chosen node */
130360f20d84SRob Herring 	rc = early_init_dt_scan_chosen(boot_command_line);
130460f20d84SRob Herring 	if (rc)
1305e1e52544SNick Kossifidis 		pr_warn("No chosen node found, continuing without\n");
13060288ffcbSRob Herring 
13070288ffcbSRob Herring 	/* Setup memory, calling early_init_dt_add_memory_arch */
13081f012283SRob Herring 	early_init_dt_scan_memory();
13092af2b50aSGeert Uytterhoeven 
13102af2b50aSGeert Uytterhoeven 	/* Handle linux,usable-memory-range property */
13118347b417SZhen Lei 	early_init_dt_check_for_usable_mem_range();
13124972a74bSLaura Abbott }
13130288ffcbSRob Herring 
13144972a74bSLaura Abbott bool __init early_init_dt_scan(void *params)
13154972a74bSLaura Abbott {
13164972a74bSLaura Abbott 	bool status;
13174972a74bSLaura Abbott 
13184972a74bSLaura Abbott 	status = early_init_dt_verify(params);
13194972a74bSLaura Abbott 	if (!status)
13204972a74bSLaura Abbott 		return false;
13214972a74bSLaura Abbott 
13224972a74bSLaura Abbott 	early_init_dt_scan_nodes();
13230288ffcbSRob Herring 	return true;
13240288ffcbSRob Herring }
13250288ffcbSRob Herring 
1326f00abd94SGrant Likely /**
132741f88009SGrant Likely  * unflatten_device_tree - create tree of device_nodes from flat blob
132841f88009SGrant Likely  *
132941f88009SGrant Likely  * unflattens the device-tree passed by the firmware, creating the
133041f88009SGrant Likely  * tree of struct device_node. It also fills the "name" and "type"
133141f88009SGrant Likely  * pointers of the nodes so the normal device-tree walking functions
133241f88009SGrant Likely  * can be used.
133341f88009SGrant Likely  */
133441f88009SGrant Likely void __init unflatten_device_tree(void)
133541f88009SGrant Likely {
1336c4263233SGavin Shan 	__unflatten_device_tree(initial_boot_params, NULL, &of_root,
13371d1bde55SMichal Suchanek 				early_init_dt_alloc_memory_arch, false);
133841f88009SGrant Likely 
13394c7d6361SRobert P. J. Day 	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
1340611cad72SShawn Guo 	of_alias_scan(early_init_dt_alloc_memory_arch);
134181d0848fSFrank Rowand 
134281d0848fSFrank Rowand 	unittest_unflatten_overlay_base();
134341f88009SGrant Likely }
1344e6ce1324SStephen Neuendorffer 
1345a8bf7527SRob Herring /**
1346a8bf7527SRob Herring  * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob
1347a8bf7527SRob Herring  *
1348a8bf7527SRob Herring  * Copies and unflattens the device-tree passed by the firmware, creating the
1349a8bf7527SRob Herring  * tree of struct device_node. It also fills the "name" and "type"
1350a8bf7527SRob Herring  * pointers of the nodes so the normal device-tree walking functions
1351a8bf7527SRob Herring  * can be used. This should only be used when the FDT memory has not been
1352a8bf7527SRob Herring  * reserved such is the case when the FDT is built-in to the kernel init
1353a8bf7527SRob Herring  * section. If the FDT memory is reserved already then unflatten_device_tree
1354a8bf7527SRob Herring  * should be used instead.
1355a8bf7527SRob Herring  */
1356a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void)
1357a8bf7527SRob Herring {
13586f041e99SJames Hogan 	int size;
13596f041e99SJames Hogan 	void *dt;
13606f041e99SJames Hogan 
13616f041e99SJames Hogan 	if (!initial_boot_params) {
13626f041e99SJames Hogan 		pr_warn("No valid device tree found, continuing without\n");
13636f041e99SJames Hogan 		return;
13646f041e99SJames Hogan 	}
13656f041e99SJames Hogan 
1366c972de14SRob Herring 	size = fdt_totalsize(initial_boot_params);
13676f041e99SJames Hogan 	dt = early_init_dt_alloc_memory_arch(size,
1368c972de14SRob Herring 					     roundup_pow_of_two(FDT_V17_SIZE));
1369a8bf7527SRob Herring 
1370a8bf7527SRob Herring 	if (dt) {
1371a8bf7527SRob Herring 		memcpy(dt, initial_boot_params, size);
1372a8bf7527SRob Herring 		initial_boot_params = dt;
1373a8bf7527SRob Herring 	}
1374a8bf7527SRob Herring 	unflatten_device_tree();
1375a8bf7527SRob Herring }
1376a8bf7527SRob Herring 
137708d53aa5SArd Biesheuvel #ifdef CONFIG_SYSFS
137808d53aa5SArd Biesheuvel static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj,
137908d53aa5SArd Biesheuvel 			       struct bin_attribute *bin_attr,
138008d53aa5SArd Biesheuvel 			       char *buf, loff_t off, size_t count)
1381b0a6fb36SRob Herring {
138208d53aa5SArd Biesheuvel 	memcpy(buf, initial_boot_params + off, count);
138308d53aa5SArd Biesheuvel 	return count;
138408d53aa5SArd Biesheuvel }
1385b0a6fb36SRob Herring 
138608d53aa5SArd Biesheuvel static int __init of_fdt_raw_init(void)
138708d53aa5SArd Biesheuvel {
138808d53aa5SArd Biesheuvel 	static struct bin_attribute of_fdt_raw_attr =
138908d53aa5SArd Biesheuvel 		__BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0);
1390b0a6fb36SRob Herring 
139108d53aa5SArd Biesheuvel 	if (!initial_boot_params)
139208d53aa5SArd Biesheuvel 		return 0;
1393b0a6fb36SRob Herring 
139408d53aa5SArd Biesheuvel 	if (of_fdt_crc32 != crc32_be(~0, initial_boot_params,
139508d53aa5SArd Biesheuvel 				     fdt_totalsize(initial_boot_params))) {
1396606ad42aSRob Herring 		pr_warn("not creating '/sys/firmware/fdt': CRC check failed\n");
1397b0a6fb36SRob Herring 		return 0;
1398b0a6fb36SRob Herring 	}
139908d53aa5SArd Biesheuvel 	of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params);
140008d53aa5SArd Biesheuvel 	return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr);
140108d53aa5SArd Biesheuvel }
140208d53aa5SArd Biesheuvel late_initcall(of_fdt_raw_init);
1403b0a6fb36SRob Herring #endif
1404b0a6fb36SRob Herring 
1405e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */
1406