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