xref: /openbmc/linux/drivers/of/fdt.c (revision b4132818)
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>
2951975db0SGrant Likely 
30c89810acSFabio Estevam #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
314ef7b373SJeremy Kerr #include <asm/page.h>
324ef7b373SJeremy Kerr 
3381d0848fSFrank Rowand #include "of_private.h"
3481d0848fSFrank Rowand 
35704033ceSLaura Abbott /*
36704033ceSLaura Abbott  * of_fdt_limit_memory - limit the number of regions in the /memory node
37704033ceSLaura Abbott  * @limit: maximum entries
38704033ceSLaura Abbott  *
39704033ceSLaura Abbott  * Adjust the flattened device tree to have at most 'limit' number of
40704033ceSLaura Abbott  * memory entries in the /memory node. This function may be called
41704033ceSLaura Abbott  * any time after initial_boot_param is set.
42704033ceSLaura Abbott  */
of_fdt_limit_memory(int limit)439b4d2b63SStephen Boyd void __init of_fdt_limit_memory(int limit)
44704033ceSLaura Abbott {
45704033ceSLaura Abbott 	int memory;
46704033ceSLaura Abbott 	int len;
47704033ceSLaura Abbott 	const void *val;
48704033ceSLaura Abbott 	int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
49704033ceSLaura Abbott 	int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
5017a70355SRob Herring 	const __be32 *addr_prop;
5117a70355SRob Herring 	const __be32 *size_prop;
52704033ceSLaura Abbott 	int root_offset;
53704033ceSLaura Abbott 	int cell_size;
54704033ceSLaura Abbott 
55704033ceSLaura Abbott 	root_offset = fdt_path_offset(initial_boot_params, "/");
56704033ceSLaura Abbott 	if (root_offset < 0)
57704033ceSLaura Abbott 		return;
58704033ceSLaura Abbott 
59704033ceSLaura Abbott 	addr_prop = fdt_getprop(initial_boot_params, root_offset,
60704033ceSLaura Abbott 				"#address-cells", NULL);
61704033ceSLaura Abbott 	if (addr_prop)
62704033ceSLaura Abbott 		nr_address_cells = fdt32_to_cpu(*addr_prop);
63704033ceSLaura Abbott 
64704033ceSLaura Abbott 	size_prop = fdt_getprop(initial_boot_params, root_offset,
65704033ceSLaura Abbott 				"#size-cells", NULL);
66704033ceSLaura Abbott 	if (size_prop)
67704033ceSLaura Abbott 		nr_size_cells = fdt32_to_cpu(*size_prop);
68704033ceSLaura Abbott 
69704033ceSLaura Abbott 	cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells);
70704033ceSLaura Abbott 
71704033ceSLaura Abbott 	memory = fdt_path_offset(initial_boot_params, "/memory");
72704033ceSLaura Abbott 	if (memory > 0) {
73704033ceSLaura Abbott 		val = fdt_getprop(initial_boot_params, memory, "reg", &len);
74704033ceSLaura Abbott 		if (len > limit*cell_size) {
75704033ceSLaura Abbott 			len = limit*cell_size;
76704033ceSLaura Abbott 			pr_debug("Limiting number of entries to %d\n", limit);
77704033ceSLaura Abbott 			fdt_setprop(initial_boot_params, memory, "reg", val,
78704033ceSLaura Abbott 					len);
79704033ceSLaura Abbott 		}
80704033ceSLaura Abbott 	}
81704033ceSLaura Abbott }
82704033ceSLaura Abbott 
of_fdt_device_is_available(const void * blob,unsigned long node)83ecc8a96eSRob Herring static bool of_fdt_device_is_available(const void *blob, unsigned long node)
84ecc8a96eSRob Herring {
85ecc8a96eSRob Herring 	const char *status = fdt_getprop(blob, node, "status", NULL);
86ecc8a96eSRob Herring 
87ecc8a96eSRob Herring 	if (!status)
88ecc8a96eSRob Herring 		return true;
89ecc8a96eSRob Herring 
90ecc8a96eSRob Herring 	if (!strcmp(status, "ok") || !strcmp(status, "okay"))
91ecc8a96eSRob Herring 		return true;
92ecc8a96eSRob Herring 
93ecc8a96eSRob Herring 	return false;
94ecc8a96eSRob Herring }
95ecc8a96eSRob Herring 
unflatten_dt_alloc(void ** mem,unsigned long size,unsigned long align)9644856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size,
97bbd33931SGrant Likely 				       unsigned long align)
98bbd33931SGrant Likely {
99bbd33931SGrant Likely 	void *res;
100bbd33931SGrant Likely 
10144856819SGrant Likely 	*mem = PTR_ALIGN(*mem, align);
10244856819SGrant Likely 	res = *mem;
103bbd33931SGrant Likely 	*mem += size;
104bbd33931SGrant Likely 
105bbd33931SGrant Likely 	return res;
106bbd33931SGrant Likely }
107bbd33931SGrant Likely 
populate_properties(const void * blob,int offset,void ** mem,struct device_node * np,const char * nodename,bool dryrun)108dfbd4c6eSGavin Shan static void populate_properties(const void *blob,
109dfbd4c6eSGavin Shan 				int offset,
110dfbd4c6eSGavin Shan 				void **mem,
111dfbd4c6eSGavin Shan 				struct device_node *np,
112dfbd4c6eSGavin Shan 				const char *nodename,
1135063e25aSGrant Likely 				bool dryrun)
114bbd33931SGrant Likely {
115dfbd4c6eSGavin Shan 	struct property *pp, **pprev = NULL;
116dfbd4c6eSGavin Shan 	int cur;
117dfbd4c6eSGavin Shan 	bool has_name = false;
118dfbd4c6eSGavin Shan 
119dfbd4c6eSGavin Shan 	pprev = &np->properties;
120dfbd4c6eSGavin Shan 	for (cur = fdt_first_property_offset(blob, offset);
121dfbd4c6eSGavin Shan 	     cur >= 0;
122dfbd4c6eSGavin Shan 	     cur = fdt_next_property_offset(blob, cur)) {
123dfbd4c6eSGavin Shan 		const __be32 *val;
124dfbd4c6eSGavin Shan 		const char *pname;
125dfbd4c6eSGavin Shan 		u32 sz;
126dfbd4c6eSGavin Shan 
127dfbd4c6eSGavin Shan 		val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
128dfbd4c6eSGavin Shan 		if (!val) {
129606ad42aSRob Herring 			pr_warn("Cannot locate property at 0x%x\n", cur);
130dfbd4c6eSGavin Shan 			continue;
131dfbd4c6eSGavin Shan 		}
132dfbd4c6eSGavin Shan 
133dfbd4c6eSGavin Shan 		if (!pname) {
134606ad42aSRob Herring 			pr_warn("Cannot find property name at 0x%x\n", cur);
135dfbd4c6eSGavin Shan 			continue;
136dfbd4c6eSGavin Shan 		}
137dfbd4c6eSGavin Shan 
138dfbd4c6eSGavin Shan 		if (!strcmp(pname, "name"))
139dfbd4c6eSGavin Shan 			has_name = true;
140dfbd4c6eSGavin Shan 
141dfbd4c6eSGavin Shan 		pp = unflatten_dt_alloc(mem, sizeof(struct property),
142dfbd4c6eSGavin Shan 					__alignof__(struct property));
143dfbd4c6eSGavin Shan 		if (dryrun)
144dfbd4c6eSGavin Shan 			continue;
145dfbd4c6eSGavin Shan 
146dfbd4c6eSGavin Shan 		/* We accept flattened tree phandles either in
147dfbd4c6eSGavin Shan 		 * ePAPR-style "phandle" properties, or the
148dfbd4c6eSGavin Shan 		 * legacy "linux,phandle" properties.  If both
149dfbd4c6eSGavin Shan 		 * appear and have different values, things
150dfbd4c6eSGavin Shan 		 * will get weird. Don't do that.
151dfbd4c6eSGavin Shan 		 */
152dfbd4c6eSGavin Shan 		if (!strcmp(pname, "phandle") ||
153dfbd4c6eSGavin Shan 		    !strcmp(pname, "linux,phandle")) {
154dfbd4c6eSGavin Shan 			if (!np->phandle)
155dfbd4c6eSGavin Shan 				np->phandle = be32_to_cpup(val);
156dfbd4c6eSGavin Shan 		}
157dfbd4c6eSGavin Shan 
158dfbd4c6eSGavin Shan 		/* And we process the "ibm,phandle" property
159dfbd4c6eSGavin Shan 		 * used in pSeries dynamic device tree
160dfbd4c6eSGavin Shan 		 * stuff
161dfbd4c6eSGavin Shan 		 */
162dfbd4c6eSGavin Shan 		if (!strcmp(pname, "ibm,phandle"))
163dfbd4c6eSGavin Shan 			np->phandle = be32_to_cpup(val);
164dfbd4c6eSGavin Shan 
165dfbd4c6eSGavin Shan 		pp->name   = (char *)pname;
166dfbd4c6eSGavin Shan 		pp->length = sz;
167dfbd4c6eSGavin Shan 		pp->value  = (__be32 *)val;
168dfbd4c6eSGavin Shan 		*pprev     = pp;
169dfbd4c6eSGavin Shan 		pprev      = &pp->next;
170dfbd4c6eSGavin Shan 	}
171dfbd4c6eSGavin Shan 
172dfbd4c6eSGavin Shan 	/* With version 0x10 we may not have the name property,
173dfbd4c6eSGavin Shan 	 * recreate it here from the unit name if absent
174dfbd4c6eSGavin Shan 	 */
175dfbd4c6eSGavin Shan 	if (!has_name) {
176dfbd4c6eSGavin Shan 		const char *p = nodename, *ps = p, *pa = NULL;
177dfbd4c6eSGavin Shan 		int len;
178dfbd4c6eSGavin Shan 
179dfbd4c6eSGavin Shan 		while (*p) {
180dfbd4c6eSGavin Shan 			if ((*p) == '@')
181dfbd4c6eSGavin Shan 				pa = p;
182dfbd4c6eSGavin Shan 			else if ((*p) == '/')
183dfbd4c6eSGavin Shan 				ps = p + 1;
184dfbd4c6eSGavin Shan 			p++;
185dfbd4c6eSGavin Shan 		}
186dfbd4c6eSGavin Shan 
187dfbd4c6eSGavin Shan 		if (pa < ps)
188dfbd4c6eSGavin Shan 			pa = p;
189dfbd4c6eSGavin Shan 		len = (pa - ps) + 1;
190dfbd4c6eSGavin Shan 		pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
191dfbd4c6eSGavin Shan 					__alignof__(struct property));
192dfbd4c6eSGavin Shan 		if (!dryrun) {
193dfbd4c6eSGavin Shan 			pp->name   = "name";
194dfbd4c6eSGavin Shan 			pp->length = len;
195dfbd4c6eSGavin Shan 			pp->value  = pp + 1;
196dfbd4c6eSGavin Shan 			*pprev     = pp;
197dfbd4c6eSGavin Shan 			memcpy(pp->value, ps, len - 1);
198dfbd4c6eSGavin Shan 			((char *)pp->value)[len - 1] = 0;
199dfbd4c6eSGavin Shan 			pr_debug("fixed up name for %s -> %s\n",
200dfbd4c6eSGavin Shan 				 nodename, (char *)pp->value);
201dfbd4c6eSGavin Shan 		}
202dfbd4c6eSGavin Shan 	}
203dfbd4c6eSGavin Shan }
204dfbd4c6eSGavin Shan 
populate_node(const void * blob,int offset,void ** mem,struct device_node * dad,struct device_node ** pnp,bool dryrun)205649cab56SFrank Rowand static int populate_node(const void *blob,
206dfbd4c6eSGavin Shan 			  int offset,
207dfbd4c6eSGavin Shan 			  void **mem,
208dfbd4c6eSGavin Shan 			  struct device_node *dad,
209dfbd4c6eSGavin Shan 			  struct device_node **pnp,
210dfbd4c6eSGavin Shan 			  bool dryrun)
211dfbd4c6eSGavin Shan {
212bbd33931SGrant Likely 	struct device_node *np;
213e6a6928cSRob Herring 	const char *pathp;
214649cab56SFrank Rowand 	int len;
215bbd33931SGrant Likely 
216649cab56SFrank Rowand 	pathp = fdt_get_name(blob, offset, &len);
217dfbd4c6eSGavin Shan 	if (!pathp) {
218dfbd4c6eSGavin Shan 		*pnp = NULL;
219649cab56SFrank Rowand 		return len;
220dfbd4c6eSGavin Shan 	}
221e6a6928cSRob Herring 
222649cab56SFrank Rowand 	len++;
223bbd33931SGrant Likely 
224649cab56SFrank Rowand 	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + len,
225bbd33931SGrant Likely 				__alignof__(struct device_node));
2265063e25aSGrant Likely 	if (!dryrun) {
227c22618a1SGrant Likely 		char *fn;
2280829f6d1SPantelis Antoniou 		of_node_init(np);
229c22618a1SGrant Likely 		np->full_name = fn = ((char *)np) + sizeof(*np);
230a7e4cfb0SRob Herring 
231649cab56SFrank Rowand 		memcpy(fn, pathp, len);
232c22618a1SGrant Likely 
233bbd33931SGrant Likely 		if (dad != NULL) {
234bbd33931SGrant Likely 			np->parent = dad;
23570161ff3SGrant Likely 			np->sibling = dad->child;
236bbd33931SGrant Likely 			dad->child = np;
237bbd33931SGrant Likely 		}
238bbd33931SGrant Likely 	}
239bbd33931SGrant Likely 
240dfbd4c6eSGavin Shan 	populate_properties(blob, offset, mem, np, pathp, dryrun);
2415063e25aSGrant Likely 	if (!dryrun) {
242bbd33931SGrant Likely 		np->name = of_get_property(np, "name", NULL);
243bbd33931SGrant Likely 		if (!np->name)
244bbd33931SGrant Likely 			np->name = "<NULL>";
245bbd33931SGrant Likely 	}
246e6a6928cSRob Herring 
247dfbd4c6eSGavin Shan 	*pnp = np;
2487913145aSXu Qiang 	return 0;
249dfbd4c6eSGavin Shan }
250dfbd4c6eSGavin Shan 
reverse_nodes(struct device_node * parent)25150800082SGavin Shan static void reverse_nodes(struct device_node *parent)
25250800082SGavin Shan {
25350800082SGavin Shan 	struct device_node *child, *next;
25450800082SGavin Shan 
25550800082SGavin Shan 	/* In-depth first */
25650800082SGavin Shan 	child = parent->child;
25750800082SGavin Shan 	while (child) {
25850800082SGavin Shan 		reverse_nodes(child);
25950800082SGavin Shan 
26050800082SGavin Shan 		child = child->sibling;
26150800082SGavin Shan 	}
26250800082SGavin Shan 
26350800082SGavin Shan 	/* Reverse the nodes in the child list */
26450800082SGavin Shan 	child = parent->child;
26550800082SGavin Shan 	parent->child = NULL;
26650800082SGavin Shan 	while (child) {
26750800082SGavin Shan 		next = child->sibling;
26850800082SGavin Shan 
26950800082SGavin Shan 		child->sibling = parent->child;
27050800082SGavin Shan 		parent->child = child;
27150800082SGavin Shan 		child = next;
27250800082SGavin Shan 	}
27350800082SGavin Shan }
27450800082SGavin Shan 
275dfbd4c6eSGavin Shan /**
276947c82cbSGavin Shan  * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree
277dfbd4c6eSGavin Shan  * @blob: The parent device tree blob
278dfbd4c6eSGavin Shan  * @mem: Memory chunk to use for allocating device nodes and properties
279dfbd4c6eSGavin Shan  * @dad: Parent struct device_node
280dfbd4c6eSGavin Shan  * @nodepp: The device_node tree created by the call
28150800082SGavin Shan  *
2828c8239c2SRob Herring  * Return: The size of unflattened device tree or error code
283dfbd4c6eSGavin Shan  */
unflatten_dt_nodes(const void * blob,void * mem,struct device_node * dad,struct device_node ** nodepp)284947c82cbSGavin Shan static int unflatten_dt_nodes(const void *blob,
285dfbd4c6eSGavin Shan 			      void *mem,
286dfbd4c6eSGavin Shan 			      struct device_node *dad,
28750800082SGavin Shan 			      struct device_node **nodepp)
288dfbd4c6eSGavin Shan {
28950800082SGavin Shan 	struct device_node *root;
2908c237cd0SGavin Shan 	int offset = 0, depth = 0, initial_depth = 0;
29150800082SGavin Shan #define FDT_MAX_DEPTH	64
29250800082SGavin Shan 	struct device_node *nps[FDT_MAX_DEPTH];
29350800082SGavin Shan 	void *base = mem;
29450800082SGavin Shan 	bool dryrun = !base;
295649cab56SFrank Rowand 	int ret;
296dfbd4c6eSGavin Shan 
29750800082SGavin Shan 	if (nodepp)
29850800082SGavin Shan 		*nodepp = NULL;
299dfbd4c6eSGavin Shan 
3008c237cd0SGavin Shan 	/*
3018c237cd0SGavin Shan 	 * We're unflattening device sub-tree if @dad is valid. There are
3028c237cd0SGavin Shan 	 * possibly multiple nodes in the first level of depth. We need
3038c237cd0SGavin Shan 	 * set @depth to 1 to make fdt_next_node() happy as it bails
3048c237cd0SGavin Shan 	 * immediately when negative @depth is found. Otherwise, the device
3058c237cd0SGavin Shan 	 * nodes except the first one won't be unflattened successfully.
3068c237cd0SGavin Shan 	 */
3078c237cd0SGavin Shan 	if (dad)
3088c237cd0SGavin Shan 		depth = initial_depth = 1;
3098c237cd0SGavin Shan 
31050800082SGavin Shan 	root = dad;
31178c44d91SRhyland Klein 	nps[depth] = dad;
3128c237cd0SGavin Shan 
31350800082SGavin Shan 	for (offset = 0;
3148c237cd0SGavin Shan 	     offset >= 0 && depth >= initial_depth;
31550800082SGavin Shan 	     offset = fdt_next_node(blob, offset, &depth)) {
3162f945a79SSergey Shtylyov 		if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH - 1))
31750800082SGavin Shan 			continue;
318e6a6928cSRob Herring 
31977ea8a68SRob Herring 		if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
32077ea8a68SRob Herring 		    !of_fdt_device_is_available(blob, offset))
32177ea8a68SRob Herring 			continue;
32277ea8a68SRob Herring 
323649cab56SFrank Rowand 		ret = populate_node(blob, offset, &mem, nps[depth],
324649cab56SFrank Rowand 				   &nps[depth+1], dryrun);
325649cab56SFrank Rowand 		if (ret < 0)
326649cab56SFrank Rowand 			return ret;
32750800082SGavin Shan 
32850800082SGavin Shan 		if (!dryrun && nodepp && !*nodepp)
32978c44d91SRhyland Klein 			*nodepp = nps[depth+1];
33050800082SGavin Shan 		if (!dryrun && !root)
33178c44d91SRhyland Klein 			root = nps[depth+1];
33250800082SGavin Shan 	}
33350800082SGavin Shan 
33450800082SGavin Shan 	if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
335606ad42aSRob Herring 		pr_err("Error %d processing FDT\n", offset);
33650800082SGavin Shan 		return -EINVAL;
33750800082SGavin Shan 	}
338e6a6928cSRob Herring 
33970161ff3SGrant Likely 	/*
34070161ff3SGrant Likely 	 * Reverse the child list. Some drivers assumes node order matches .dts
34170161ff3SGrant Likely 	 * node order
34270161ff3SGrant Likely 	 */
34350800082SGavin Shan 	if (!dryrun)
34450800082SGavin Shan 		reverse_nodes(root);
34570161ff3SGrant Likely 
34650800082SGavin Shan 	return mem - base;
347bbd33931SGrant Likely }
34841f88009SGrant Likely 
349fe140423SStephen Neuendorffer /**
350fe140423SStephen Neuendorffer  * __unflatten_device_tree - create tree of device_nodes from flat blob
351fe140423SStephen Neuendorffer  * @blob: The blob to expand
352c4263233SGavin Shan  * @dad: Parent device node
353fe140423SStephen Neuendorffer  * @mynodes: The device_node tree created by the call
354fe140423SStephen Neuendorffer  * @dt_alloc: An allocator that provides a virtual address to memory
355fe140423SStephen Neuendorffer  * for the resulting tree
356f5d2da67SStephen Boyd  * @detached: if true set OF_DETACHED on @mynodes
35783262418SGavin Shan  *
35862f026f0SRob Herring  * unflattens a device-tree, creating the tree of struct device_node. It also
35962f026f0SRob Herring  * fills the "name" and "type" pointers of the nodes so the normal device-tree
36062f026f0SRob Herring  * walking functions can be used.
36162f026f0SRob Herring  *
3628c8239c2SRob Herring  * Return: NULL on failure or the memory chunk containing the unflattened
36383262418SGavin Shan  * device tree on success.
364fe140423SStephen Neuendorffer  */
__unflatten_device_tree(const void * blob,struct device_node * dad,struct device_node ** mynodes,void * (* dt_alloc)(u64 size,u64 align),bool detached)36581d0848fSFrank Rowand void *__unflatten_device_tree(const void *blob,
366c4263233SGavin Shan 			      struct device_node *dad,
367fe140423SStephen Neuendorffer 			      struct device_node **mynodes,
3681d1bde55SMichal Suchanek 			      void *(*dt_alloc)(u64 size, u64 align),
3691d1bde55SMichal Suchanek 			      bool detached)
370fe140423SStephen Neuendorffer {
37150800082SGavin Shan 	int size;
372e6a6928cSRob Herring 	void *mem;
373649cab56SFrank Rowand 	int ret;
374649cab56SFrank Rowand 
375649cab56SFrank Rowand 	if (mynodes)
376649cab56SFrank Rowand 		*mynodes = NULL;
377fe140423SStephen Neuendorffer 
378fe140423SStephen Neuendorffer 	pr_debug(" -> unflatten_device_tree()\n");
379fe140423SStephen Neuendorffer 
380fe140423SStephen Neuendorffer 	if (!blob) {
381fe140423SStephen Neuendorffer 		pr_debug("No device tree pointer\n");
38283262418SGavin Shan 		return NULL;
383fe140423SStephen Neuendorffer 	}
384fe140423SStephen Neuendorffer 
385fe140423SStephen Neuendorffer 	pr_debug("Unflattening device tree:\n");
386c972de14SRob Herring 	pr_debug("magic: %08x\n", fdt_magic(blob));
387c972de14SRob Herring 	pr_debug("size: %08x\n", fdt_totalsize(blob));
388c972de14SRob Herring 	pr_debug("version: %08x\n", fdt_version(blob));
389fe140423SStephen Neuendorffer 
390c972de14SRob Herring 	if (fdt_check_header(blob)) {
391fe140423SStephen Neuendorffer 		pr_err("Invalid device tree blob header\n");
39283262418SGavin Shan 		return NULL;
393fe140423SStephen Neuendorffer 	}
394fe140423SStephen Neuendorffer 
395fe140423SStephen Neuendorffer 	/* First pass, scan for size */
396c4263233SGavin Shan 	size = unflatten_dt_nodes(blob, NULL, dad, NULL);
397649cab56SFrank Rowand 	if (size <= 0)
39883262418SGavin Shan 		return NULL;
399fe140423SStephen Neuendorffer 
40050800082SGavin Shan 	size = ALIGN(size, 4);
40150800082SGavin Shan 	pr_debug("  size is %d, allocating...\n", size);
402fe140423SStephen Neuendorffer 
403fe140423SStephen Neuendorffer 	/* Allocate memory for the expanded device tree */
40444856819SGrant Likely 	mem = dt_alloc(size + 4, __alignof__(struct device_node));
40549e67dd1SJohan Hovold 	if (!mem)
40649e67dd1SJohan Hovold 		return NULL;
40749e67dd1SJohan Hovold 
40844856819SGrant Likely 	memset(mem, 0, size);
409fe140423SStephen Neuendorffer 
41044856819SGrant Likely 	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
4119e401275SWladislav Wiebe 
41244856819SGrant Likely 	pr_debug("  unflattening %p...\n", mem);
413fe140423SStephen Neuendorffer 
414fe140423SStephen Neuendorffer 	/* Second pass, do actual unflattening */
415649cab56SFrank Rowand 	ret = unflatten_dt_nodes(blob, mem, dad, mynodes);
416649cab56SFrank Rowand 
41744856819SGrant Likely 	if (be32_to_cpup(mem + size) != 0xdeadbeef)
418e2f04da7SKefeng Wang 		pr_warn("End of tree marker overwritten: %08x\n",
41944856819SGrant Likely 			be32_to_cpup(mem + size));
420fe140423SStephen Neuendorffer 
421649cab56SFrank Rowand 	if (ret <= 0)
422649cab56SFrank Rowand 		return NULL;
423649cab56SFrank Rowand 
424649cab56SFrank Rowand 	if (detached && mynodes && *mynodes) {
4251d1bde55SMichal Suchanek 		of_node_set_flag(*mynodes, OF_DETACHED);
4261d1bde55SMichal Suchanek 		pr_debug("unflattened tree is detached\n");
4271d1bde55SMichal Suchanek 	}
4281d1bde55SMichal Suchanek 
429fe140423SStephen Neuendorffer 	pr_debug(" <- unflatten_device_tree()\n");
43083262418SGavin Shan 	return mem;
431fe140423SStephen Neuendorffer }
432fe140423SStephen Neuendorffer 
kernel_tree_alloc(u64 size,u64 align)433fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align)
434fe140423SStephen Neuendorffer {
435fe140423SStephen Neuendorffer 	return kzalloc(size, GFP_KERNEL);
436fe140423SStephen Neuendorffer }
437fe140423SStephen Neuendorffer 
438f8062386SGuenter Roeck static DEFINE_MUTEX(of_fdt_unflatten_mutex);
439f8062386SGuenter Roeck 
440fe140423SStephen Neuendorffer /**
441fe140423SStephen Neuendorffer  * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
442c4263233SGavin Shan  * @blob: Flat device tree blob
443c4263233SGavin Shan  * @dad: Parent device node
444c4263233SGavin Shan  * @mynodes: The device tree created by the call
445fe140423SStephen Neuendorffer  *
446fe140423SStephen Neuendorffer  * unflattens the device-tree passed by the firmware, creating the
447fe140423SStephen Neuendorffer  * tree of struct device_node. It also fills the "name" and "type"
448fe140423SStephen Neuendorffer  * pointers of the nodes so the normal device-tree walking functions
449fe140423SStephen Neuendorffer  * can be used.
45083262418SGavin Shan  *
4518c8239c2SRob Herring  * Return: NULL on failure or the memory chunk containing the unflattened
45283262418SGavin Shan  * device tree on success.
453fe140423SStephen Neuendorffer  */
of_fdt_unflatten_tree(const unsigned long * blob,struct device_node * dad,struct device_node ** mynodes)45483262418SGavin Shan void *of_fdt_unflatten_tree(const unsigned long *blob,
455c4263233SGavin Shan 			    struct device_node *dad,
456fe140423SStephen Neuendorffer 			    struct device_node **mynodes)
457fe140423SStephen Neuendorffer {
45883262418SGavin Shan 	void *mem;
45983262418SGavin Shan 
460f8062386SGuenter Roeck 	mutex_lock(&of_fdt_unflatten_mutex);
4611d1bde55SMichal Suchanek 	mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc,
4621d1bde55SMichal Suchanek 				      true);
463f8062386SGuenter Roeck 	mutex_unlock(&of_fdt_unflatten_mutex);
46483262418SGavin Shan 
46583262418SGavin Shan 	return mem;
466fe140423SStephen Neuendorffer }
467fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
468fe140423SStephen Neuendorffer 
46957d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */
47057d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells;
47157d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells;
47257d00ecfSStephen Neuendorffer 
4737c71650fSStephen Boyd void *initial_boot_params __ro_after_init;
47457d00ecfSStephen Neuendorffer 
47557d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE
47657d00ecfSStephen Neuendorffer 
47708d53aa5SArd Biesheuvel static u32 of_fdt_crc32;
47808d53aa5SArd Biesheuvel 
early_init_dt_reserve_memory(phys_addr_t base,phys_addr_t size,bool nomap)479f8a855edSPeter Collingbourne static int __init early_init_dt_reserve_memory(phys_addr_t base,
48018250b43SGeert Uytterhoeven 					       phys_addr_t size, bool nomap)
48118250b43SGeert Uytterhoeven {
48218250b43SGeert Uytterhoeven 	if (nomap) {
48318250b43SGeert Uytterhoeven 		/*
48418250b43SGeert Uytterhoeven 		 * If the memory is already reserved (by another region), we
485da17d690SStephen Boyd 		 * should not allow it to be marked nomap, but don't worry
486da17d690SStephen Boyd 		 * if the region isn't memory as it won't be mapped.
48718250b43SGeert Uytterhoeven 		 */
488da17d690SStephen Boyd 		if (memblock_overlaps_region(&memblock.memory, base, size) &&
489da17d690SStephen Boyd 		    memblock_is_region_reserved(base, size))
49018250b43SGeert Uytterhoeven 			return -EBUSY;
49118250b43SGeert Uytterhoeven 
49218250b43SGeert Uytterhoeven 		return memblock_mark_nomap(base, size);
49318250b43SGeert Uytterhoeven 	}
49418250b43SGeert Uytterhoeven 	return memblock_reserve(base, size);
49518250b43SGeert Uytterhoeven }
49618250b43SGeert Uytterhoeven 
497a300dc86SLee Jones /*
498c8813f7eSchenqiwu  * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
499e8d9d1f5SMarek Szyprowski  */
__reserved_mem_reserve_reg(unsigned long node,const char * uname)500e8d9d1f5SMarek Szyprowski static int __init __reserved_mem_reserve_reg(unsigned long node,
501e8d9d1f5SMarek Szyprowski 					     const char *uname)
502e8d9d1f5SMarek Szyprowski {
503e8d9d1f5SMarek Szyprowski 	int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
504e8d9d1f5SMarek Szyprowski 	phys_addr_t base, size;
5059d0c4dfeSRob Herring 	int len;
5069d0c4dfeSRob Herring 	const __be32 *prop;
5075c68b823SMasahiro Yamada 	int first = 1;
5085c68b823SMasahiro Yamada 	bool nomap;
509e8d9d1f5SMarek Szyprowski 
510e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "reg", &len);
511e8d9d1f5SMarek Szyprowski 	if (!prop)
512e8d9d1f5SMarek Szyprowski 		return -ENOENT;
513e8d9d1f5SMarek Szyprowski 
514e8d9d1f5SMarek Szyprowski 	if (len && len % t_len != 0) {
515e8d9d1f5SMarek Szyprowski 		pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
516e8d9d1f5SMarek Szyprowski 		       uname);
517e8d9d1f5SMarek Szyprowski 		return -EINVAL;
518e8d9d1f5SMarek Szyprowski 	}
519e8d9d1f5SMarek Szyprowski 
520e8d9d1f5SMarek Szyprowski 	nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
521e8d9d1f5SMarek Szyprowski 
522e8d9d1f5SMarek Szyprowski 	while (len >= t_len) {
523e8d9d1f5SMarek Szyprowski 		base = dt_mem_next_cell(dt_root_addr_cells, &prop);
524e8d9d1f5SMarek Szyprowski 		size = dt_mem_next_cell(dt_root_size_cells, &prop);
525e8d9d1f5SMarek Szyprowski 
526b5f2a8c0SAl Cooper 		if (size &&
5278ef852f1SIsaac J. Manjarres 		    early_init_dt_reserve_memory(base, size, nomap) == 0)
5282892d8a0SGeert Uytterhoeven 			pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
5292892d8a0SGeert Uytterhoeven 				uname, &base, (unsigned long)(size / SZ_1M));
530e8d9d1f5SMarek Szyprowski 		else
5316991cd74SVincent Whitchurch 			pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
5322892d8a0SGeert Uytterhoeven 			       uname, &base, (unsigned long)(size / SZ_1M));
533e8d9d1f5SMarek Szyprowski 
534e8d9d1f5SMarek Szyprowski 		len -= t_len;
5353f0c8206SMarek Szyprowski 		if (first) {
5363f0c8206SMarek Szyprowski 			fdt_reserved_mem_save_node(node, uname, base, size);
5373f0c8206SMarek Szyprowski 			first = 0;
5383f0c8206SMarek Szyprowski 		}
539e8d9d1f5SMarek Szyprowski 	}
540e8d9d1f5SMarek Szyprowski 	return 0;
541e8d9d1f5SMarek Szyprowski }
542e8d9d1f5SMarek Szyprowski 
543a300dc86SLee Jones /*
544e8d9d1f5SMarek Szyprowski  * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
545e8d9d1f5SMarek Szyprowski  * in /reserved-memory matches the values supported by the current implementation,
546e8d9d1f5SMarek Szyprowski  * also check if ranges property has been provided
547e8d9d1f5SMarek Szyprowski  */
__reserved_mem_check_root(unsigned long node)5485b624118SXiubo Li static int __init __reserved_mem_check_root(unsigned long node)
549e8d9d1f5SMarek Szyprowski {
5509d0c4dfeSRob Herring 	const __be32 *prop;
551e8d9d1f5SMarek Szyprowski 
552e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
553e8d9d1f5SMarek Szyprowski 	if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
554e8d9d1f5SMarek Szyprowski 		return -EINVAL;
555e8d9d1f5SMarek Szyprowski 
556e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
557e8d9d1f5SMarek Szyprowski 	if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
558e8d9d1f5SMarek Szyprowski 		return -EINVAL;
559e8d9d1f5SMarek Szyprowski 
560e8d9d1f5SMarek Szyprowski 	prop = of_get_flat_dt_prop(node, "ranges", NULL);
561e8d9d1f5SMarek Szyprowski 	if (!prop)
562e8d9d1f5SMarek Szyprowski 		return -EINVAL;
563e8d9d1f5SMarek Szyprowski 	return 0;
564e8d9d1f5SMarek Szyprowski }
565e8d9d1f5SMarek Szyprowski 
566a300dc86SLee Jones /*
567fb2293fdSRob Herring  * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
568e8d9d1f5SMarek Szyprowski  */
fdt_scan_reserved_mem(void)569fb2293fdSRob Herring static int __init fdt_scan_reserved_mem(void)
570e8d9d1f5SMarek Szyprowski {
571fb2293fdSRob Herring 	int node, child;
572fb2293fdSRob Herring 	const void *fdt = initial_boot_params;
573e8d9d1f5SMarek Szyprowski 
574fb2293fdSRob Herring 	node = fdt_path_offset(fdt, "/reserved-memory");
575fb2293fdSRob Herring 	if (node < 0)
576fb2293fdSRob Herring 		return -ENODEV;
577fb2293fdSRob Herring 
578e8d9d1f5SMarek Szyprowski 	if (__reserved_mem_check_root(node) != 0) {
579e8d9d1f5SMarek Szyprowski 		pr_err("Reserved memory: unsupported node format, ignoring\n");
580fb2293fdSRob Herring 		return -EINVAL;
581e8d9d1f5SMarek Szyprowski 	}
582e8d9d1f5SMarek Szyprowski 
583fb2293fdSRob Herring 	fdt_for_each_subnode(child, fdt, node) {
584fb2293fdSRob Herring 		const char *uname;
585fb2293fdSRob Herring 		int err;
586e8d9d1f5SMarek Szyprowski 
587fb2293fdSRob Herring 		if (!of_fdt_device_is_available(fdt, child))
588fb2293fdSRob Herring 			continue;
589e8d9d1f5SMarek Szyprowski 
590fb2293fdSRob Herring 		uname = fdt_get_name(fdt, child, NULL);
591fb2293fdSRob Herring 
592fb2293fdSRob Herring 		err = __reserved_mem_reserve_reg(child, uname);
593fb2293fdSRob Herring 		if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL))
594fb2293fdSRob Herring 			fdt_reserved_mem_save_node(child, uname, 0, 0);
595fb2293fdSRob Herring 	}
596e8d9d1f5SMarek Szyprowski 	return 0;
597e8d9d1f5SMarek Szyprowski }
598e8d9d1f5SMarek Szyprowski 
599f7e7ce93SGeert Uytterhoeven /*
6002fcf9a17SGeert Uytterhoeven  * fdt_reserve_elfcorehdr() - reserves memory for elf core header
601f7e7ce93SGeert Uytterhoeven  *
602f7e7ce93SGeert Uytterhoeven  * This function reserves the memory occupied by an elf core header
603f7e7ce93SGeert Uytterhoeven  * described in the device tree. This region contains all the
604f7e7ce93SGeert Uytterhoeven  * information about primary kernel's core image and is used by a dump
605f7e7ce93SGeert Uytterhoeven  * capture kernel to access the system memory on primary kernel.
606f7e7ce93SGeert Uytterhoeven  */
fdt_reserve_elfcorehdr(void)6072fcf9a17SGeert Uytterhoeven static void __init fdt_reserve_elfcorehdr(void)
608f7e7ce93SGeert Uytterhoeven {
609f7e7ce93SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_CRASH_DUMP) || !elfcorehdr_size)
610f7e7ce93SGeert Uytterhoeven 		return;
611f7e7ce93SGeert Uytterhoeven 
612f7e7ce93SGeert Uytterhoeven 	if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
613f7e7ce93SGeert Uytterhoeven 		pr_warn("elfcorehdr is overlapped\n");
614f7e7ce93SGeert Uytterhoeven 		return;
615f7e7ce93SGeert Uytterhoeven 	}
616f7e7ce93SGeert Uytterhoeven 
617f7e7ce93SGeert Uytterhoeven 	memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
618f7e7ce93SGeert Uytterhoeven 
619f7e7ce93SGeert Uytterhoeven 	pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n",
620f7e7ce93SGeert Uytterhoeven 		elfcorehdr_size >> 10, elfcorehdr_addr);
621f7e7ce93SGeert Uytterhoeven }
622f7e7ce93SGeert Uytterhoeven 
623e8d9d1f5SMarek Szyprowski /**
624e8d9d1f5SMarek Szyprowski  * early_init_fdt_scan_reserved_mem() - create reserved memory regions
625e8d9d1f5SMarek Szyprowski  *
626e8d9d1f5SMarek Szyprowski  * This function grabs memory from early allocator for device exclusive use
627e8d9d1f5SMarek Szyprowski  * defined in device tree structures. It should be called by arch specific code
628e8d9d1f5SMarek Szyprowski  * once the early allocator (i.e. memblock) has been fully activated.
629e8d9d1f5SMarek Szyprowski  */
early_init_fdt_scan_reserved_mem(void)630e8d9d1f5SMarek Szyprowski void __init early_init_fdt_scan_reserved_mem(void)
631e8d9d1f5SMarek Szyprowski {
632d1552ce4SRob Herring 	int n;
633d1552ce4SRob Herring 	u64 base, size;
634d1552ce4SRob Herring 
6352040b527SJosh Cartwright 	if (!initial_boot_params)
6362040b527SJosh Cartwright 		return;
6372040b527SJosh Cartwright 
638*b4132818SLucas Tanure 	fdt_scan_reserved_mem();
639*b4132818SLucas Tanure 	fdt_reserve_elfcorehdr();
640*b4132818SLucas Tanure 
641d1552ce4SRob Herring 	/* Process header /memreserve/ fields */
642d1552ce4SRob Herring 	for (n = 0; ; n++) {
643d1552ce4SRob Herring 		fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
644d1552ce4SRob Herring 		if (!size)
645d1552ce4SRob Herring 			break;
646f8a855edSPeter Collingbourne 		memblock_reserve(base, size);
647d1552ce4SRob Herring 	}
648d1552ce4SRob Herring 
649132507edSNikhil Gupta 	fdt_init_reserved_mem();
650e8d9d1f5SMarek Szyprowski }
651e8d9d1f5SMarek Szyprowski 
652e8d9d1f5SMarek Szyprowski /**
65324bbd929SArd Biesheuvel  * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob
65424bbd929SArd Biesheuvel  */
early_init_fdt_reserve_self(void)65524bbd929SArd Biesheuvel void __init early_init_fdt_reserve_self(void)
65624bbd929SArd Biesheuvel {
65724bbd929SArd Biesheuvel 	if (!initial_boot_params)
65824bbd929SArd Biesheuvel 		return;
65924bbd929SArd Biesheuvel 
66024bbd929SArd Biesheuvel 	/* Reserve the dtb region */
661f8a855edSPeter Collingbourne 	memblock_reserve(__pa(initial_boot_params),
662f8a855edSPeter Collingbourne 			 fdt_totalsize(initial_boot_params));
66324bbd929SArd Biesheuvel }
66424bbd929SArd Biesheuvel 
66524bbd929SArd Biesheuvel /**
66657d00ecfSStephen Neuendorffer  * of_scan_flat_dt - scan flattened tree blob and call callback on each.
66757d00ecfSStephen Neuendorffer  * @it: callback function
66857d00ecfSStephen Neuendorffer  * @data: context data pointer
66957d00ecfSStephen Neuendorffer  *
67057d00ecfSStephen Neuendorffer  * This function is used to scan the flattened device-tree, it is
67157d00ecfSStephen Neuendorffer  * used to extract the memory information at boot before we can
67257d00ecfSStephen Neuendorffer  * unflatten the tree
67357d00ecfSStephen Neuendorffer  */
of_scan_flat_dt(int (* it)(unsigned long node,const char * uname,int depth,void * data),void * data)67457d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node,
67557d00ecfSStephen Neuendorffer 				     const char *uname, int depth,
67657d00ecfSStephen Neuendorffer 				     void *data),
67757d00ecfSStephen Neuendorffer 			   void *data)
67857d00ecfSStephen Neuendorffer {
679e6a6928cSRob Herring 	const void *blob = initial_boot_params;
680e55b0829SFabio Estevam 	const char *pathp;
681e6a6928cSRob Herring 	int offset, rc = 0, depth = -1;
68257d00ecfSStephen Neuendorffer 
6833ec75441STobias Wolf 	if (!blob)
6843ec75441STobias Wolf 		return 0;
6853ec75441STobias Wolf 
686e6a6928cSRob Herring 	for (offset = fdt_next_node(blob, -1, &depth);
687e6a6928cSRob Herring 	     offset >= 0 && depth >= 0 && !rc;
688e6a6928cSRob Herring 	     offset = fdt_next_node(blob, offset, &depth)) {
689e6a6928cSRob Herring 
690e6a6928cSRob Herring 		pathp = fdt_get_name(blob, offset, NULL);
691e6a6928cSRob Herring 		rc = it(offset, pathp, depth, data);
692e6a6928cSRob Herring 	}
69357d00ecfSStephen Neuendorffer 	return rc;
69457d00ecfSStephen Neuendorffer }
69557d00ecfSStephen Neuendorffer 
69657d00ecfSStephen Neuendorffer /**
697ea47dd19SNicholas Piggin  * of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each.
698a300dc86SLee Jones  * @parent: parent node
699ea47dd19SNicholas Piggin  * @it: callback function
700ea47dd19SNicholas Piggin  * @data: context data pointer
701ea47dd19SNicholas Piggin  *
702ea47dd19SNicholas Piggin  * This function is used to scan sub-nodes of a node.
703ea47dd19SNicholas Piggin  */
of_scan_flat_dt_subnodes(unsigned long parent,int (* it)(unsigned long node,const char * uname,void * data),void * data)704ea47dd19SNicholas Piggin int __init of_scan_flat_dt_subnodes(unsigned long parent,
705ea47dd19SNicholas Piggin 				    int (*it)(unsigned long node,
706ea47dd19SNicholas Piggin 					      const char *uname,
707ea47dd19SNicholas Piggin 					      void *data),
708ea47dd19SNicholas Piggin 				    void *data)
709ea47dd19SNicholas Piggin {
710ea47dd19SNicholas Piggin 	const void *blob = initial_boot_params;
711ea47dd19SNicholas Piggin 	int node;
712ea47dd19SNicholas Piggin 
713ea47dd19SNicholas Piggin 	fdt_for_each_subnode(node, blob, parent) {
714ea47dd19SNicholas Piggin 		const char *pathp;
715ea47dd19SNicholas Piggin 		int rc;
716ea47dd19SNicholas Piggin 
717ea47dd19SNicholas Piggin 		pathp = fdt_get_name(blob, node, NULL);
718ea47dd19SNicholas Piggin 		rc = it(node, pathp, data);
719ea47dd19SNicholas Piggin 		if (rc)
720ea47dd19SNicholas Piggin 			return rc;
721ea47dd19SNicholas Piggin 	}
722ea47dd19SNicholas Piggin 	return 0;
723ea47dd19SNicholas Piggin }
724ea47dd19SNicholas Piggin 
725ea47dd19SNicholas Piggin /**
7269c609868SShannon Zhao  * of_get_flat_dt_subnode_by_name - get the subnode by given name
7279c609868SShannon Zhao  *
7289c609868SShannon Zhao  * @node: the parent node
7299c609868SShannon Zhao  * @uname: the name of subnode
7309c609868SShannon Zhao  * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none
7319c609868SShannon Zhao  */
7329c609868SShannon Zhao 
of_get_flat_dt_subnode_by_name(unsigned long node,const char * uname)7339b4d2b63SStephen Boyd int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
7349c609868SShannon Zhao {
7359c609868SShannon Zhao 	return fdt_subnode_offset(initial_boot_params, node, uname);
7369c609868SShannon Zhao }
7379c609868SShannon Zhao 
738a300dc86SLee Jones /*
73957d00ecfSStephen Neuendorffer  * of_get_flat_dt_root - find the root node in the flat blob
74057d00ecfSStephen Neuendorffer  */
of_get_flat_dt_root(void)74157d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void)
74257d00ecfSStephen Neuendorffer {
743e6a6928cSRob Herring 	return 0;
74457d00ecfSStephen Neuendorffer }
74557d00ecfSStephen Neuendorffer 
746a300dc86SLee Jones /*
74757d00ecfSStephen Neuendorffer  * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
74857d00ecfSStephen Neuendorffer  *
74957d00ecfSStephen Neuendorffer  * This function can be used within scan_flattened_dt callback to get
75057d00ecfSStephen Neuendorffer  * access to properties
75157d00ecfSStephen Neuendorffer  */
of_get_flat_dt_prop(unsigned long node,const char * name,int * size)7529d0c4dfeSRob Herring const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
7539d0c4dfeSRob Herring 				       int *size)
75457d00ecfSStephen Neuendorffer {
755e6a6928cSRob Herring 	return fdt_getprop(initial_boot_params, node, name, size);
75657d00ecfSStephen Neuendorffer }
75757d00ecfSStephen Neuendorffer 
75857d00ecfSStephen Neuendorffer /**
7595d9c4e95SKefeng Wang  * of_fdt_is_compatible - Return true if given node from the given blob has
7605d9c4e95SKefeng Wang  * compat in its compatible list
7615d9c4e95SKefeng Wang  * @blob: A device tree blob
7625d9c4e95SKefeng Wang  * @node: node to test
7635d9c4e95SKefeng Wang  * @compat: compatible string to compare with compatible list.
7645d9c4e95SKefeng Wang  *
7658c8239c2SRob Herring  * Return: a non-zero value on match with smaller values returned for more
7665d9c4e95SKefeng Wang  * specific compatible values.
7675d9c4e95SKefeng Wang  */
of_fdt_is_compatible(const void * blob,unsigned long node,const char * compat)7685d9c4e95SKefeng Wang static int of_fdt_is_compatible(const void *blob,
7695d9c4e95SKefeng Wang 		      unsigned long node, const char *compat)
7705d9c4e95SKefeng Wang {
7715d9c4e95SKefeng Wang 	const char *cp;
7725d9c4e95SKefeng Wang 	int cplen;
7735d9c4e95SKefeng Wang 	unsigned long l, score = 0;
7745d9c4e95SKefeng Wang 
7755d9c4e95SKefeng Wang 	cp = fdt_getprop(blob, node, "compatible", &cplen);
7765d9c4e95SKefeng Wang 	if (cp == NULL)
7775d9c4e95SKefeng Wang 		return 0;
7785d9c4e95SKefeng Wang 	while (cplen > 0) {
7795d9c4e95SKefeng Wang 		score++;
7805d9c4e95SKefeng Wang 		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
7815d9c4e95SKefeng Wang 			return score;
7825d9c4e95SKefeng Wang 		l = strlen(cp) + 1;
7835d9c4e95SKefeng Wang 		cp += l;
7845d9c4e95SKefeng Wang 		cplen -= l;
7855d9c4e95SKefeng Wang 	}
7865d9c4e95SKefeng Wang 
7875d9c4e95SKefeng Wang 	return 0;
7885d9c4e95SKefeng Wang }
7895d9c4e95SKefeng Wang 
7905d9c4e95SKefeng Wang /**
79157d00ecfSStephen Neuendorffer  * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
79257d00ecfSStephen Neuendorffer  * @node: node to test
79357d00ecfSStephen Neuendorffer  * @compat: compatible string to compare with compatible list.
79457d00ecfSStephen Neuendorffer  */
of_flat_dt_is_compatible(unsigned long node,const char * compat)79557d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
79657d00ecfSStephen Neuendorffer {
79757d00ecfSStephen Neuendorffer 	return of_fdt_is_compatible(initial_boot_params, node, compat);
79857d00ecfSStephen Neuendorffer }
79957d00ecfSStephen Neuendorffer 
800a300dc86SLee Jones /*
801a4f740cfSGrant Likely  * of_flat_dt_match - Return true if node matches a list of compatible values
802a4f740cfSGrant Likely  */
of_flat_dt_match(unsigned long node,const char * const * compat)8039b4d2b63SStephen Boyd static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
804a4f740cfSGrant Likely {
8055d9c4e95SKefeng Wang 	unsigned int tmp, score = 0;
8065d9c4e95SKefeng Wang 
8075d9c4e95SKefeng Wang 	if (!compat)
8085d9c4e95SKefeng Wang 		return 0;
8095d9c4e95SKefeng Wang 
8105d9c4e95SKefeng Wang 	while (*compat) {
8115d9c4e95SKefeng Wang 		tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
8125d9c4e95SKefeng Wang 		if (tmp && (score == 0 || (tmp < score)))
8135d9c4e95SKefeng Wang 			score = tmp;
8145d9c4e95SKefeng Wang 		compat++;
8155d9c4e95SKefeng Wang 	}
8165d9c4e95SKefeng Wang 
8175d9c4e95SKefeng Wang 	return score;
818a4f740cfSGrant Likely }
819a4f740cfSGrant Likely 
820a300dc86SLee Jones /*
821a300dc86SLee Jones  * of_get_flat_dt_phandle - Given a node in the flat blob, return the phandle
822ea47dd19SNicholas Piggin  */
of_get_flat_dt_phandle(unsigned long node)823ea47dd19SNicholas Piggin uint32_t __init of_get_flat_dt_phandle(unsigned long node)
824ea47dd19SNicholas Piggin {
825ea47dd19SNicholas Piggin 	return fdt_get_phandle(initial_boot_params, node);
826ea47dd19SNicholas Piggin }
827ea47dd19SNicholas Piggin 
of_flat_dt_get_machine_name(void)8286a903a25SRob Herring const char * __init of_flat_dt_get_machine_name(void)
8296a903a25SRob Herring {
8306a903a25SRob Herring 	const char *name;
8316a903a25SRob Herring 	unsigned long dt_root = of_get_flat_dt_root();
8326a903a25SRob Herring 
8336a903a25SRob Herring 	name = of_get_flat_dt_prop(dt_root, "model", NULL);
8346a903a25SRob Herring 	if (!name)
8356a903a25SRob Herring 		name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
8366a903a25SRob Herring 	return name;
8376a903a25SRob Herring }
8386a903a25SRob Herring 
8396a903a25SRob Herring /**
8406a903a25SRob Herring  * of_flat_dt_match_machine - Iterate match tables to find matching machine.
8416a903a25SRob Herring  *
8426a903a25SRob Herring  * @default_match: A machine specific ptr to return in case of no match.
8436a903a25SRob Herring  * @get_next_compat: callback function to return next compatible match table.
8446a903a25SRob Herring  *
8456a903a25SRob Herring  * Iterate through machine match tables to find the best match for the machine
8466a903a25SRob Herring  * compatible string in the FDT.
8476a903a25SRob Herring  */
of_flat_dt_match_machine(const void * default_match,const void * (* get_next_compat)(const char * const **))8486a903a25SRob Herring const void * __init of_flat_dt_match_machine(const void *default_match,
8496a903a25SRob Herring 		const void * (*get_next_compat)(const char * const**))
8506a903a25SRob Herring {
8516a903a25SRob Herring 	const void *data = NULL;
8526a903a25SRob Herring 	const void *best_data = default_match;
8536a903a25SRob Herring 	const char *const *compat;
8546a903a25SRob Herring 	unsigned long dt_root;
8556a903a25SRob Herring 	unsigned int best_score = ~1, score = 0;
8566a903a25SRob Herring 
8576a903a25SRob Herring 	dt_root = of_get_flat_dt_root();
8586a903a25SRob Herring 	while ((data = get_next_compat(&compat))) {
8596a903a25SRob Herring 		score = of_flat_dt_match(dt_root, compat);
8606a903a25SRob Herring 		if (score > 0 && score < best_score) {
8616a903a25SRob Herring 			best_data = data;
8626a903a25SRob Herring 			best_score = score;
8636a903a25SRob Herring 		}
8646a903a25SRob Herring 	}
8656a903a25SRob Herring 	if (!best_data) {
8666a903a25SRob Herring 		const char *prop;
8679d0c4dfeSRob Herring 		int size;
8686a903a25SRob Herring 
8696a903a25SRob Herring 		pr_err("\n unrecognized device tree list:\n[ ");
8706a903a25SRob Herring 
8716a903a25SRob Herring 		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
8726a903a25SRob Herring 		if (prop) {
8736a903a25SRob Herring 			while (size > 0) {
8746a903a25SRob Herring 				printk("'%s' ", prop);
8756a903a25SRob Herring 				size -= strlen(prop) + 1;
8766a903a25SRob Herring 				prop += strlen(prop) + 1;
8776a903a25SRob Herring 			}
8786a903a25SRob Herring 		}
8796a903a25SRob Herring 		printk("]\n\n");
8806a903a25SRob Herring 		return NULL;
8816a903a25SRob Herring 	}
8826a903a25SRob Herring 
8836a903a25SRob Herring 	pr_info("Machine model: %s\n", of_flat_dt_get_machine_name());
8846a903a25SRob Herring 
8856a903a25SRob Herring 	return best_data;
8866a903a25SRob Herring }
8876a903a25SRob Herring 
__early_init_dt_declare_initrd(unsigned long start,unsigned long end)888369bc9abSArd Biesheuvel static void __early_init_dt_declare_initrd(unsigned long start,
889369bc9abSArd Biesheuvel 					   unsigned long end)
890369bc9abSArd Biesheuvel {
891cdbc848bSFlorian Fainelli 	/*
892cdbc848bSFlorian Fainelli 	 * __va() is not yet available this early on some platforms. In that
893cdbc848bSFlorian Fainelli 	 * case, the platform uses phys_initrd_start/phys_initrd_size instead
894cdbc848bSFlorian Fainelli 	 * and does the VA conversion itself.
895cdbc848bSFlorian Fainelli 	 */
896cdbc848bSFlorian Fainelli 	if (!IS_ENABLED(CONFIG_ARM64) &&
897369bc9abSArd Biesheuvel 	    !(IS_ENABLED(CONFIG_RISCV) && IS_ENABLED(CONFIG_64BIT))) {
898369bc9abSArd Biesheuvel 		initrd_start = (unsigned long)__va(start);
899369bc9abSArd Biesheuvel 		initrd_end = (unsigned long)__va(end);
900369bc9abSArd Biesheuvel 		initrd_below_start_ok = 1;
901cdbc848bSFlorian Fainelli 	}
902369bc9abSArd Biesheuvel }
903f7b3a835SGrant Likely 
904f7b3a835SGrant Likely /**
905f7b3a835SGrant Likely  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
906f7b3a835SGrant Likely  * @node: reference to node containing initrd location ('chosen')
90729eb45a9SRob Herring  */
early_init_dt_check_for_initrd(unsigned long node)908f7b3a835SGrant Likely static void __init early_init_dt_check_for_initrd(unsigned long node)
909374d5c99SSantosh Shilimkar {
9109d0c4dfeSRob Herring 	u64 start, end;
9119d0c4dfeSRob Herring 	int len;
912f7b3a835SGrant Likely 	const __be32 *prop;
913bf2e8609SGeert Uytterhoeven 
914bf2e8609SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
915bf2e8609SGeert Uytterhoeven 		return;
916f7b3a835SGrant Likely 
917f7b3a835SGrant Likely 	pr_debug("Looking for initrd properties... ");
918f7b3a835SGrant Likely 
9191406bc2fSJeremy Kerr 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
9201406bc2fSJeremy Kerr 	if (!prop)
921374d5c99SSantosh Shilimkar 		return;
922f7b3a835SGrant Likely 	start = of_read_number(prop, len/4);
923f7b3a835SGrant Likely 
9241406bc2fSJeremy Kerr 	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
9251406bc2fSJeremy Kerr 	if (!prop)
926374d5c99SSantosh Shilimkar 		return;
927d5e3050cSMarek Bykowski 	end = of_read_number(prop, len/4);
928d5e3050cSMarek Bykowski 	if (start > end)
929f7b3a835SGrant Likely 		return;
930369bc9abSArd Biesheuvel 
931fe7db757SFlorian Fainelli 	__early_init_dt_declare_initrd(start, end);
932fe7db757SFlorian Fainelli 	phys_initrd_start = start;
93329eb45a9SRob Herring 	phys_initrd_size = end - start;
9340e407a9aSGeert Uytterhoeven 
935f7b3a835SGrant Likely 	pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n", start, end);
936f7b3a835SGrant Likely }
937f7e7ce93SGeert Uytterhoeven 
938f7e7ce93SGeert Uytterhoeven /**
939f7e7ce93SGeert Uytterhoeven  * early_init_dt_check_for_elfcorehdr - Decode elfcorehdr location from flat
940f7e7ce93SGeert Uytterhoeven  * tree
941f7e7ce93SGeert Uytterhoeven  * @node: reference to node containing elfcorehdr location ('chosen')
942f7e7ce93SGeert Uytterhoeven  */
early_init_dt_check_for_elfcorehdr(unsigned long node)943f7e7ce93SGeert Uytterhoeven static void __init early_init_dt_check_for_elfcorehdr(unsigned long node)
944f7e7ce93SGeert Uytterhoeven {
945f7e7ce93SGeert Uytterhoeven 	const __be32 *prop;
946f7e7ce93SGeert Uytterhoeven 	int len;
947f7e7ce93SGeert Uytterhoeven 
948f7e7ce93SGeert Uytterhoeven 	if (!IS_ENABLED(CONFIG_CRASH_DUMP))
949f7e7ce93SGeert Uytterhoeven 		return;
950f7e7ce93SGeert Uytterhoeven 
951f7e7ce93SGeert Uytterhoeven 	pr_debug("Looking for elfcorehdr property... ");
952f7e7ce93SGeert Uytterhoeven 
953f7e7ce93SGeert Uytterhoeven 	prop = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len);
954f7e7ce93SGeert Uytterhoeven 	if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells)))
955f7e7ce93SGeert Uytterhoeven 		return;
956f7e7ce93SGeert Uytterhoeven 
957f7e7ce93SGeert Uytterhoeven 	elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
958f7e7ce93SGeert Uytterhoeven 	elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &prop);
959f7e7ce93SGeert Uytterhoeven 
960f7e7ce93SGeert Uytterhoeven 	pr_debug("elfcorehdr_start=0x%llx elfcorehdr_size=0x%llx\n",
961f7e7ce93SGeert Uytterhoeven 		 elfcorehdr_addr, elfcorehdr_size);
962f7e7ce93SGeert Uytterhoeven }
9638347b417SZhen Lei 
9642af2b50aSGeert Uytterhoeven static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
965fb319e77SChen Zhou 
966fb319e77SChen Zhou /*
967fb319e77SChen Zhou  * The main usage of linux,usable-memory-range is for crash dump kernel.
968fb319e77SChen Zhou  * Originally, the number of usable-memory regions is one. Now there may
969fb319e77SChen Zhou  * be two regions, low region and high region.
970fb319e77SChen Zhou  * To make compatibility with existing user-space and older kdump, the low
971fb319e77SChen Zhou  * region is always the last range of linux,usable-memory-range if exist.
972fb319e77SChen Zhou  */
973fb319e77SChen Zhou #define MAX_USABLE_RANGES		2
9742af2b50aSGeert Uytterhoeven 
9752af2b50aSGeert Uytterhoeven /**
9762af2b50aSGeert Uytterhoeven  * early_init_dt_check_for_usable_mem_range - Decode usable memory range
9772af2b50aSGeert Uytterhoeven  * location from flat tree
978b398123bSPingfan Liu  */
early_init_dt_check_for_usable_mem_range(void)9792af2b50aSGeert Uytterhoeven void __init early_init_dt_check_for_usable_mem_range(void)
980fb319e77SChen Zhou {
981fb319e77SChen Zhou 	struct memblock_region rgn[MAX_USABLE_RANGES] = {0};
982fb319e77SChen Zhou 	const __be32 *prop, *endp;
9838347b417SZhen Lei 	int len, i;
9848347b417SZhen Lei 	unsigned long node = chosen_node_offset;
9858347b417SZhen Lei 
9868347b417SZhen Lei 	if ((long)node < 0)
9872af2b50aSGeert Uytterhoeven 		return;
9882af2b50aSGeert Uytterhoeven 
9892af2b50aSGeert Uytterhoeven 	pr_debug("Looking for usable-memory-range property... ");
9902af2b50aSGeert Uytterhoeven 
991fb319e77SChen Zhou 	prop = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len);
9922af2b50aSGeert Uytterhoeven 	if (!prop || (len % (dt_root_addr_cells + dt_root_size_cells)))
9932af2b50aSGeert Uytterhoeven 		return;
994fb319e77SChen Zhou 
995fb319e77SChen Zhou 	endp = prop + (len / sizeof(__be32));
996fb319e77SChen Zhou 	for (i = 0; i < MAX_USABLE_RANGES && prop < endp; i++) {
997fb319e77SChen Zhou 		rgn[i].base = dt_mem_next_cell(dt_root_addr_cells, &prop);
9982af2b50aSGeert Uytterhoeven 		rgn[i].size = dt_mem_next_cell(dt_root_size_cells, &prop);
999fb319e77SChen Zhou 
1000fb319e77SChen Zhou 		pr_debug("cap_mem_regions[%d]: base=%pa, size=%pa\n",
1001fb319e77SChen Zhou 			 i, &rgn[i].base, &rgn[i].size);
10028347b417SZhen Lei 	}
1003fb319e77SChen Zhou 
1004fb319e77SChen Zhou 	memblock_cap_memory_range(rgn[0].base, rgn[0].size);
1005fb319e77SChen Zhou 	for (i = 1; i < MAX_USABLE_RANGES && rgn[i].size; i++)
10062af2b50aSGeert Uytterhoeven 		memblock_add(rgn[i].base, rgn[i].size);
10072af2b50aSGeert Uytterhoeven }
1008fb11ffe7SRob Herring 
1009fb11ffe7SRob Herring #ifdef CONFIG_SERIAL_EARLYCON
1010d503187bSLeif Lindholm 
early_init_dt_scan_chosen_stdout(void)1011fb11ffe7SRob Herring int __init early_init_dt_scan_chosen_stdout(void)
1012fb11ffe7SRob Herring {
10134d118c9aSPeter Hurley 	int offset;
1014fb11ffe7SRob Herring 	const char *p, *q, *options = NULL;
101562dcd9c5SJohan Hovold 	int l;
1016fb11ffe7SRob Herring 	const struct earlycon_id *match;
101765e20e8cSMichael Walle 	const void *fdt = initial_boot_params;
1018fb11ffe7SRob Herring 	int ret;
1019fb11ffe7SRob Herring 
1020fb11ffe7SRob Herring 	offset = fdt_path_offset(fdt, "/chosen");
1021fb11ffe7SRob Herring 	if (offset < 0)
1022fb11ffe7SRob Herring 		offset = fdt_path_offset(fdt, "/chosen@0");
1023fb11ffe7SRob Herring 	if (offset < 0)
1024fb11ffe7SRob Herring 		return -ENOENT;
1025fb11ffe7SRob Herring 
1026fb11ffe7SRob Herring 	p = fdt_getprop(fdt, offset, "stdout-path", &l);
1027fb11ffe7SRob Herring 	if (!p)
1028fb11ffe7SRob Herring 		p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
1029fb11ffe7SRob Herring 	if (!p || !l)
1030fb11ffe7SRob Herring 		return -ENOENT;
10314d118c9aSPeter Hurley 
10324d118c9aSPeter Hurley 	q = strchrnul(p, ':');
10334d118c9aSPeter Hurley 	if (*q != '\0')
10340fcc286fSPeter Hurley 		options = q + 1;
10356296ad9eSStefan Agner 	l = q - p;
1036fb11ffe7SRob Herring 
10370fcc286fSPeter Hurley 	/* Get the node specified by stdout-path */
10380fcc286fSPeter Hurley 	offset = fdt_path_offset_namelen(fdt, p, l);
10390fcc286fSPeter Hurley 	if (offset < 0) {
10400fcc286fSPeter Hurley 		pr_warn("earlycon: stdout-path %.*s not found\n", l, p);
10410fcc286fSPeter Hurley 		return 0;
1042fb11ffe7SRob Herring 	}
104362dcd9c5SJohan Hovold 
10442eaa7909SPeter Hurley 	for (match = __earlycon_table; match < __earlycon_table_end; match++) {
1045fb11ffe7SRob Herring 		if (!match->compatible[0])
10462eaa7909SPeter Hurley 			continue;
10472eaa7909SPeter Hurley 
10482eaa7909SPeter Hurley 		if (fdt_node_check_compatible(fdt, offset, match->compatible))
1049fb11ffe7SRob Herring 			continue;
105065e20e8cSMichael Walle 
105165e20e8cSMichael Walle 		ret = of_setup_earlycon(match, offset, options);
1052fb11ffe7SRob Herring 		if (!ret || ret == -EALREADY)
1053fb11ffe7SRob Herring 			return 0;
1054fb11ffe7SRob Herring 	}
1055fb11ffe7SRob Herring 	return -ENODEV;
1056fb11ffe7SRob Herring }
1057fb11ffe7SRob Herring #endif
1058a300dc86SLee Jones 
1059f00abd94SGrant Likely /*
1060f00abd94SGrant Likely  * early_init_dt_scan_root - fetch the top level address and size cells
1061d665881dSRob Herring  */
early_init_dt_scan_root(void)1062f00abd94SGrant Likely int __init early_init_dt_scan_root(void)
10639d0c4dfeSRob Herring {
1064d665881dSRob Herring 	const __be32 *prop;
1065d665881dSRob Herring 	const void *fdt = initial_boot_params;
1066f00abd94SGrant Likely 	int node = fdt_path_offset(fdt, "/");
1067d665881dSRob Herring 
1068d665881dSRob Herring 	if (node < 0)
1069f00abd94SGrant Likely 		return -ENODEV;
107033714881SJeremy Kerr 
107133714881SJeremy Kerr 	dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
107233714881SJeremy Kerr 	dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
1073f00abd94SGrant Likely 
107433714881SJeremy Kerr 	prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
107533714881SJeremy Kerr 	if (prop)
1076f00abd94SGrant Likely 		dt_root_size_cells = be32_to_cpup(prop);
1077f00abd94SGrant Likely 	pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
1078f00abd94SGrant Likely 
107933714881SJeremy Kerr 	prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
108033714881SJeremy Kerr 	if (prop)
1081f00abd94SGrant Likely 		dt_root_addr_cells = be32_to_cpup(prop);
1082f00abd94SGrant Likely 	pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
1083d665881dSRob Herring 
1084f00abd94SGrant Likely 	return 0;
1085f00abd94SGrant Likely }
10869d0c4dfeSRob Herring 
dt_mem_next_cell(int s,const __be32 ** cellp)108783f7a06eSGrant Likely u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
10889d0c4dfeSRob Herring {
108983f7a06eSGrant Likely 	const __be32 *p = *cellp;
109083f7a06eSGrant Likely 
109183f7a06eSGrant Likely 	*cellp = p + s;
109283f7a06eSGrant Likely 	return of_read_number(p, s);
109383f7a06eSGrant Likely }
1094a300dc86SLee Jones 
10950ef5adcaSFrank Rowand /*
109651975db0SGrant Likely  * early_init_dt_scan_memory - Look for and parse memory nodes
10971f012283SRob Herring  */
early_init_dt_scan_memory(void)109851975db0SGrant Likely int __init early_init_dt_scan_memory(void)
10992a12187dSAndreas Rammhold {
11001f012283SRob Herring 	int node, found_memory = 0;
11011f012283SRob Herring 	const void *fdt = initial_boot_params;
11021f012283SRob Herring 
11039d0c4dfeSRob Herring 	fdt_for_each_subnode(node, fdt, 0) {
11049d0c4dfeSRob Herring 		const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
11059d0c4dfeSRob Herring 		const __be32 *reg, *endp;
110641a9ada3SReza Arbab 		int l;
110751975db0SGrant Likely 		bool hotpluggable;
110851975db0SGrant Likely 
1109da653130SMichael Ellerman 		/* We are scanning "memory" nodes only */
11101f012283SRob Herring 		if (type == NULL || strcmp(type, "memory") != 0)
111151975db0SGrant Likely 			continue;
1112df5cd369SAndre Przywara 
1113df5cd369SAndre Przywara 		if (!of_fdt_device_is_available(fdt, node))
1114df5cd369SAndre Przywara 			continue;
111551975db0SGrant Likely 
111651975db0SGrant Likely 		reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
111751975db0SGrant Likely 		if (reg == NULL)
111851975db0SGrant Likely 			reg = of_get_flat_dt_prop(node, "reg", &l);
11191f012283SRob Herring 		if (reg == NULL)
112051975db0SGrant Likely 			continue;
112151975db0SGrant Likely 
112241a9ada3SReza Arbab 		endp = reg + (l / sizeof(__be32));
112351975db0SGrant Likely 		hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL);
11241f012283SRob Herring 
11251f012283SRob Herring 		pr_debug("memory scan node %s, reg size %d,\n",
112651975db0SGrant Likely 			 fdt_get_name(fdt, node, NULL), l);
112751975db0SGrant Likely 
112851975db0SGrant Likely 		while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
112951975db0SGrant Likely 			u64 base, size;
113051975db0SGrant Likely 
113151975db0SGrant Likely 			base = dt_mem_next_cell(dt_root_addr_cells, &reg);
113251975db0SGrant Likely 			size = dt_mem_next_cell(dt_root_size_cells, &reg);
113351975db0SGrant Likely 
113451975db0SGrant Likely 			if (size == 0)
11350e407a9aSGeert Uytterhoeven 				continue;
113651975db0SGrant Likely 			pr_debug(" - %llx, %llx\n", base, size);
113751975db0SGrant Likely 
113841a9ada3SReza Arbab 			early_init_dt_add_memory_arch(base, size);
11392a12187dSAndreas Rammhold 
11402a12187dSAndreas Rammhold 			found_memory = 1;
114141a9ada3SReza Arbab 
114241a9ada3SReza Arbab 			if (!hotpluggable)
114341a9ada3SReza Arbab 				continue;
114439c6b3a3SGeert Uytterhoeven 
114541a9ada3SReza Arbab 			if (memblock_mark_hotplug(base, size))
114641a9ada3SReza Arbab 				pr_warn("failed to mark hotplug range 0x%llx - 0x%llx\n",
114751975db0SGrant Likely 					base, base + size);
11481f012283SRob Herring 		}
11492a12187dSAndreas Rammhold 	}
115051975db0SGrant Likely 	return found_memory;
115151975db0SGrant Likely }
115260f20d84SRob Herring 
early_init_dt_scan_chosen(char * cmdline)115386e03221SGrant Likely int __init early_init_dt_scan_chosen(char *cmdline)
115460f20d84SRob Herring {
11559d0c4dfeSRob Herring 	int l, node;
1156428826f5SHsin-Yi Wang 	const char *p;
115760f20d84SRob Herring 	const void *rng_seed;
115886e03221SGrant Likely 	const void *fdt = initial_boot_params;
115960f20d84SRob Herring 
116060f20d84SRob Herring 	node = fdt_path_offset(fdt, "/chosen");
116160f20d84SRob Herring 	if (node < 0)
116260f20d84SRob Herring 		node = fdt_path_offset(fdt, "/chosen@0");
1163064e32dcSRob Herring 	if (node < 0)
1164064e32dcSRob Herring 		/* Handle the cmdline config options even if no /chosen node */
116586e03221SGrant Likely 		goto handle_cmdline;
11668347b417SZhen Lei 
11678347b417SZhen Lei 	chosen_node_offset = node;
116886e03221SGrant Likely 
1169f7e7ce93SGeert Uytterhoeven 	early_init_dt_check_for_initrd(node);
117086e03221SGrant Likely 	early_init_dt_check_for_elfcorehdr(node);
1171064e32dcSRob Herring 
1172064e32dcSRob Herring 	rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
1173064e32dcSRob Herring 	if (rng_seed && l > 0) {
1174064e32dcSRob Herring 		add_bootloader_randomness(rng_seed, l);
1175064e32dcSRob Herring 
1176064e32dcSRob Herring 		/* try to clear seed so it won't be found. */
1177064e32dcSRob Herring 		fdt_nop_property(initial_boot_params, node, "rng-seed");
1178064e32dcSRob Herring 
1179064e32dcSRob Herring 		/* update CRC check value */
1180064e32dcSRob Herring 		of_fdt_crc32 = crc32_be(~0, initial_boot_params,
1181064e32dcSRob Herring 				fdt_totalsize(initial_boot_params));
1182064e32dcSRob Herring 	}
118325985edcSLucas De Marchi 
118486e03221SGrant Likely 	/* Retrieve command line */
118586e03221SGrant Likely 	p = of_get_flat_dt_prop(node, "bootargs", &l);
11867a12dd07SWolfram Sang 	if (p != NULL && l > 0)
118786e03221SGrant Likely 		strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE));
1188064e32dcSRob Herring 
1189bd0ddcfcSRob Herring handle_cmdline:
1190bd0ddcfcSRob Herring 	/*
1191bd0ddcfcSRob Herring 	 * CONFIG_CMDLINE is meant to be a default in case nothing else
1192bd0ddcfcSRob Herring 	 * managed to set the command line, unless CONFIG_CMDLINE_FORCE
1193bd0ddcfcSRob Herring 	 * is set in which case we override whatever was found earlier.
1194bd0ddcfcSRob Herring 	 */
1195bd0ddcfcSRob Herring #ifdef CONFIG_CMDLINE
1196bd0ddcfcSRob Herring #if defined(CONFIG_CMDLINE_EXTEND)
1197bd0ddcfcSRob Herring 	strlcat(cmdline, " ", COMMAND_LINE_SIZE);
1198bd0ddcfcSRob Herring 	strlcat(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
1199bd0ddcfcSRob Herring #elif defined(CONFIG_CMDLINE_FORCE)
1200bd0ddcfcSRob Herring 	strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
1201bd0ddcfcSRob Herring #else
1202bd0ddcfcSRob Herring 	/* No arguments from boot loader, use kernel's  cmdl*/
1203bd0ddcfcSRob Herring 	if (!((char *)cmdline)[0])
1204bd0ddcfcSRob Herring 		strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
1205bd0ddcfcSRob Herring #endif
1206bd0ddcfcSRob Herring #endif /* CONFIG_CMDLINE */
1207bd0ddcfcSRob Herring 
1208bd0ddcfcSRob Herring 	pr_debug("Command line is: %s\n", (char *)cmdline);
120960f20d84SRob Herring 
121086e03221SGrant Likely 	return 0;
121186e03221SGrant Likely }
1212270522a0SArd Biesheuvel 
1213270522a0SArd Biesheuvel #ifndef MIN_MEMBLOCK_ADDR
1214270522a0SArd Biesheuvel #define MIN_MEMBLOCK_ADDR	__pa(PAGE_OFFSET)
12158eafeb48SArd Biesheuvel #endif
12168eafeb48SArd Biesheuvel #ifndef MAX_MEMBLOCK_ADDR
12178eafeb48SArd Biesheuvel #define MAX_MEMBLOCK_ADDR	((phys_addr_t)~0)
12183069f0c0SLaura Abbott #endif
1219068f6310SRob Herring 
early_init_dt_add_memory_arch(u64 base,u64 size)1220068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
1221270522a0SArd Biesheuvel {
12228f73d4b7SGeert Uytterhoeven 	const u64 phys_offset = MIN_MEMBLOCK_ADDR;
12238cccffc5SArd Biesheuvel 
12248cccffc5SArd Biesheuvel 	if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
12258cccffc5SArd Biesheuvel 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
12268cccffc5SArd Biesheuvel 			base, base + size);
12278cccffc5SArd Biesheuvel 		return;
12286072cf56SMike Rapoport 	}
12296072cf56SMike Rapoport 
12308f73d4b7SGeert Uytterhoeven 	if (!PAGE_ALIGNED(base)) {
12318f73d4b7SGeert Uytterhoeven 		size -= PAGE_SIZE - (base & ~PAGE_MASK);
12328f73d4b7SGeert Uytterhoeven 		base = PAGE_ALIGN(base);
1233068f6310SRob Herring 	}
1234a67a6ed1SLaura Abbott 	size &= PAGE_MASK;
12358eafeb48SArd Biesheuvel 
1236e2f04da7SKefeng Wang 	if (base > MAX_MEMBLOCK_ADDR) {
1237a67a6ed1SLaura Abbott 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
1238a67a6ed1SLaura Abbott 			base, base + size);
1239a67a6ed1SLaura Abbott 		return;
1240a67a6ed1SLaura Abbott 	}
12418eafeb48SArd Biesheuvel 
1242e2f04da7SKefeng Wang 	if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
12438eafeb48SArd Biesheuvel 		pr_warn("Ignoring memory range 0x%llx - 0x%llx\n",
12448eafeb48SArd Biesheuvel 			((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
1245a67a6ed1SLaura Abbott 		size = MAX_MEMBLOCK_ADDR - base + 1;
1246a67a6ed1SLaura Abbott 	}
1247068f6310SRob Herring 
1248e2f04da7SKefeng Wang 	if (base + size < phys_offset) {
1249068f6310SRob Herring 		pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
1250068f6310SRob Herring 			base, base + size);
1251068f6310SRob Herring 		return;
1252068f6310SRob Herring 	}
1253e2f04da7SKefeng Wang 	if (base < phys_offset) {
1254068f6310SRob Herring 		pr_warn("Ignoring memory range 0x%llx - 0x%llx\n",
1255068f6310SRob Herring 			base, phys_offset);
1256068f6310SRob Herring 		size -= phys_offset - base;
1257068f6310SRob Herring 		base = phys_offset;
1258068f6310SRob Herring 	}
1259068f6310SRob Herring 	memblock_add(base, size);
1260068f6310SRob Herring }
12610fa1c579SRob Herring 
early_init_dt_alloc_memory_arch(u64 size,u64 align)12620fa1c579SRob Herring static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
12638a7f97b9SMike Rapoport {
12648a7f97b9SMike Rapoport 	void *ptr = memblock_alloc(size, align);
12658a7f97b9SMike Rapoport 
12668a7f97b9SMike Rapoport 	if (!ptr)
12678a7f97b9SMike Rapoport 		panic("%s: Failed to allocate %llu bytes align=0x%llx\n",
12688a7f97b9SMike Rapoport 		      __func__, size, align);
12698a7f97b9SMike Rapoport 
12700fa1c579SRob Herring 	return ptr;
12710fa1c579SRob Herring }
12724972a74bSLaura Abbott 
early_init_dt_verify(void * params)12730288ffcbSRob Herring bool __init early_init_dt_verify(void *params)
12740288ffcbSRob Herring {
12750288ffcbSRob Herring 	if (!params)
12760288ffcbSRob Herring 		return false;
127750ba08f3SBjorn Helgaas 
127850ba08f3SBjorn Helgaas 	/* check device tree validity */
127950ba08f3SBjorn Helgaas 	if (fdt_check_header(params))
128050ba08f3SBjorn Helgaas 		return false;
12810288ffcbSRob Herring 
12820288ffcbSRob Herring 	/* Setup flat device-tree pointer */
1283dd753d96SHsin-Yi Wang 	initial_boot_params = params;
1284dd753d96SHsin-Yi Wang 	of_fdt_crc32 = crc32_be(~0, initial_boot_params,
12854972a74bSLaura Abbott 				fdt_totalsize(initial_boot_params));
12864972a74bSLaura Abbott 	return true;
12874972a74bSLaura Abbott }
12884972a74bSLaura Abbott 
12894972a74bSLaura Abbott 
early_init_dt_scan_nodes(void)12904972a74bSLaura Abbott void __init early_init_dt_scan_nodes(void)
129160f20d84SRob Herring {
1292e1e52544SNick Kossifidis 	int rc;
1293f7e7ce93SGeert Uytterhoeven 
1294d665881dSRob Herring 	/* Initialize {size,address}-cells info */
1295f7e7ce93SGeert Uytterhoeven 	early_init_dt_scan_root();
12960288ffcbSRob Herring 
129760f20d84SRob Herring 	/* Retrieve various information from the /chosen node */
129860f20d84SRob Herring 	rc = early_init_dt_scan_chosen(boot_command_line);
1299e1e52544SNick Kossifidis 	if (rc)
13000288ffcbSRob Herring 		pr_warn("No chosen node found, continuing without\n");
13010288ffcbSRob Herring 
13021f012283SRob Herring 	/* Setup memory, calling early_init_dt_add_memory_arch */
13032af2b50aSGeert Uytterhoeven 	early_init_dt_scan_memory();
13042af2b50aSGeert Uytterhoeven 
13058347b417SZhen Lei 	/* Handle linux,usable-memory-range property */
13064972a74bSLaura Abbott 	early_init_dt_check_for_usable_mem_range();
13070288ffcbSRob Herring }
13084972a74bSLaura Abbott 
early_init_dt_scan(void * params)13094972a74bSLaura Abbott bool __init early_init_dt_scan(void *params)
13104972a74bSLaura Abbott {
13114972a74bSLaura Abbott 	bool status;
13124972a74bSLaura Abbott 
13134972a74bSLaura Abbott 	status = early_init_dt_verify(params);
13144972a74bSLaura Abbott 	if (!status)
13154972a74bSLaura Abbott 		return false;
13164972a74bSLaura Abbott 
13170288ffcbSRob Herring 	early_init_dt_scan_nodes();
13180288ffcbSRob Herring 	return true;
13190288ffcbSRob Herring }
1320f00abd94SGrant Likely 
132141f88009SGrant Likely /**
132241f88009SGrant Likely  * unflatten_device_tree - create tree of device_nodes from flat blob
132341f88009SGrant Likely  *
132441f88009SGrant Likely  * unflattens the device-tree passed by the firmware, creating the
132541f88009SGrant Likely  * tree of struct device_node. It also fills the "name" and "type"
132641f88009SGrant Likely  * pointers of the nodes so the normal device-tree walking functions
132741f88009SGrant Likely  * can be used.
132841f88009SGrant Likely  */
unflatten_device_tree(void)132941f88009SGrant Likely void __init unflatten_device_tree(void)
1330c4263233SGavin Shan {
13311d1bde55SMichal Suchanek 	__unflatten_device_tree(initial_boot_params, NULL, &of_root,
133241f88009SGrant Likely 				early_init_dt_alloc_memory_arch, false);
13334c7d6361SRobert P. J. Day 
1334611cad72SShawn Guo 	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
133581d0848fSFrank Rowand 	of_alias_scan(early_init_dt_alloc_memory_arch);
133681d0848fSFrank Rowand 
133741f88009SGrant Likely 	unittest_unflatten_overlay_base();
1338e6ce1324SStephen Neuendorffer }
1339a8bf7527SRob Herring 
1340a8bf7527SRob Herring /**
1341a8bf7527SRob Herring  * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob
1342a8bf7527SRob Herring  *
1343a8bf7527SRob Herring  * Copies and unflattens the device-tree passed by the firmware, creating the
1344a8bf7527SRob Herring  * tree of struct device_node. It also fills the "name" and "type"
1345a8bf7527SRob Herring  * pointers of the nodes so the normal device-tree walking functions
1346a8bf7527SRob Herring  * can be used. This should only be used when the FDT memory has not been
1347a8bf7527SRob Herring  * reserved such is the case when the FDT is built-in to the kernel init
1348a8bf7527SRob Herring  * section. If the FDT memory is reserved already then unflatten_device_tree
1349a8bf7527SRob Herring  * should be used instead.
1350a8bf7527SRob Herring  */
unflatten_and_copy_device_tree(void)1351a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void)
13526f041e99SJames Hogan {
13536f041e99SJames Hogan 	int size;
13546f041e99SJames Hogan 	void *dt;
13556f041e99SJames Hogan 
13566f041e99SJames Hogan 	if (!initial_boot_params) {
13576f041e99SJames Hogan 		pr_warn("No valid device tree found, continuing without\n");
13586f041e99SJames Hogan 		return;
13596f041e99SJames Hogan 	}
1360c972de14SRob Herring 
13616f041e99SJames Hogan 	size = fdt_totalsize(initial_boot_params);
1362c972de14SRob Herring 	dt = early_init_dt_alloc_memory_arch(size,
1363a8bf7527SRob Herring 					     roundup_pow_of_two(FDT_V17_SIZE));
1364a8bf7527SRob Herring 
1365a8bf7527SRob Herring 	if (dt) {
1366a8bf7527SRob Herring 		memcpy(dt, initial_boot_params, size);
1367a8bf7527SRob Herring 		initial_boot_params = dt;
1368a8bf7527SRob Herring 	}
1369a8bf7527SRob Herring 	unflatten_device_tree();
1370a8bf7527SRob Herring }
137108d53aa5SArd Biesheuvel 
137208d53aa5SArd Biesheuvel #ifdef CONFIG_SYSFS
of_fdt_raw_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)137308d53aa5SArd Biesheuvel static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj,
137408d53aa5SArd Biesheuvel 			       struct bin_attribute *bin_attr,
1375b0a6fb36SRob Herring 			       char *buf, loff_t off, size_t count)
137608d53aa5SArd Biesheuvel {
137708d53aa5SArd Biesheuvel 	memcpy(buf, initial_boot_params + off, count);
137808d53aa5SArd Biesheuvel 	return count;
1379b0a6fb36SRob Herring }
138008d53aa5SArd Biesheuvel 
of_fdt_raw_init(void)138108d53aa5SArd Biesheuvel static int __init of_fdt_raw_init(void)
138208d53aa5SArd Biesheuvel {
138308d53aa5SArd Biesheuvel 	static struct bin_attribute of_fdt_raw_attr =
1384b0a6fb36SRob Herring 		__BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0);
138508d53aa5SArd Biesheuvel 
138608d53aa5SArd Biesheuvel 	if (!initial_boot_params)
1387b0a6fb36SRob Herring 		return 0;
138808d53aa5SArd Biesheuvel 
138908d53aa5SArd Biesheuvel 	if (of_fdt_crc32 != crc32_be(~0, initial_boot_params,
1390606ad42aSRob Herring 				     fdt_totalsize(initial_boot_params))) {
1391b0a6fb36SRob Herring 		pr_warn("not creating '/sys/firmware/fdt': CRC check failed\n");
1392b0a6fb36SRob Herring 		return 0;
139308d53aa5SArd Biesheuvel 	}
139408d53aa5SArd Biesheuvel 	of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params);
139508d53aa5SArd Biesheuvel 	return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr);
139608d53aa5SArd Biesheuvel }
1397b0a6fb36SRob Herring late_initcall(of_fdt_raw_init);
1398b0a6fb36SRob Herring #endif
1399e6ce1324SStephen Neuendorffer 
1400 #endif /* CONFIG_OF_EARLY_FLATTREE */
1401