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, ®);
113251975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®);
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