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 1108d53aa5SArd Biesheuvel #include <linux/crc32.h> 1241f88009SGrant Likely #include <linux/kernel.h> 13f7b3a835SGrant Likely #include <linux/initrd.h> 14a1727da5SGrant Likely #include <linux/memblock.h> 15f8062386SGuenter Roeck #include <linux/mutex.h> 16e169cfbeSGrant Likely #include <linux/of.h> 17e169cfbeSGrant Likely #include <linux/of_fdt.h> 183f0c8206SMarek Szyprowski #include <linux/of_reserved_mem.h> 19e8d9d1f5SMarek Szyprowski #include <linux/sizes.h> 204ef7b373SJeremy Kerr #include <linux/string.h> 214ef7b373SJeremy Kerr #include <linux/errno.h> 22fe140423SStephen Neuendorffer #include <linux/slab.h> 23e6a6928cSRob Herring #include <linux/libfdt.h> 24b0a6fb36SRob Herring #include <linux/debugfs.h> 25fb11ffe7SRob Herring #include <linux/serial_core.h> 2608d53aa5SArd Biesheuvel #include <linux/sysfs.h> 2751975db0SGrant Likely 28c89810acSFabio Estevam #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 294ef7b373SJeremy Kerr #include <asm/page.h> 304ef7b373SJeremy Kerr 3181d0848fSFrank Rowand #include "of_private.h" 3281d0848fSFrank Rowand 33704033ceSLaura Abbott /* 34704033ceSLaura Abbott * of_fdt_limit_memory - limit the number of regions in the /memory node 35704033ceSLaura Abbott * @limit: maximum entries 36704033ceSLaura Abbott * 37704033ceSLaura Abbott * Adjust the flattened device tree to have at most 'limit' number of 38704033ceSLaura Abbott * memory entries in the /memory node. This function may be called 39704033ceSLaura Abbott * any time after initial_boot_param is set. 40704033ceSLaura Abbott */ 419b4d2b63SStephen Boyd void __init of_fdt_limit_memory(int limit) 42704033ceSLaura Abbott { 43704033ceSLaura Abbott int memory; 44704033ceSLaura Abbott int len; 45704033ceSLaura Abbott const void *val; 46704033ceSLaura Abbott int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 47704033ceSLaura Abbott int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 4817a70355SRob Herring const __be32 *addr_prop; 4917a70355SRob Herring const __be32 *size_prop; 50704033ceSLaura Abbott int root_offset; 51704033ceSLaura Abbott int cell_size; 52704033ceSLaura Abbott 53704033ceSLaura Abbott root_offset = fdt_path_offset(initial_boot_params, "/"); 54704033ceSLaura Abbott if (root_offset < 0) 55704033ceSLaura Abbott return; 56704033ceSLaura Abbott 57704033ceSLaura Abbott addr_prop = fdt_getprop(initial_boot_params, root_offset, 58704033ceSLaura Abbott "#address-cells", NULL); 59704033ceSLaura Abbott if (addr_prop) 60704033ceSLaura Abbott nr_address_cells = fdt32_to_cpu(*addr_prop); 61704033ceSLaura Abbott 62704033ceSLaura Abbott size_prop = fdt_getprop(initial_boot_params, root_offset, 63704033ceSLaura Abbott "#size-cells", NULL); 64704033ceSLaura Abbott if (size_prop) 65704033ceSLaura Abbott nr_size_cells = fdt32_to_cpu(*size_prop); 66704033ceSLaura Abbott 67704033ceSLaura Abbott cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells); 68704033ceSLaura Abbott 69704033ceSLaura Abbott memory = fdt_path_offset(initial_boot_params, "/memory"); 70704033ceSLaura Abbott if (memory > 0) { 71704033ceSLaura Abbott val = fdt_getprop(initial_boot_params, memory, "reg", &len); 72704033ceSLaura Abbott if (len > limit*cell_size) { 73704033ceSLaura Abbott len = limit*cell_size; 74704033ceSLaura Abbott pr_debug("Limiting number of entries to %d\n", limit); 75704033ceSLaura Abbott fdt_setprop(initial_boot_params, memory, "reg", val, 76704033ceSLaura Abbott len); 77704033ceSLaura Abbott } 78704033ceSLaura Abbott } 79704033ceSLaura Abbott } 80704033ceSLaura Abbott 81ecc8a96eSRob Herring static bool of_fdt_device_is_available(const void *blob, unsigned long node) 82ecc8a96eSRob Herring { 83ecc8a96eSRob Herring const char *status = fdt_getprop(blob, node, "status", NULL); 84ecc8a96eSRob Herring 85ecc8a96eSRob Herring if (!status) 86ecc8a96eSRob Herring return true; 87ecc8a96eSRob Herring 88ecc8a96eSRob Herring if (!strcmp(status, "ok") || !strcmp(status, "okay")) 89ecc8a96eSRob Herring return true; 90ecc8a96eSRob Herring 91ecc8a96eSRob Herring return false; 92ecc8a96eSRob Herring } 93ecc8a96eSRob Herring 9444856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size, 95bbd33931SGrant Likely unsigned long align) 96bbd33931SGrant Likely { 97bbd33931SGrant Likely void *res; 98bbd33931SGrant Likely 9944856819SGrant Likely *mem = PTR_ALIGN(*mem, align); 10044856819SGrant Likely res = *mem; 101bbd33931SGrant Likely *mem += size; 102bbd33931SGrant Likely 103bbd33931SGrant Likely return res; 104bbd33931SGrant Likely } 105bbd33931SGrant Likely 106dfbd4c6eSGavin Shan static void populate_properties(const void *blob, 107dfbd4c6eSGavin Shan int offset, 108dfbd4c6eSGavin Shan void **mem, 109dfbd4c6eSGavin Shan struct device_node *np, 110dfbd4c6eSGavin Shan const char *nodename, 1115063e25aSGrant Likely bool dryrun) 112bbd33931SGrant Likely { 113dfbd4c6eSGavin Shan struct property *pp, **pprev = NULL; 114dfbd4c6eSGavin Shan int cur; 115dfbd4c6eSGavin Shan bool has_name = false; 116dfbd4c6eSGavin Shan 117dfbd4c6eSGavin Shan pprev = &np->properties; 118dfbd4c6eSGavin Shan for (cur = fdt_first_property_offset(blob, offset); 119dfbd4c6eSGavin Shan cur >= 0; 120dfbd4c6eSGavin Shan cur = fdt_next_property_offset(blob, cur)) { 121dfbd4c6eSGavin Shan const __be32 *val; 122dfbd4c6eSGavin Shan const char *pname; 123dfbd4c6eSGavin Shan u32 sz; 124dfbd4c6eSGavin Shan 125dfbd4c6eSGavin Shan val = fdt_getprop_by_offset(blob, cur, &pname, &sz); 126dfbd4c6eSGavin Shan if (!val) { 127606ad42aSRob Herring pr_warn("Cannot locate property at 0x%x\n", cur); 128dfbd4c6eSGavin Shan continue; 129dfbd4c6eSGavin Shan } 130dfbd4c6eSGavin Shan 131dfbd4c6eSGavin Shan if (!pname) { 132606ad42aSRob Herring pr_warn("Cannot find property name at 0x%x\n", cur); 133dfbd4c6eSGavin Shan continue; 134dfbd4c6eSGavin Shan } 135dfbd4c6eSGavin Shan 136dfbd4c6eSGavin Shan if (!strcmp(pname, "name")) 137dfbd4c6eSGavin Shan has_name = true; 138dfbd4c6eSGavin Shan 139dfbd4c6eSGavin Shan pp = unflatten_dt_alloc(mem, sizeof(struct property), 140dfbd4c6eSGavin Shan __alignof__(struct property)); 141dfbd4c6eSGavin Shan if (dryrun) 142dfbd4c6eSGavin Shan continue; 143dfbd4c6eSGavin Shan 144dfbd4c6eSGavin Shan /* We accept flattened tree phandles either in 145dfbd4c6eSGavin Shan * ePAPR-style "phandle" properties, or the 146dfbd4c6eSGavin Shan * legacy "linux,phandle" properties. If both 147dfbd4c6eSGavin Shan * appear and have different values, things 148dfbd4c6eSGavin Shan * will get weird. Don't do that. 149dfbd4c6eSGavin Shan */ 150dfbd4c6eSGavin Shan if (!strcmp(pname, "phandle") || 151dfbd4c6eSGavin Shan !strcmp(pname, "linux,phandle")) { 152dfbd4c6eSGavin Shan if (!np->phandle) 153dfbd4c6eSGavin Shan np->phandle = be32_to_cpup(val); 154dfbd4c6eSGavin Shan } 155dfbd4c6eSGavin Shan 156dfbd4c6eSGavin Shan /* And we process the "ibm,phandle" property 157dfbd4c6eSGavin Shan * used in pSeries dynamic device tree 158dfbd4c6eSGavin Shan * stuff 159dfbd4c6eSGavin Shan */ 160dfbd4c6eSGavin Shan if (!strcmp(pname, "ibm,phandle")) 161dfbd4c6eSGavin Shan np->phandle = be32_to_cpup(val); 162dfbd4c6eSGavin Shan 163dfbd4c6eSGavin Shan pp->name = (char *)pname; 164dfbd4c6eSGavin Shan pp->length = sz; 165dfbd4c6eSGavin Shan pp->value = (__be32 *)val; 166dfbd4c6eSGavin Shan *pprev = pp; 167dfbd4c6eSGavin Shan pprev = &pp->next; 168dfbd4c6eSGavin Shan } 169dfbd4c6eSGavin Shan 170dfbd4c6eSGavin Shan /* With version 0x10 we may not have the name property, 171dfbd4c6eSGavin Shan * recreate it here from the unit name if absent 172dfbd4c6eSGavin Shan */ 173dfbd4c6eSGavin Shan if (!has_name) { 174dfbd4c6eSGavin Shan const char *p = nodename, *ps = p, *pa = NULL; 175dfbd4c6eSGavin Shan int len; 176dfbd4c6eSGavin Shan 177dfbd4c6eSGavin Shan while (*p) { 178dfbd4c6eSGavin Shan if ((*p) == '@') 179dfbd4c6eSGavin Shan pa = p; 180dfbd4c6eSGavin Shan else if ((*p) == '/') 181dfbd4c6eSGavin Shan ps = p + 1; 182dfbd4c6eSGavin Shan p++; 183dfbd4c6eSGavin Shan } 184dfbd4c6eSGavin Shan 185dfbd4c6eSGavin Shan if (pa < ps) 186dfbd4c6eSGavin Shan pa = p; 187dfbd4c6eSGavin Shan len = (pa - ps) + 1; 188dfbd4c6eSGavin Shan pp = unflatten_dt_alloc(mem, sizeof(struct property) + len, 189dfbd4c6eSGavin Shan __alignof__(struct property)); 190dfbd4c6eSGavin Shan if (!dryrun) { 191dfbd4c6eSGavin Shan pp->name = "name"; 192dfbd4c6eSGavin Shan pp->length = len; 193dfbd4c6eSGavin Shan pp->value = pp + 1; 194dfbd4c6eSGavin Shan *pprev = pp; 195dfbd4c6eSGavin Shan pprev = &pp->next; 196dfbd4c6eSGavin Shan memcpy(pp->value, ps, len - 1); 197dfbd4c6eSGavin Shan ((char *)pp->value)[len - 1] = 0; 198dfbd4c6eSGavin Shan pr_debug("fixed up name for %s -> %s\n", 199dfbd4c6eSGavin Shan nodename, (char *)pp->value); 200dfbd4c6eSGavin Shan } 201dfbd4c6eSGavin Shan } 202dfbd4c6eSGavin Shan 203dfbd4c6eSGavin Shan if (!dryrun) 204dfbd4c6eSGavin Shan *pprev = NULL; 205dfbd4c6eSGavin Shan } 206dfbd4c6eSGavin Shan 207a7e4cfb0SRob Herring static bool populate_node(const void *blob, 208dfbd4c6eSGavin Shan int offset, 209dfbd4c6eSGavin Shan void **mem, 210dfbd4c6eSGavin Shan struct device_node *dad, 211dfbd4c6eSGavin Shan struct device_node **pnp, 212dfbd4c6eSGavin Shan bool dryrun) 213dfbd4c6eSGavin Shan { 214bbd33931SGrant Likely struct device_node *np; 215e6a6928cSRob Herring const char *pathp; 216bbd33931SGrant Likely unsigned int l, allocl; 217bbd33931SGrant Likely 218dfbd4c6eSGavin Shan pathp = fdt_get_name(blob, offset, &l); 219dfbd4c6eSGavin Shan if (!pathp) { 220dfbd4c6eSGavin Shan *pnp = NULL; 221a7e4cfb0SRob Herring return false; 222dfbd4c6eSGavin Shan } 223e6a6928cSRob Herring 22405f4647bSRicky Liang allocl = ++l; 225bbd33931SGrant Likely 226dfbd4c6eSGavin Shan np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl, 227bbd33931SGrant Likely __alignof__(struct device_node)); 2285063e25aSGrant Likely if (!dryrun) { 229c22618a1SGrant Likely char *fn; 2300829f6d1SPantelis Antoniou of_node_init(np); 231c22618a1SGrant Likely np->full_name = fn = ((char *)np) + sizeof(*np); 232a7e4cfb0SRob Herring 233bbd33931SGrant Likely memcpy(fn, pathp, l); 234c22618a1SGrant Likely 235bbd33931SGrant Likely if (dad != NULL) { 236bbd33931SGrant Likely np->parent = dad; 23770161ff3SGrant Likely np->sibling = dad->child; 238bbd33931SGrant Likely dad->child = np; 239bbd33931SGrant Likely } 240bbd33931SGrant Likely } 241bbd33931SGrant Likely 242dfbd4c6eSGavin Shan populate_properties(blob, offset, mem, np, pathp, dryrun); 2435063e25aSGrant Likely if (!dryrun) { 244bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 245bbd33931SGrant Likely if (!np->name) 246bbd33931SGrant Likely np->name = "<NULL>"; 247bbd33931SGrant Likely } 248e6a6928cSRob Herring 249dfbd4c6eSGavin Shan *pnp = np; 250a7e4cfb0SRob Herring return true; 251dfbd4c6eSGavin Shan } 252dfbd4c6eSGavin Shan 25350800082SGavin Shan static void reverse_nodes(struct device_node *parent) 25450800082SGavin Shan { 25550800082SGavin Shan struct device_node *child, *next; 25650800082SGavin Shan 25750800082SGavin Shan /* In-depth first */ 25850800082SGavin Shan child = parent->child; 25950800082SGavin Shan while (child) { 26050800082SGavin Shan reverse_nodes(child); 26150800082SGavin Shan 26250800082SGavin Shan child = child->sibling; 26350800082SGavin Shan } 26450800082SGavin Shan 26550800082SGavin Shan /* Reverse the nodes in the child list */ 26650800082SGavin Shan child = parent->child; 26750800082SGavin Shan parent->child = NULL; 26850800082SGavin Shan while (child) { 26950800082SGavin Shan next = child->sibling; 27050800082SGavin Shan 27150800082SGavin Shan child->sibling = parent->child; 27250800082SGavin Shan parent->child = child; 27350800082SGavin Shan child = next; 27450800082SGavin Shan } 27550800082SGavin Shan } 27650800082SGavin Shan 277dfbd4c6eSGavin Shan /** 278947c82cbSGavin Shan * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree 279dfbd4c6eSGavin Shan * @blob: The parent device tree blob 280dfbd4c6eSGavin Shan * @mem: Memory chunk to use for allocating device nodes and properties 281dfbd4c6eSGavin Shan * @dad: Parent struct device_node 282dfbd4c6eSGavin Shan * @nodepp: The device_node tree created by the call 28350800082SGavin Shan * 28450800082SGavin Shan * It returns the size of unflattened device tree or error code 285dfbd4c6eSGavin Shan */ 286947c82cbSGavin Shan static int unflatten_dt_nodes(const void *blob, 287dfbd4c6eSGavin Shan void *mem, 288dfbd4c6eSGavin Shan struct device_node *dad, 28950800082SGavin Shan struct device_node **nodepp) 290dfbd4c6eSGavin Shan { 29150800082SGavin Shan struct device_node *root; 2928c237cd0SGavin Shan int offset = 0, depth = 0, initial_depth = 0; 29350800082SGavin Shan #define FDT_MAX_DEPTH 64 29450800082SGavin Shan struct device_node *nps[FDT_MAX_DEPTH]; 29550800082SGavin Shan void *base = mem; 29650800082SGavin Shan bool dryrun = !base; 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)) { 31750800082SGavin Shan if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH)) 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 324a7e4cfb0SRob Herring if (!populate_node(blob, offset, &mem, nps[depth], 325a7e4cfb0SRob Herring &nps[depth+1], dryrun)) 32650800082SGavin Shan return mem - base; 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 * 352fe140423SStephen Neuendorffer * unflattens a device-tree, creating the 353fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 354fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 355fe140423SStephen Neuendorffer * can be used. 356fe140423SStephen Neuendorffer * @blob: The blob to expand 357c4263233SGavin Shan * @dad: Parent device node 358fe140423SStephen Neuendorffer * @mynodes: The device_node tree created by the call 359fe140423SStephen Neuendorffer * @dt_alloc: An allocator that provides a virtual address to memory 360fe140423SStephen Neuendorffer * for the resulting tree 361f5d2da67SStephen Boyd * @detached: if true set OF_DETACHED on @mynodes 36283262418SGavin Shan * 36383262418SGavin Shan * Returns 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; 374fe140423SStephen Neuendorffer 375fe140423SStephen Neuendorffer pr_debug(" -> unflatten_device_tree()\n"); 376fe140423SStephen Neuendorffer 377fe140423SStephen Neuendorffer if (!blob) { 378fe140423SStephen Neuendorffer pr_debug("No device tree pointer\n"); 37983262418SGavin Shan return NULL; 380fe140423SStephen Neuendorffer } 381fe140423SStephen Neuendorffer 382fe140423SStephen Neuendorffer pr_debug("Unflattening device tree:\n"); 383c972de14SRob Herring pr_debug("magic: %08x\n", fdt_magic(blob)); 384c972de14SRob Herring pr_debug("size: %08x\n", fdt_totalsize(blob)); 385c972de14SRob Herring pr_debug("version: %08x\n", fdt_version(blob)); 386fe140423SStephen Neuendorffer 387c972de14SRob Herring if (fdt_check_header(blob)) { 388fe140423SStephen Neuendorffer pr_err("Invalid device tree blob header\n"); 38983262418SGavin Shan return NULL; 390fe140423SStephen Neuendorffer } 391fe140423SStephen Neuendorffer 392fe140423SStephen Neuendorffer /* First pass, scan for size */ 393c4263233SGavin Shan size = unflatten_dt_nodes(blob, NULL, dad, NULL); 39450800082SGavin Shan if (size < 0) 39583262418SGavin Shan return NULL; 396fe140423SStephen Neuendorffer 39750800082SGavin Shan size = ALIGN(size, 4); 39850800082SGavin Shan pr_debug(" size is %d, allocating...\n", size); 399fe140423SStephen Neuendorffer 400fe140423SStephen Neuendorffer /* Allocate memory for the expanded device tree */ 40144856819SGrant Likely mem = dt_alloc(size + 4, __alignof__(struct device_node)); 40249e67dd1SJohan Hovold if (!mem) 40349e67dd1SJohan Hovold return NULL; 40449e67dd1SJohan Hovold 40544856819SGrant Likely memset(mem, 0, size); 406fe140423SStephen Neuendorffer 40744856819SGrant Likely *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 4089e401275SWladislav Wiebe 40944856819SGrant Likely pr_debug(" unflattening %p...\n", mem); 410fe140423SStephen Neuendorffer 411fe140423SStephen Neuendorffer /* Second pass, do actual unflattening */ 412c4263233SGavin Shan unflatten_dt_nodes(blob, mem, dad, mynodes); 41344856819SGrant Likely if (be32_to_cpup(mem + size) != 0xdeadbeef) 414fe140423SStephen Neuendorffer pr_warning("End of tree marker overwritten: %08x\n", 41544856819SGrant Likely be32_to_cpup(mem + size)); 416fe140423SStephen Neuendorffer 41789c67752SGavin Shan if (detached && mynodes) { 4181d1bde55SMichal Suchanek of_node_set_flag(*mynodes, OF_DETACHED); 4191d1bde55SMichal Suchanek pr_debug("unflattened tree is detached\n"); 4201d1bde55SMichal Suchanek } 4211d1bde55SMichal Suchanek 422fe140423SStephen Neuendorffer pr_debug(" <- unflatten_device_tree()\n"); 42383262418SGavin Shan return mem; 424fe140423SStephen Neuendorffer } 425fe140423SStephen Neuendorffer 426fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align) 427fe140423SStephen Neuendorffer { 428fe140423SStephen Neuendorffer return kzalloc(size, GFP_KERNEL); 429fe140423SStephen Neuendorffer } 430fe140423SStephen Neuendorffer 431f8062386SGuenter Roeck static DEFINE_MUTEX(of_fdt_unflatten_mutex); 432f8062386SGuenter Roeck 433fe140423SStephen Neuendorffer /** 434fe140423SStephen Neuendorffer * of_fdt_unflatten_tree - create tree of device_nodes from flat blob 435c4263233SGavin Shan * @blob: Flat device tree blob 436c4263233SGavin Shan * @dad: Parent device node 437c4263233SGavin Shan * @mynodes: The device tree created by the call 438fe140423SStephen Neuendorffer * 439fe140423SStephen Neuendorffer * unflattens the device-tree passed by the firmware, creating the 440fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 441fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 442fe140423SStephen Neuendorffer * can be used. 44383262418SGavin Shan * 44483262418SGavin Shan * Returns NULL on failure or the memory chunk containing the unflattened 44583262418SGavin Shan * device tree on success. 446fe140423SStephen Neuendorffer */ 44783262418SGavin Shan void *of_fdt_unflatten_tree(const unsigned long *blob, 448c4263233SGavin Shan struct device_node *dad, 449fe140423SStephen Neuendorffer struct device_node **mynodes) 450fe140423SStephen Neuendorffer { 45183262418SGavin Shan void *mem; 45283262418SGavin Shan 453f8062386SGuenter Roeck mutex_lock(&of_fdt_unflatten_mutex); 4541d1bde55SMichal Suchanek mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc, 4551d1bde55SMichal Suchanek true); 456f8062386SGuenter Roeck mutex_unlock(&of_fdt_unflatten_mutex); 45783262418SGavin Shan 45883262418SGavin Shan return mem; 459fe140423SStephen Neuendorffer } 460fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); 461fe140423SStephen Neuendorffer 46257d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */ 46357d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells; 46457d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells; 46557d00ecfSStephen Neuendorffer 4667c71650fSStephen Boyd void *initial_boot_params __ro_after_init; 46757d00ecfSStephen Neuendorffer 46857d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE 46957d00ecfSStephen Neuendorffer 47008d53aa5SArd Biesheuvel static u32 of_fdt_crc32; 47108d53aa5SArd Biesheuvel 47257d00ecfSStephen Neuendorffer /** 473e8d9d1f5SMarek Szyprowski * res_mem_reserve_reg() - reserve all memory described in 'reg' property 474e8d9d1f5SMarek Szyprowski */ 475e8d9d1f5SMarek Szyprowski static int __init __reserved_mem_reserve_reg(unsigned long node, 476e8d9d1f5SMarek Szyprowski const char *uname) 477e8d9d1f5SMarek Szyprowski { 478e8d9d1f5SMarek Szyprowski int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); 479e8d9d1f5SMarek Szyprowski phys_addr_t base, size; 4809d0c4dfeSRob Herring int len; 4819d0c4dfeSRob Herring const __be32 *prop; 4825c68b823SMasahiro Yamada int first = 1; 4835c68b823SMasahiro Yamada bool nomap; 484e8d9d1f5SMarek Szyprowski 485e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "reg", &len); 486e8d9d1f5SMarek Szyprowski if (!prop) 487e8d9d1f5SMarek Szyprowski return -ENOENT; 488e8d9d1f5SMarek Szyprowski 489e8d9d1f5SMarek Szyprowski if (len && len % t_len != 0) { 490e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", 491e8d9d1f5SMarek Szyprowski uname); 492e8d9d1f5SMarek Szyprowski return -EINVAL; 493e8d9d1f5SMarek Szyprowski } 494e8d9d1f5SMarek Szyprowski 495e8d9d1f5SMarek Szyprowski nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; 496e8d9d1f5SMarek Szyprowski 497e8d9d1f5SMarek Szyprowski while (len >= t_len) { 498e8d9d1f5SMarek Szyprowski base = dt_mem_next_cell(dt_root_addr_cells, &prop); 499e8d9d1f5SMarek Szyprowski size = dt_mem_next_cell(dt_root_size_cells, &prop); 500e8d9d1f5SMarek Szyprowski 501b5f2a8c0SAl Cooper if (size && 502e8d9d1f5SMarek Szyprowski early_init_dt_reserve_memory_arch(base, size, nomap) == 0) 503e8d9d1f5SMarek Szyprowski pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", 504e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 505e8d9d1f5SMarek Szyprowski else 506e8d9d1f5SMarek Szyprowski pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", 507e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 508e8d9d1f5SMarek Szyprowski 509e8d9d1f5SMarek Szyprowski len -= t_len; 5103f0c8206SMarek Szyprowski if (first) { 5113f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, base, size); 5123f0c8206SMarek Szyprowski first = 0; 5133f0c8206SMarek Szyprowski } 514e8d9d1f5SMarek Szyprowski } 515e8d9d1f5SMarek Szyprowski return 0; 516e8d9d1f5SMarek Szyprowski } 517e8d9d1f5SMarek Szyprowski 518e8d9d1f5SMarek Szyprowski /** 519e8d9d1f5SMarek Szyprowski * __reserved_mem_check_root() - check if #size-cells, #address-cells provided 520e8d9d1f5SMarek Szyprowski * in /reserved-memory matches the values supported by the current implementation, 521e8d9d1f5SMarek Szyprowski * also check if ranges property has been provided 522e8d9d1f5SMarek Szyprowski */ 5235b624118SXiubo Li static int __init __reserved_mem_check_root(unsigned long node) 524e8d9d1f5SMarek Szyprowski { 5259d0c4dfeSRob Herring const __be32 *prop; 526e8d9d1f5SMarek Szyprowski 527e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 528e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_size_cells) 529e8d9d1f5SMarek Szyprowski return -EINVAL; 530e8d9d1f5SMarek Szyprowski 531e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 532e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) 533e8d9d1f5SMarek Szyprowski return -EINVAL; 534e8d9d1f5SMarek Szyprowski 535e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "ranges", NULL); 536e8d9d1f5SMarek Szyprowski if (!prop) 537e8d9d1f5SMarek Szyprowski return -EINVAL; 538e8d9d1f5SMarek Szyprowski return 0; 539e8d9d1f5SMarek Szyprowski } 540e8d9d1f5SMarek Szyprowski 541e8d9d1f5SMarek Szyprowski /** 542e8d9d1f5SMarek Szyprowski * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory 543e8d9d1f5SMarek Szyprowski */ 544e8d9d1f5SMarek Szyprowski static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, 545e8d9d1f5SMarek Szyprowski int depth, void *data) 546e8d9d1f5SMarek Szyprowski { 547e8d9d1f5SMarek Szyprowski static int found; 5483f0c8206SMarek Szyprowski int err; 549e8d9d1f5SMarek Szyprowski 550e8d9d1f5SMarek Szyprowski if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) { 551e8d9d1f5SMarek Szyprowski if (__reserved_mem_check_root(node) != 0) { 552e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: unsupported node format, ignoring\n"); 553e8d9d1f5SMarek Szyprowski /* break scan */ 554e8d9d1f5SMarek Szyprowski return 1; 555e8d9d1f5SMarek Szyprowski } 556e8d9d1f5SMarek Szyprowski found = 1; 557e8d9d1f5SMarek Szyprowski /* scan next node */ 558e8d9d1f5SMarek Szyprowski return 0; 559e8d9d1f5SMarek Szyprowski } else if (!found) { 560e8d9d1f5SMarek Szyprowski /* scan next node */ 561e8d9d1f5SMarek Szyprowski return 0; 562e8d9d1f5SMarek Szyprowski } else if (found && depth < 2) { 563e8d9d1f5SMarek Szyprowski /* scanning of /reserved-memory has been finished */ 564e8d9d1f5SMarek Szyprowski return 1; 565e8d9d1f5SMarek Szyprowski } 566e8d9d1f5SMarek Szyprowski 567ecc8a96eSRob Herring if (!of_fdt_device_is_available(initial_boot_params, node)) 568e8d9d1f5SMarek Szyprowski return 0; 569e8d9d1f5SMarek Szyprowski 5703f0c8206SMarek Szyprowski err = __reserved_mem_reserve_reg(node, uname); 5713f0c8206SMarek Szyprowski if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL)) 5723f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, 0, 0); 573e8d9d1f5SMarek Szyprowski 574e8d9d1f5SMarek Szyprowski /* scan next node */ 575e8d9d1f5SMarek Szyprowski return 0; 576e8d9d1f5SMarek Szyprowski } 577e8d9d1f5SMarek Szyprowski 578e8d9d1f5SMarek Szyprowski /** 579e8d9d1f5SMarek Szyprowski * early_init_fdt_scan_reserved_mem() - create reserved memory regions 580e8d9d1f5SMarek Szyprowski * 581e8d9d1f5SMarek Szyprowski * This function grabs memory from early allocator for device exclusive use 582e8d9d1f5SMarek Szyprowski * defined in device tree structures. It should be called by arch specific code 583e8d9d1f5SMarek Szyprowski * once the early allocator (i.e. memblock) has been fully activated. 584e8d9d1f5SMarek Szyprowski */ 585e8d9d1f5SMarek Szyprowski void __init early_init_fdt_scan_reserved_mem(void) 586e8d9d1f5SMarek Szyprowski { 587d1552ce4SRob Herring int n; 588d1552ce4SRob Herring u64 base, size; 589d1552ce4SRob Herring 5902040b527SJosh Cartwright if (!initial_boot_params) 5912040b527SJosh Cartwright return; 5922040b527SJosh Cartwright 593d1552ce4SRob Herring /* Process header /memreserve/ fields */ 594d1552ce4SRob Herring for (n = 0; ; n++) { 595d1552ce4SRob Herring fdt_get_mem_rsv(initial_boot_params, n, &base, &size); 596d1552ce4SRob Herring if (!size) 597d1552ce4SRob Herring break; 5985c68b823SMasahiro Yamada early_init_dt_reserve_memory_arch(base, size, false); 599d1552ce4SRob Herring } 600d1552ce4SRob Herring 601e8d9d1f5SMarek Szyprowski of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); 6023f0c8206SMarek Szyprowski fdt_init_reserved_mem(); 603e8d9d1f5SMarek Szyprowski } 604e8d9d1f5SMarek Szyprowski 605e8d9d1f5SMarek Szyprowski /** 60624bbd929SArd Biesheuvel * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob 60724bbd929SArd Biesheuvel */ 60824bbd929SArd Biesheuvel void __init early_init_fdt_reserve_self(void) 60924bbd929SArd Biesheuvel { 61024bbd929SArd Biesheuvel if (!initial_boot_params) 61124bbd929SArd Biesheuvel return; 61224bbd929SArd Biesheuvel 61324bbd929SArd Biesheuvel /* Reserve the dtb region */ 61424bbd929SArd Biesheuvel early_init_dt_reserve_memory_arch(__pa(initial_boot_params), 61524bbd929SArd Biesheuvel fdt_totalsize(initial_boot_params), 6165c68b823SMasahiro Yamada false); 61724bbd929SArd Biesheuvel } 61824bbd929SArd Biesheuvel 61924bbd929SArd Biesheuvel /** 62057d00ecfSStephen Neuendorffer * of_scan_flat_dt - scan flattened tree blob and call callback on each. 62157d00ecfSStephen Neuendorffer * @it: callback function 62257d00ecfSStephen Neuendorffer * @data: context data pointer 62357d00ecfSStephen Neuendorffer * 62457d00ecfSStephen Neuendorffer * This function is used to scan the flattened device-tree, it is 62557d00ecfSStephen Neuendorffer * used to extract the memory information at boot before we can 62657d00ecfSStephen Neuendorffer * unflatten the tree 62757d00ecfSStephen Neuendorffer */ 62857d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node, 62957d00ecfSStephen Neuendorffer const char *uname, int depth, 63057d00ecfSStephen Neuendorffer void *data), 63157d00ecfSStephen Neuendorffer void *data) 63257d00ecfSStephen Neuendorffer { 633e6a6928cSRob Herring const void *blob = initial_boot_params; 634e55b0829SFabio Estevam const char *pathp; 635e6a6928cSRob Herring int offset, rc = 0, depth = -1; 63657d00ecfSStephen Neuendorffer 6373ec75441STobias Wolf if (!blob) 6383ec75441STobias Wolf return 0; 6393ec75441STobias Wolf 640e6a6928cSRob Herring for (offset = fdt_next_node(blob, -1, &depth); 641e6a6928cSRob Herring offset >= 0 && depth >= 0 && !rc; 642e6a6928cSRob Herring offset = fdt_next_node(blob, offset, &depth)) { 643e6a6928cSRob Herring 644e6a6928cSRob Herring pathp = fdt_get_name(blob, offset, NULL); 645375da3a7SAndy Shevchenko if (*pathp == '/') 646375da3a7SAndy Shevchenko pathp = kbasename(pathp); 647e6a6928cSRob Herring rc = it(offset, pathp, depth, data); 648e6a6928cSRob Herring } 64957d00ecfSStephen Neuendorffer return rc; 65057d00ecfSStephen Neuendorffer } 65157d00ecfSStephen Neuendorffer 65257d00ecfSStephen Neuendorffer /** 653ea47dd19SNicholas Piggin * of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each. 654ea47dd19SNicholas Piggin * @it: callback function 655ea47dd19SNicholas Piggin * @data: context data pointer 656ea47dd19SNicholas Piggin * 657ea47dd19SNicholas Piggin * This function is used to scan sub-nodes of a node. 658ea47dd19SNicholas Piggin */ 659ea47dd19SNicholas Piggin int __init of_scan_flat_dt_subnodes(unsigned long parent, 660ea47dd19SNicholas Piggin int (*it)(unsigned long node, 661ea47dd19SNicholas Piggin const char *uname, 662ea47dd19SNicholas Piggin void *data), 663ea47dd19SNicholas Piggin void *data) 664ea47dd19SNicholas Piggin { 665ea47dd19SNicholas Piggin const void *blob = initial_boot_params; 666ea47dd19SNicholas Piggin int node; 667ea47dd19SNicholas Piggin 668ea47dd19SNicholas Piggin fdt_for_each_subnode(node, blob, parent) { 669ea47dd19SNicholas Piggin const char *pathp; 670ea47dd19SNicholas Piggin int rc; 671ea47dd19SNicholas Piggin 672ea47dd19SNicholas Piggin pathp = fdt_get_name(blob, node, NULL); 673ea47dd19SNicholas Piggin if (*pathp == '/') 674ea47dd19SNicholas Piggin pathp = kbasename(pathp); 675ea47dd19SNicholas Piggin rc = it(node, pathp, data); 676ea47dd19SNicholas Piggin if (rc) 677ea47dd19SNicholas Piggin return rc; 678ea47dd19SNicholas Piggin } 679ea47dd19SNicholas Piggin return 0; 680ea47dd19SNicholas Piggin } 681ea47dd19SNicholas Piggin 682ea47dd19SNicholas Piggin /** 6839c609868SShannon Zhao * of_get_flat_dt_subnode_by_name - get the subnode by given name 6849c609868SShannon Zhao * 6859c609868SShannon Zhao * @node: the parent node 6869c609868SShannon Zhao * @uname: the name of subnode 6879c609868SShannon Zhao * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none 6889c609868SShannon Zhao */ 6899c609868SShannon Zhao 6909b4d2b63SStephen Boyd int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname) 6919c609868SShannon Zhao { 6929c609868SShannon Zhao return fdt_subnode_offset(initial_boot_params, node, uname); 6939c609868SShannon Zhao } 6949c609868SShannon Zhao 6959c609868SShannon Zhao /** 69657d00ecfSStephen Neuendorffer * of_get_flat_dt_root - find the root node in the flat blob 69757d00ecfSStephen Neuendorffer */ 69857d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void) 69957d00ecfSStephen Neuendorffer { 700e6a6928cSRob Herring return 0; 70157d00ecfSStephen Neuendorffer } 70257d00ecfSStephen Neuendorffer 70357d00ecfSStephen Neuendorffer /** 70457d00ecfSStephen Neuendorffer * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 70557d00ecfSStephen Neuendorffer * 70657d00ecfSStephen Neuendorffer * This function can be used within scan_flattened_dt callback to get 70757d00ecfSStephen Neuendorffer * access to properties 70857d00ecfSStephen Neuendorffer */ 7099d0c4dfeSRob Herring const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 7109d0c4dfeSRob Herring int *size) 71157d00ecfSStephen Neuendorffer { 712e6a6928cSRob Herring return fdt_getprop(initial_boot_params, node, name, size); 71357d00ecfSStephen Neuendorffer } 71457d00ecfSStephen Neuendorffer 71557d00ecfSStephen Neuendorffer /** 7165d9c4e95SKefeng Wang * of_fdt_is_compatible - Return true if given node from the given blob has 7175d9c4e95SKefeng Wang * compat in its compatible list 7185d9c4e95SKefeng Wang * @blob: A device tree blob 7195d9c4e95SKefeng Wang * @node: node to test 7205d9c4e95SKefeng Wang * @compat: compatible string to compare with compatible list. 7215d9c4e95SKefeng Wang * 7225d9c4e95SKefeng Wang * On match, returns a non-zero value with smaller values returned for more 7235d9c4e95SKefeng Wang * specific compatible values. 7245d9c4e95SKefeng Wang */ 7255d9c4e95SKefeng Wang static int of_fdt_is_compatible(const void *blob, 7265d9c4e95SKefeng Wang unsigned long node, const char *compat) 7275d9c4e95SKefeng Wang { 7285d9c4e95SKefeng Wang const char *cp; 7295d9c4e95SKefeng Wang int cplen; 7305d9c4e95SKefeng Wang unsigned long l, score = 0; 7315d9c4e95SKefeng Wang 7325d9c4e95SKefeng Wang cp = fdt_getprop(blob, node, "compatible", &cplen); 7335d9c4e95SKefeng Wang if (cp == NULL) 7345d9c4e95SKefeng Wang return 0; 7355d9c4e95SKefeng Wang while (cplen > 0) { 7365d9c4e95SKefeng Wang score++; 7375d9c4e95SKefeng Wang if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 7385d9c4e95SKefeng Wang return score; 7395d9c4e95SKefeng Wang l = strlen(cp) + 1; 7405d9c4e95SKefeng Wang cp += l; 7415d9c4e95SKefeng Wang cplen -= l; 7425d9c4e95SKefeng Wang } 7435d9c4e95SKefeng Wang 7445d9c4e95SKefeng Wang return 0; 7455d9c4e95SKefeng Wang } 7465d9c4e95SKefeng Wang 7475d9c4e95SKefeng Wang /** 74857d00ecfSStephen Neuendorffer * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 74957d00ecfSStephen Neuendorffer * @node: node to test 75057d00ecfSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 75157d00ecfSStephen Neuendorffer */ 75257d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 75357d00ecfSStephen Neuendorffer { 75457d00ecfSStephen Neuendorffer return of_fdt_is_compatible(initial_boot_params, node, compat); 75557d00ecfSStephen Neuendorffer } 75657d00ecfSStephen Neuendorffer 757a4f740cfSGrant Likely /** 758a4f740cfSGrant Likely * of_flat_dt_match - Return true if node matches a list of compatible values 759a4f740cfSGrant Likely */ 7609b4d2b63SStephen Boyd static int __init of_flat_dt_match(unsigned long node, const char *const *compat) 761a4f740cfSGrant Likely { 7625d9c4e95SKefeng Wang unsigned int tmp, score = 0; 7635d9c4e95SKefeng Wang 7645d9c4e95SKefeng Wang if (!compat) 7655d9c4e95SKefeng Wang return 0; 7665d9c4e95SKefeng Wang 7675d9c4e95SKefeng Wang while (*compat) { 7685d9c4e95SKefeng Wang tmp = of_fdt_is_compatible(initial_boot_params, node, *compat); 7695d9c4e95SKefeng Wang if (tmp && (score == 0 || (tmp < score))) 7705d9c4e95SKefeng Wang score = tmp; 7715d9c4e95SKefeng Wang compat++; 7725d9c4e95SKefeng Wang } 7735d9c4e95SKefeng Wang 7745d9c4e95SKefeng Wang return score; 775a4f740cfSGrant Likely } 776a4f740cfSGrant Likely 777ea47dd19SNicholas Piggin /** 778ea47dd19SNicholas Piggin * of_get_flat_dt_prop - Given a node in the flat blob, return the phandle 779ea47dd19SNicholas Piggin */ 780ea47dd19SNicholas Piggin uint32_t __init of_get_flat_dt_phandle(unsigned long node) 781ea47dd19SNicholas Piggin { 782ea47dd19SNicholas Piggin return fdt_get_phandle(initial_boot_params, node); 783ea47dd19SNicholas Piggin } 784ea47dd19SNicholas Piggin 78557d74bcfSMarek Szyprowski struct fdt_scan_status { 78657d74bcfSMarek Szyprowski const char *name; 78757d74bcfSMarek Szyprowski int namelen; 78857d74bcfSMarek Szyprowski int depth; 78957d74bcfSMarek Szyprowski int found; 79057d74bcfSMarek Szyprowski int (*iterator)(unsigned long node, const char *uname, int depth, void *data); 79157d74bcfSMarek Szyprowski void *data; 79257d74bcfSMarek Szyprowski }; 79357d74bcfSMarek Szyprowski 7946a903a25SRob Herring const char * __init of_flat_dt_get_machine_name(void) 7956a903a25SRob Herring { 7966a903a25SRob Herring const char *name; 7976a903a25SRob Herring unsigned long dt_root = of_get_flat_dt_root(); 7986a903a25SRob Herring 7996a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "model", NULL); 8006a903a25SRob Herring if (!name) 8016a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "compatible", NULL); 8026a903a25SRob Herring return name; 8036a903a25SRob Herring } 8046a903a25SRob Herring 8056a903a25SRob Herring /** 8066a903a25SRob Herring * of_flat_dt_match_machine - Iterate match tables to find matching machine. 8076a903a25SRob Herring * 8086a903a25SRob Herring * @default_match: A machine specific ptr to return in case of no match. 8096a903a25SRob Herring * @get_next_compat: callback function to return next compatible match table. 8106a903a25SRob Herring * 8116a903a25SRob Herring * Iterate through machine match tables to find the best match for the machine 8126a903a25SRob Herring * compatible string in the FDT. 8136a903a25SRob Herring */ 8146a903a25SRob Herring const void * __init of_flat_dt_match_machine(const void *default_match, 8156a903a25SRob Herring const void * (*get_next_compat)(const char * const**)) 8166a903a25SRob Herring { 8176a903a25SRob Herring const void *data = NULL; 8186a903a25SRob Herring const void *best_data = default_match; 8196a903a25SRob Herring const char *const *compat; 8206a903a25SRob Herring unsigned long dt_root; 8216a903a25SRob Herring unsigned int best_score = ~1, score = 0; 8226a903a25SRob Herring 8236a903a25SRob Herring dt_root = of_get_flat_dt_root(); 8246a903a25SRob Herring while ((data = get_next_compat(&compat))) { 8256a903a25SRob Herring score = of_flat_dt_match(dt_root, compat); 8266a903a25SRob Herring if (score > 0 && score < best_score) { 8276a903a25SRob Herring best_data = data; 8286a903a25SRob Herring best_score = score; 8296a903a25SRob Herring } 8306a903a25SRob Herring } 8316a903a25SRob Herring if (!best_data) { 8326a903a25SRob Herring const char *prop; 8339d0c4dfeSRob Herring int size; 8346a903a25SRob Herring 8356a903a25SRob Herring pr_err("\n unrecognized device tree list:\n[ "); 8366a903a25SRob Herring 8376a903a25SRob Herring prop = of_get_flat_dt_prop(dt_root, "compatible", &size); 8386a903a25SRob Herring if (prop) { 8396a903a25SRob Herring while (size > 0) { 8406a903a25SRob Herring printk("'%s' ", prop); 8416a903a25SRob Herring size -= strlen(prop) + 1; 8426a903a25SRob Herring prop += strlen(prop) + 1; 8436a903a25SRob Herring } 8446a903a25SRob Herring } 8456a903a25SRob Herring printk("]\n\n"); 8466a903a25SRob Herring return NULL; 8476a903a25SRob Herring } 8486a903a25SRob Herring 8496a903a25SRob Herring pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); 8506a903a25SRob Herring 8516a903a25SRob Herring return best_data; 8526a903a25SRob Herring } 8536a903a25SRob Herring 854f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 855369bc9abSArd Biesheuvel static void __early_init_dt_declare_initrd(unsigned long start, 856369bc9abSArd Biesheuvel unsigned long end) 857369bc9abSArd Biesheuvel { 858cdbc848bSFlorian Fainelli /* ARM64 would cause a BUG to occur here when CONFIG_DEBUG_VM is 859cdbc848bSFlorian Fainelli * enabled since __va() is called too early. ARM64 does make use 860cdbc848bSFlorian Fainelli * of phys_initrd_start/phys_initrd_size so we can skip this 861cdbc848bSFlorian Fainelli * conversion. 862cdbc848bSFlorian Fainelli */ 863cdbc848bSFlorian Fainelli if (!IS_ENABLED(CONFIG_ARM64)) { 864369bc9abSArd Biesheuvel initrd_start = (unsigned long)__va(start); 865369bc9abSArd Biesheuvel initrd_end = (unsigned long)__va(end); 866369bc9abSArd Biesheuvel initrd_below_start_ok = 1; 867369bc9abSArd Biesheuvel } 868cdbc848bSFlorian Fainelli } 869369bc9abSArd Biesheuvel 870f7b3a835SGrant Likely /** 871f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 872f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 873f7b3a835SGrant Likely */ 87429eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node) 875f7b3a835SGrant Likely { 876374d5c99SSantosh Shilimkar u64 start, end; 8779d0c4dfeSRob Herring int len; 8789d0c4dfeSRob Herring const __be32 *prop; 879f7b3a835SGrant Likely 880f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 881f7b3a835SGrant Likely 882f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 8831406bc2fSJeremy Kerr if (!prop) 8841406bc2fSJeremy Kerr return; 885374d5c99SSantosh Shilimkar start = of_read_number(prop, len/4); 886f7b3a835SGrant Likely 887f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 8881406bc2fSJeremy Kerr if (!prop) 8891406bc2fSJeremy Kerr return; 890374d5c99SSantosh Shilimkar end = of_read_number(prop, len/4); 891f7b3a835SGrant Likely 892369bc9abSArd Biesheuvel __early_init_dt_declare_initrd(start, end); 893fe7db757SFlorian Fainelli phys_initrd_start = start; 894fe7db757SFlorian Fainelli phys_initrd_size = end - start; 89529eb45a9SRob Herring 896374d5c99SSantosh Shilimkar pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", 897374d5c99SSantosh Shilimkar (unsigned long long)start, (unsigned long long)end); 898f7b3a835SGrant Likely } 899f7b3a835SGrant Likely #else 90029eb45a9SRob Herring static inline void early_init_dt_check_for_initrd(unsigned long node) 901f7b3a835SGrant Likely { 902f7b3a835SGrant Likely } 903f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 904f7b3a835SGrant Likely 905fb11ffe7SRob Herring #ifdef CONFIG_SERIAL_EARLYCON 906fb11ffe7SRob Herring 907d503187bSLeif Lindholm int __init early_init_dt_scan_chosen_stdout(void) 908fb11ffe7SRob Herring { 909fb11ffe7SRob Herring int offset; 9104d118c9aSPeter Hurley const char *p, *q, *options = NULL; 911fb11ffe7SRob Herring int l; 912dd709e72SDaniel Kurtz const struct earlycon_id **p_match; 913fb11ffe7SRob Herring const void *fdt = initial_boot_params; 914fb11ffe7SRob Herring 915fb11ffe7SRob Herring offset = fdt_path_offset(fdt, "/chosen"); 916fb11ffe7SRob Herring if (offset < 0) 917fb11ffe7SRob Herring offset = fdt_path_offset(fdt, "/chosen@0"); 918fb11ffe7SRob Herring if (offset < 0) 919fb11ffe7SRob Herring return -ENOENT; 920fb11ffe7SRob Herring 921fb11ffe7SRob Herring p = fdt_getprop(fdt, offset, "stdout-path", &l); 922fb11ffe7SRob Herring if (!p) 923fb11ffe7SRob Herring p = fdt_getprop(fdt, offset, "linux,stdout-path", &l); 924fb11ffe7SRob Herring if (!p || !l) 925fb11ffe7SRob Herring return -ENOENT; 926fb11ffe7SRob Herring 9274d118c9aSPeter Hurley q = strchrnul(p, ':'); 9284d118c9aSPeter Hurley if (*q != '\0') 9294d118c9aSPeter Hurley options = q + 1; 9300fcc286fSPeter Hurley l = q - p; 9316296ad9eSStefan Agner 932fb11ffe7SRob Herring /* Get the node specified by stdout-path */ 9330fcc286fSPeter Hurley offset = fdt_path_offset_namelen(fdt, p, l); 9340fcc286fSPeter Hurley if (offset < 0) { 9350fcc286fSPeter Hurley pr_warn("earlycon: stdout-path %.*s not found\n", l, p); 9360fcc286fSPeter Hurley return 0; 9370fcc286fSPeter Hurley } 938fb11ffe7SRob Herring 939dd709e72SDaniel Kurtz for (p_match = __earlycon_table; p_match < __earlycon_table_end; 940dd709e72SDaniel Kurtz p_match++) { 941dd709e72SDaniel Kurtz const struct earlycon_id *match = *p_match; 942dd709e72SDaniel Kurtz 9432eaa7909SPeter Hurley if (!match->compatible[0]) 944fb11ffe7SRob Herring continue; 9452eaa7909SPeter Hurley 9462eaa7909SPeter Hurley if (fdt_node_check_compatible(fdt, offset, match->compatible)) 9472eaa7909SPeter Hurley continue; 948fb11ffe7SRob Herring 949c90fe9c0SPeter Hurley of_setup_earlycon(match, offset, options); 950fb11ffe7SRob Herring return 0; 951fb11ffe7SRob Herring } 952fb11ffe7SRob Herring return -ENODEV; 953fb11ffe7SRob Herring } 954fb11ffe7SRob Herring #endif 955fb11ffe7SRob Herring 95641f88009SGrant Likely /** 957f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 958f00abd94SGrant Likely */ 959f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 960f00abd94SGrant Likely int depth, void *data) 961f00abd94SGrant Likely { 9629d0c4dfeSRob Herring const __be32 *prop; 963f00abd94SGrant Likely 964f00abd94SGrant Likely if (depth != 0) 965f00abd94SGrant Likely return 0; 966f00abd94SGrant Likely 96733714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 96833714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 96933714881SJeremy Kerr 970f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 97133714881SJeremy Kerr if (prop) 97233714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 973f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 974f00abd94SGrant Likely 975f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 97633714881SJeremy Kerr if (prop) 97733714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 978f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 979f00abd94SGrant Likely 980f00abd94SGrant Likely /* break now */ 981f00abd94SGrant Likely return 1; 982f00abd94SGrant Likely } 983f00abd94SGrant Likely 9849d0c4dfeSRob Herring u64 __init dt_mem_next_cell(int s, const __be32 **cellp) 98583f7a06eSGrant Likely { 9869d0c4dfeSRob Herring const __be32 *p = *cellp; 98783f7a06eSGrant Likely 98883f7a06eSGrant Likely *cellp = p + s; 98983f7a06eSGrant Likely return of_read_number(p, s); 99083f7a06eSGrant Likely } 99183f7a06eSGrant Likely 99251975db0SGrant Likely /** 9930ef5adcaSFrank Rowand * early_init_dt_scan_memory - Look for and parse memory nodes 99451975db0SGrant Likely */ 99551975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 99651975db0SGrant Likely int depth, void *data) 99751975db0SGrant Likely { 9989d0c4dfeSRob Herring const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 9999d0c4dfeSRob Herring const __be32 *reg, *endp; 10009d0c4dfeSRob Herring int l; 100141a9ada3SReza Arbab bool hotpluggable; 100251975db0SGrant Likely 100351975db0SGrant Likely /* We are scanning "memory" nodes only */ 1004da653130SMichael Ellerman if (type == NULL || strcmp(type, "memory") != 0) 100551975db0SGrant Likely return 0; 100651975db0SGrant Likely 100751975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 100851975db0SGrant Likely if (reg == NULL) 100951975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 101051975db0SGrant Likely if (reg == NULL) 101151975db0SGrant Likely return 0; 101251975db0SGrant Likely 101351975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 101441a9ada3SReza Arbab hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL); 101551975db0SGrant Likely 1016c954b36eSFlorian Fainelli pr_debug("memory scan node %s, reg size %d,\n", uname, l); 101751975db0SGrant Likely 101851975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 101951975db0SGrant Likely u64 base, size; 102051975db0SGrant Likely 102151975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 102251975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 102351975db0SGrant Likely 102451975db0SGrant Likely if (size == 0) 102551975db0SGrant Likely continue; 102651975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 102751975db0SGrant Likely (unsigned long long)size); 102851975db0SGrant Likely 102951975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 103041a9ada3SReza Arbab 103141a9ada3SReza Arbab if (!hotpluggable) 103241a9ada3SReza Arbab continue; 103341a9ada3SReza Arbab 103441a9ada3SReza Arbab if (early_init_dt_mark_hotplug_memory_arch(base, size)) 103541a9ada3SReza Arbab pr_warn("failed to mark hotplug range 0x%llx - 0x%llx\n", 103641a9ada3SReza Arbab base, base + size); 103751975db0SGrant Likely } 103851975db0SGrant Likely 103951975db0SGrant Likely return 0; 104051975db0SGrant Likely } 104151975db0SGrant Likely 104286e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 104386e03221SGrant Likely int depth, void *data) 104486e03221SGrant Likely { 10459d0c4dfeSRob Herring int l; 10469d0c4dfeSRob Herring const char *p; 104786e03221SGrant Likely 104886e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 104986e03221SGrant Likely 105085f60ae4SGrant Likely if (depth != 1 || !data || 105186e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 105286e03221SGrant Likely return 0; 105386e03221SGrant Likely 105486e03221SGrant Likely early_init_dt_check_for_initrd(node); 105586e03221SGrant Likely 105625985edcSLucas De Marchi /* Retrieve command line */ 105786e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 105886e03221SGrant Likely if (p != NULL && l > 0) 1059b827bcbbSxiaojiangfeng strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); 106086e03221SGrant Likely 106178b782cbSBenjamin Herrenschmidt /* 106278b782cbSBenjamin Herrenschmidt * CONFIG_CMDLINE is meant to be a default in case nothing else 106378b782cbSBenjamin Herrenschmidt * managed to set the command line, unless CONFIG_CMDLINE_FORCE 106478b782cbSBenjamin Herrenschmidt * is set in which case we override whatever was found earlier. 106578b782cbSBenjamin Herrenschmidt */ 106686e03221SGrant Likely #ifdef CONFIG_CMDLINE 106734b82026SMax Uvarov #if defined(CONFIG_CMDLINE_EXTEND) 106834b82026SMax Uvarov strlcat(data, " ", COMMAND_LINE_SIZE); 106934b82026SMax Uvarov strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 107034b82026SMax Uvarov #elif defined(CONFIG_CMDLINE_FORCE) 107185f60ae4SGrant Likely strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 107234b82026SMax Uvarov #else 107334b82026SMax Uvarov /* No arguments from boot loader, use kernel's cmdl*/ 107434b82026SMax Uvarov if (!((char *)data)[0]) 107534b82026SMax Uvarov strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 107634b82026SMax Uvarov #endif 107786e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 107886e03221SGrant Likely 107985f60ae4SGrant Likely pr_debug("Command line is: %s\n", (char*)data); 108086e03221SGrant Likely 108186e03221SGrant Likely /* break now */ 108286e03221SGrant Likely return 1; 108386e03221SGrant Likely } 108486e03221SGrant Likely 1085270522a0SArd Biesheuvel #ifndef MIN_MEMBLOCK_ADDR 1086270522a0SArd Biesheuvel #define MIN_MEMBLOCK_ADDR __pa(PAGE_OFFSET) 1087270522a0SArd Biesheuvel #endif 10888eafeb48SArd Biesheuvel #ifndef MAX_MEMBLOCK_ADDR 10898eafeb48SArd Biesheuvel #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0) 10908eafeb48SArd Biesheuvel #endif 10913069f0c0SLaura Abbott 1092068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) 1093068f6310SRob Herring { 1094270522a0SArd Biesheuvel const u64 phys_offset = MIN_MEMBLOCK_ADDR; 10958f73d4b7SGeert Uytterhoeven 10968cccffc5SArd Biesheuvel if (size < PAGE_SIZE - (base & ~PAGE_MASK)) { 10978cccffc5SArd Biesheuvel pr_warn("Ignoring memory block 0x%llx - 0x%llx\n", 10988cccffc5SArd Biesheuvel base, base + size); 10998cccffc5SArd Biesheuvel return; 11008cccffc5SArd Biesheuvel } 11016072cf56SMike Rapoport 11026072cf56SMike Rapoport if (!PAGE_ALIGNED(base)) { 11038f73d4b7SGeert Uytterhoeven size -= PAGE_SIZE - (base & ~PAGE_MASK); 11048f73d4b7SGeert Uytterhoeven base = PAGE_ALIGN(base); 11058f73d4b7SGeert Uytterhoeven } 1106068f6310SRob Herring size &= PAGE_MASK; 1107a67a6ed1SLaura Abbott 11088eafeb48SArd Biesheuvel if (base > MAX_MEMBLOCK_ADDR) { 1109a67a6ed1SLaura Abbott pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 1110a67a6ed1SLaura Abbott base, base + size); 1111a67a6ed1SLaura Abbott return; 1112a67a6ed1SLaura Abbott } 1113a67a6ed1SLaura Abbott 11148eafeb48SArd Biesheuvel if (base + size - 1 > MAX_MEMBLOCK_ADDR) { 11159aacd602SSrinivas Kandagatla pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 11168eafeb48SArd Biesheuvel ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size); 11178eafeb48SArd Biesheuvel size = MAX_MEMBLOCK_ADDR - base + 1; 1118a67a6ed1SLaura Abbott } 1119a67a6ed1SLaura Abbott 1120068f6310SRob Herring if (base + size < phys_offset) { 1121068f6310SRob Herring pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 1122068f6310SRob Herring base, base + size); 1123068f6310SRob Herring return; 1124068f6310SRob Herring } 1125068f6310SRob Herring if (base < phys_offset) { 1126068f6310SRob Herring pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 1127068f6310SRob Herring base, phys_offset); 1128068f6310SRob Herring size -= phys_offset - base; 1129068f6310SRob Herring base = phys_offset; 1130068f6310SRob Herring } 1131068f6310SRob Herring memblock_add(base, size); 1132068f6310SRob Herring } 1133068f6310SRob Herring 113441a9ada3SReza Arbab int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size) 113541a9ada3SReza Arbab { 113641a9ada3SReza Arbab return memblock_mark_hotplug(base, size); 113741a9ada3SReza Arbab } 113841a9ada3SReza Arbab 1139e8d9d1f5SMarek Szyprowski int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, 1140e8d9d1f5SMarek Szyprowski phys_addr_t size, bool nomap) 1141e8d9d1f5SMarek Szyprowski { 1142e8d9d1f5SMarek Szyprowski if (nomap) 1143e8d9d1f5SMarek Szyprowski return memblock_remove(base, size); 1144e8d9d1f5SMarek Szyprowski return memblock_reserve(base, size); 1145e8d9d1f5SMarek Szyprowski } 1146e8d9d1f5SMarek Szyprowski 11470fa1c579SRob Herring static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) 11480fa1c579SRob Herring { 11498a7f97b9SMike Rapoport void *ptr = memblock_alloc(size, align); 11508a7f97b9SMike Rapoport 11518a7f97b9SMike Rapoport if (!ptr) 11528a7f97b9SMike Rapoport panic("%s: Failed to allocate %llu bytes align=0x%llx\n", 11538a7f97b9SMike Rapoport __func__, size, align); 11548a7f97b9SMike Rapoport 11558a7f97b9SMike Rapoport return ptr; 11560fa1c579SRob Herring } 11570fa1c579SRob Herring 11584972a74bSLaura Abbott bool __init early_init_dt_verify(void *params) 11590288ffcbSRob Herring { 11600288ffcbSRob Herring if (!params) 11610288ffcbSRob Herring return false; 11620288ffcbSRob Herring 116350ba08f3SBjorn Helgaas /* check device tree validity */ 116450ba08f3SBjorn Helgaas if (fdt_check_header(params)) 116550ba08f3SBjorn Helgaas return false; 116650ba08f3SBjorn Helgaas 11670288ffcbSRob Herring /* Setup flat device-tree pointer */ 11680288ffcbSRob Herring initial_boot_params = params; 116908d53aa5SArd Biesheuvel of_fdt_crc32 = crc32_be(~0, initial_boot_params, 117008d53aa5SArd Biesheuvel fdt_totalsize(initial_boot_params)); 11714972a74bSLaura Abbott return true; 11724972a74bSLaura Abbott } 11734972a74bSLaura Abbott 11744972a74bSLaura Abbott 11754972a74bSLaura Abbott void __init early_init_dt_scan_nodes(void) 11764972a74bSLaura Abbott { 1177e1e52544SNick Kossifidis int rc = 0; 1178e1e52544SNick Kossifidis 11790288ffcbSRob Herring /* Retrieve various information from the /chosen node */ 1180e1e52544SNick Kossifidis rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 1181e1e52544SNick Kossifidis if (!rc) 1182e1e52544SNick Kossifidis pr_warn("No chosen node found, continuing without\n"); 11830288ffcbSRob Herring 11840288ffcbSRob Herring /* Initialize {size,address}-cells info */ 11850288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_root, NULL); 11860288ffcbSRob Herring 11870288ffcbSRob Herring /* Setup memory, calling early_init_dt_add_memory_arch */ 11880288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_memory, NULL); 11894972a74bSLaura Abbott } 11900288ffcbSRob Herring 11914972a74bSLaura Abbott bool __init early_init_dt_scan(void *params) 11924972a74bSLaura Abbott { 11934972a74bSLaura Abbott bool status; 11944972a74bSLaura Abbott 11954972a74bSLaura Abbott status = early_init_dt_verify(params); 11964972a74bSLaura Abbott if (!status) 11974972a74bSLaura Abbott return false; 11984972a74bSLaura Abbott 11994972a74bSLaura Abbott early_init_dt_scan_nodes(); 12000288ffcbSRob Herring return true; 12010288ffcbSRob Herring } 12020288ffcbSRob Herring 1203f00abd94SGrant Likely /** 120441f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 120541f88009SGrant Likely * 120641f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 120741f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 120841f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 120941f88009SGrant Likely * can be used. 121041f88009SGrant Likely */ 121141f88009SGrant Likely void __init unflatten_device_tree(void) 121241f88009SGrant Likely { 1213c4263233SGavin Shan __unflatten_device_tree(initial_boot_params, NULL, &of_root, 12141d1bde55SMichal Suchanek early_init_dt_alloc_memory_arch, false); 121541f88009SGrant Likely 12164c7d6361SRobert P. J. Day /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ 1217611cad72SShawn Guo of_alias_scan(early_init_dt_alloc_memory_arch); 121881d0848fSFrank Rowand 121981d0848fSFrank Rowand unittest_unflatten_overlay_base(); 122041f88009SGrant Likely } 1221e6ce1324SStephen Neuendorffer 1222a8bf7527SRob Herring /** 1223a8bf7527SRob Herring * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob 1224a8bf7527SRob Herring * 1225a8bf7527SRob Herring * Copies and unflattens the device-tree passed by the firmware, creating the 1226a8bf7527SRob Herring * tree of struct device_node. It also fills the "name" and "type" 1227a8bf7527SRob Herring * pointers of the nodes so the normal device-tree walking functions 1228a8bf7527SRob Herring * can be used. This should only be used when the FDT memory has not been 1229a8bf7527SRob Herring * reserved such is the case when the FDT is built-in to the kernel init 1230a8bf7527SRob Herring * section. If the FDT memory is reserved already then unflatten_device_tree 1231a8bf7527SRob Herring * should be used instead. 1232a8bf7527SRob Herring */ 1233a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void) 1234a8bf7527SRob Herring { 12356f041e99SJames Hogan int size; 12366f041e99SJames Hogan void *dt; 12376f041e99SJames Hogan 12386f041e99SJames Hogan if (!initial_boot_params) { 12396f041e99SJames Hogan pr_warn("No valid device tree found, continuing without\n"); 12406f041e99SJames Hogan return; 12416f041e99SJames Hogan } 12426f041e99SJames Hogan 1243c972de14SRob Herring size = fdt_totalsize(initial_boot_params); 12446f041e99SJames Hogan dt = early_init_dt_alloc_memory_arch(size, 1245c972de14SRob Herring roundup_pow_of_two(FDT_V17_SIZE)); 1246a8bf7527SRob Herring 1247a8bf7527SRob Herring if (dt) { 1248a8bf7527SRob Herring memcpy(dt, initial_boot_params, size); 1249a8bf7527SRob Herring initial_boot_params = dt; 1250a8bf7527SRob Herring } 1251a8bf7527SRob Herring unflatten_device_tree(); 1252a8bf7527SRob Herring } 1253a8bf7527SRob Herring 125408d53aa5SArd Biesheuvel #ifdef CONFIG_SYSFS 125508d53aa5SArd Biesheuvel static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj, 125608d53aa5SArd Biesheuvel struct bin_attribute *bin_attr, 125708d53aa5SArd Biesheuvel char *buf, loff_t off, size_t count) 1258b0a6fb36SRob Herring { 125908d53aa5SArd Biesheuvel memcpy(buf, initial_boot_params + off, count); 126008d53aa5SArd Biesheuvel return count; 126108d53aa5SArd Biesheuvel } 1262b0a6fb36SRob Herring 126308d53aa5SArd Biesheuvel static int __init of_fdt_raw_init(void) 126408d53aa5SArd Biesheuvel { 126508d53aa5SArd Biesheuvel static struct bin_attribute of_fdt_raw_attr = 126608d53aa5SArd Biesheuvel __BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0); 1267b0a6fb36SRob Herring 126808d53aa5SArd Biesheuvel if (!initial_boot_params) 126908d53aa5SArd Biesheuvel return 0; 1270b0a6fb36SRob Herring 127108d53aa5SArd Biesheuvel if (of_fdt_crc32 != crc32_be(~0, initial_boot_params, 127208d53aa5SArd Biesheuvel fdt_totalsize(initial_boot_params))) { 1273606ad42aSRob Herring pr_warn("not creating '/sys/firmware/fdt': CRC check failed\n"); 1274b0a6fb36SRob Herring return 0; 1275b0a6fb36SRob Herring } 127608d53aa5SArd Biesheuvel of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params); 127708d53aa5SArd Biesheuvel return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr); 127808d53aa5SArd Biesheuvel } 127908d53aa5SArd Biesheuvel late_initcall(of_fdt_raw_init); 1280b0a6fb36SRob Herring #endif 1281b0a6fb36SRob Herring 1282e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */ 1283